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
19e713576292fc72086de47066981b86ad2f27ab0fShaopeng Jiaimport com.android.i18n.phonenumbers.NumberParseException;
20e713576292fc72086de47066981b86ad2f27ab0fShaopeng Jiaimport com.android.i18n.phonenumbers.PhoneNumberUtil;
21e713576292fc72086de47066981b86ad2f27ab0fShaopeng Jiaimport com.android.i18n.phonenumbers.PhoneNumberUtil.PhoneNumberFormat;
22e713576292fc72086de47066981b86ad2f27ab0fShaopeng Jiaimport com.android.i18n.phonenumbers.Phonenumber.PhoneNumber;
23ab971d3c26346cfd94a37e40591318bf3b3ae4fdShaopeng Jiaimport com.android.i18n.phonenumbers.ShortNumberUtil;
24fae6ec9e9673e96085fdbde69866a41b5491fa0dBai Tao
259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.Context;
269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.Intent;
279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.database.Cursor;
286b7c3f8a1cd8b638defc28a3249746e99b8039aeShaopeng Jiaimport android.location.CountryDetector;
299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.net.Uri;
309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.SystemProperties;
319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.provider.Contacts;
32f28ca902ad07ca3cf9c2f2e5d2d20dd58c0f13e5Jeff Sharkeyimport android.provider.ContactsContract;
339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.text.Editable;
349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.text.SpannableStringBuilder;
359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.text.TextUtils;
3618e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.comimport android.util.Log;
379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.util.SparseIntArray;
389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
397850cdde66705152b859aafda875833acdda9653Libin Tangimport static com.android.internal.telephony.TelephonyProperties.PROPERTY_ICC_OPERATOR_ISO_COUNTRY;
4018e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.comimport static com.android.internal.telephony.TelephonyProperties.PROPERTY_IDP_STRING;
417850cdde66705152b859aafda875833acdda9653Libin Tangimport static com.android.internal.telephony.TelephonyProperties.PROPERTY_OPERATOR_ISO_COUNTRY;
4218e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com
439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.Locale;
449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.regex.Matcher;
459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.regex.Pattern;
469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/**
489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Various utilities for dealing with phone number strings.
499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpublic class PhoneNumberUtils
519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{
529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /*
539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Special characters
549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * (See "What is a phone number?" doc)
569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * 'p' --- GSM pause character, same as comma
579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * 'n' --- GSM wild character
589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * 'w' --- GSM wait character
599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static final char PAUSE = ',';
619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static final char WAIT = ';';
629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static final char WILD = 'N';
639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /*
65adff0ad3cdae6c9bf043ab40fb0f40a54d5151acBabis Triantafyllou     * Calling Line Identification Restriction (CLIR)
66adff0ad3cdae6c9bf043ab40fb0f40a54d5151acBabis Triantafyllou     */
67e333c82da35119cfa25109328c3db98fa84f965eJake Hamby    private static final String CLIR_ON = "*31#";
68e333c82da35119cfa25109328c3db98fa84f965eJake Hamby    private static final String CLIR_OFF = "#31#";
69adff0ad3cdae6c9bf043ab40fb0f40a54d5151acBabis Triantafyllou
70adff0ad3cdae6c9bf043ab40fb0f40a54d5151acBabis Triantafyllou    /*
719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * TOA = TON + NPI
729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * See TS 24.008 section 10.5.4.7 for details.
739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * These are the only really useful TOA values
749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static final int TOA_International = 0x91;
769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static final int TOA_Unknown = 0x81;
779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7818e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com    static final String LOG_TAG = "PhoneNumberUtils";
7918e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com    private static final boolean DBG = false;
8018e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com
819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /*
829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * global-phone-number = ["+"] 1*( DIGIT / written-sep )
839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * written-sep         = ("-"/".")
849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final Pattern GLOBAL_PHONE_NUMBER_PATTERN =
869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Pattern.compile("[\\+]?[0-9.-]+");
879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** True if c is ISO-LATIN characters 0-9 */
899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static boolean
909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    isISODigit (char c) {
919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return c >= '0' && c <= '9';
929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** True if c is ISO-LATIN characters 0-9, *, # */
959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public final static boolean
969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    is12Key(char c) {
979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return (c >= '0' && c <= '9') || c == '*' || c == '#';
989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** True if c is ISO-LATIN characters 0-9, *, # , +, WILD  */
1019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public final static boolean
1029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    isDialable(char c) {
1039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return (c >= '0' && c <= '9') || c == '*' || c == '#' || c == '+' || c == WILD;
1049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** True if c is ISO-LATIN characters 0-9, *, # , + (no WILD)  */
1079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public final static boolean
1089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    isReallyDialable(char c) {
1099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return (c >= '0' && c <= '9') || c == '*' || c == '#' || c == '+';
1109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** True if c is ISO-LATIN characters 0-9, *, # , +, WILD, WAIT, PAUSE   */
1139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public final static boolean
1149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    isNonSeparator(char c) {
1159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return (c >= '0' && c <= '9') || c == '*' || c == '#' || c == '+'
1169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                || c == WILD || c == WAIT || c == PAUSE;
1179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** This any anything to the right of this char is part of the
1209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *  post-dial string (eg this is PAUSE or WAIT)
1219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public final static boolean
1239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    isStartsPostDial (char c) {
1249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return c == PAUSE || c == WAIT;
1259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1274eb45cc98bdcee575cc21f5ad5754cde57197a81inshik    private static boolean
1284eb45cc98bdcee575cc21f5ad5754cde57197a81inshik    isPause (char c){
1294eb45cc98bdcee575cc21f5ad5754cde57197a81inshik        return c == 'p'||c == 'P';
1304eb45cc98bdcee575cc21f5ad5754cde57197a81inshik    }
1314eb45cc98bdcee575cc21f5ad5754cde57197a81inshik
1324eb45cc98bdcee575cc21f5ad5754cde57197a81inshik    private static boolean
1334eb45cc98bdcee575cc21f5ad5754cde57197a81inshik    isToneWait (char c){
1344eb45cc98bdcee575cc21f5ad5754cde57197a81inshik        return c == 'w'||c == 'W';
1354eb45cc98bdcee575cc21f5ad5754cde57197a81inshik    }
1364eb45cc98bdcee575cc21f5ad5754cde57197a81inshik
1374eb45cc98bdcee575cc21f5ad5754cde57197a81inshik
1389a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa    /** Returns true if ch is not dialable or alpha char */
1399a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa    private static boolean isSeparator(char ch) {
1409a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa        return !isDialable(ch) && !(('a' <= ch && ch <= 'z') || ('A' <= ch && ch <= 'Z'));
1419a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa    }
1429a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa
1439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** Extracts the phone number from an Intent.
1449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
1459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param intent the intent to get the number of
1469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param context a context to use for database access
1479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
1489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return the phone number that would be called by the intent, or
1499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *         <code>null</code> if the number cannot be found.
1509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static String getNumberFromIntent(Intent intent, Context context) {
1529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        String number = null;
1539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Uri uri = intent.getData();
1559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        String scheme = uri.getScheme();
1569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1576f0f870f16003adc60e0c5f37c86b2d5e7895940Chung-yih Wang        if (scheme.equals("tel") || scheme.equals("sip")) {
1589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return uri.getSchemeSpecificPart();
1599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
16160d45f0f0320801a16db2ad038453c098e98966cNicolas Catania        // TODO: We don't check for SecurityException here (requires
162c69f5be0ed3529564e5db6874de52775c2c99007Wink Saville        // CALL_PRIVILEGED permission).
1639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (scheme.equals("voicemail")) {
164c69f5be0ed3529564e5db6874de52775c2c99007Wink Saville            return TelephonyManager.getDefault().getCompleteVoiceMailNumber();
1659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (context == null) {
1689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return null;
1699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        String type = intent.resolveType(context);
172f28ca902ad07ca3cf9c2f2e5d2d20dd58c0f13e5Jeff Sharkey        String phoneColumn = null;
173f28ca902ad07ca3cf9c2f2e5d2d20dd58c0f13e5Jeff Sharkey
174f28ca902ad07ca3cf9c2f2e5d2d20dd58c0f13e5Jeff Sharkey        // Correctly read out the phone entry based on requested provider
175f28ca902ad07ca3cf9c2f2e5d2d20dd58c0f13e5Jeff Sharkey        final String authority = uri.getAuthority();
176f28ca902ad07ca3cf9c2f2e5d2d20dd58c0f13e5Jeff Sharkey        if (Contacts.AUTHORITY.equals(authority)) {
177f28ca902ad07ca3cf9c2f2e5d2d20dd58c0f13e5Jeff Sharkey            phoneColumn = Contacts.People.Phones.NUMBER;
178f28ca902ad07ca3cf9c2f2e5d2d20dd58c0f13e5Jeff Sharkey        } else if (ContactsContract.AUTHORITY.equals(authority)) {
179f28ca902ad07ca3cf9c2f2e5d2d20dd58c0f13e5Jeff Sharkey            phoneColumn = ContactsContract.CommonDataKinds.Phone.NUMBER;
180f28ca902ad07ca3cf9c2f2e5d2d20dd58c0f13e5Jeff Sharkey        }
1819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
182f28ca902ad07ca3cf9c2f2e5d2d20dd58c0f13e5Jeff Sharkey        final Cursor c = context.getContentResolver().query(uri, new String[] {
183f28ca902ad07ca3cf9c2f2e5d2d20dd58c0f13e5Jeff Sharkey            phoneColumn
184f28ca902ad07ca3cf9c2f2e5d2d20dd58c0f13e5Jeff Sharkey        }, null, null, null);
1859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (c != null) {
1869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            try {
1879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (c.moveToFirst()) {
188f28ca902ad07ca3cf9c2f2e5d2d20dd58c0f13e5Jeff Sharkey                    number = c.getString(c.getColumnIndex(phoneColumn));
1899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
1909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } finally {
1919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                c.close();
1929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
1939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return number;
1969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** Extracts the network address portion and canonicalizes
1999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *  (filters out separators.)
2009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *  Network address portion is everything up to DTMF control digit
2019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *  separators (pause or wait), but without non-dialable characters.
2029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
2039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *  Please note that the GSM wild character is allowed in the result.
2049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *  This must be resolved before dialing.
2059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
2069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *  Returns null if phoneNumber == null
2079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
2089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static String
2099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    extractNetworkPortion(String phoneNumber) {
2109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (phoneNumber == null) {
2119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return null;
2129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int len = phoneNumber.length();
2159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        StringBuilder ret = new StringBuilder(len);
2169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (int i = 0; i < len; i++) {
2189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            char c = phoneNumber.charAt(i);
219e333c82da35119cfa25109328c3db98fa84f965eJake Hamby            // Character.digit() supports ASCII and Unicode digits (fullwidth, Arabic-Indic, etc.)
220e333c82da35119cfa25109328c3db98fa84f965eJake Hamby            int digit = Character.digit(c, 10);
221e333c82da35119cfa25109328c3db98fa84f965eJake Hamby            if (digit != -1) {
222e333c82da35119cfa25109328c3db98fa84f965eJake Hamby                ret.append(digit);
223e333c82da35119cfa25109328c3db98fa84f965eJake Hamby            } else if (c == '+') {
224e333c82da35119cfa25109328c3db98fa84f965eJake Hamby                // Allow '+' as first character or after CLIR MMI prefix
225e333c82da35119cfa25109328c3db98fa84f965eJake Hamby                String prefix = ret.toString();
226e333c82da35119cfa25109328c3db98fa84f965eJake Hamby                if (prefix.length() == 0 || prefix.equals(CLIR_ON) || prefix.equals(CLIR_OFF)) {
227e333c82da35119cfa25109328c3db98fa84f965eJake Hamby                    ret.append(c);
228e333c82da35119cfa25109328c3db98fa84f965eJake Hamby                }
229e333c82da35119cfa25109328c3db98fa84f965eJake Hamby            } else if (isDialable(c)) {
2309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                ret.append(c);
2319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else if (isStartsPostDial (c)) {
2329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                break;
2339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
2349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return ret.toString();
2379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
2409e534153264138cfee383c626db92b934fafc1afTammo Spalink     * Extracts the network address portion and canonicalize.
2419e534153264138cfee383c626db92b934fafc1afTammo Spalink     *
2429e534153264138cfee383c626db92b934fafc1afTammo Spalink     * This function is equivalent to extractNetworkPortion(), except
2439e534153264138cfee383c626db92b934fafc1afTammo Spalink     * for allowing the PLUS character to occur at arbitrary positions
2449e534153264138cfee383c626db92b934fafc1afTammo Spalink     * in the address portion, not just the first position.
2459e534153264138cfee383c626db92b934fafc1afTammo Spalink     *
2469e534153264138cfee383c626db92b934fafc1afTammo Spalink     * @hide
2479e534153264138cfee383c626db92b934fafc1afTammo Spalink     */
2489e534153264138cfee383c626db92b934fafc1afTammo Spalink    public static String extractNetworkPortionAlt(String phoneNumber) {
2499e534153264138cfee383c626db92b934fafc1afTammo Spalink        if (phoneNumber == null) {
2509e534153264138cfee383c626db92b934fafc1afTammo Spalink            return null;
2519e534153264138cfee383c626db92b934fafc1afTammo Spalink        }
2529e534153264138cfee383c626db92b934fafc1afTammo Spalink
2539e534153264138cfee383c626db92b934fafc1afTammo Spalink        int len = phoneNumber.length();
2549e534153264138cfee383c626db92b934fafc1afTammo Spalink        StringBuilder ret = new StringBuilder(len);
2559e534153264138cfee383c626db92b934fafc1afTammo Spalink        boolean haveSeenPlus = false;
2569e534153264138cfee383c626db92b934fafc1afTammo Spalink
2579e534153264138cfee383c626db92b934fafc1afTammo Spalink        for (int i = 0; i < len; i++) {
2589e534153264138cfee383c626db92b934fafc1afTammo Spalink            char c = phoneNumber.charAt(i);
2599e534153264138cfee383c626db92b934fafc1afTammo Spalink            if (c == '+') {
2609e534153264138cfee383c626db92b934fafc1afTammo Spalink                if (haveSeenPlus) {
2619e534153264138cfee383c626db92b934fafc1afTammo Spalink                    continue;
2629e534153264138cfee383c626db92b934fafc1afTammo Spalink                }
2639e534153264138cfee383c626db92b934fafc1afTammo Spalink                haveSeenPlus = true;
2649e534153264138cfee383c626db92b934fafc1afTammo Spalink            }
2659e534153264138cfee383c626db92b934fafc1afTammo Spalink            if (isDialable(c)) {
2669e534153264138cfee383c626db92b934fafc1afTammo Spalink                ret.append(c);
2679e534153264138cfee383c626db92b934fafc1afTammo Spalink            } else if (isStartsPostDial (c)) {
2689e534153264138cfee383c626db92b934fafc1afTammo Spalink                break;
2699e534153264138cfee383c626db92b934fafc1afTammo Spalink            }
2709e534153264138cfee383c626db92b934fafc1afTammo Spalink        }
2719e534153264138cfee383c626db92b934fafc1afTammo Spalink
2729e534153264138cfee383c626db92b934fafc1afTammo Spalink        return ret.toString();
2739e534153264138cfee383c626db92b934fafc1afTammo Spalink    }
2749e534153264138cfee383c626db92b934fafc1afTammo Spalink
2759e534153264138cfee383c626db92b934fafc1afTammo Spalink    /**
2769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Strips separators from a phone number string.
2779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param phoneNumber phone number to strip.
2789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return phone string stripped of separators.
2799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
2809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static String stripSeparators(String phoneNumber) {
2819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (phoneNumber == null) {
2829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return null;
2839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int len = phoneNumber.length();
2859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        StringBuilder ret = new StringBuilder(len);
2869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (int i = 0; i < len; i++) {
2889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            char c = phoneNumber.charAt(i);
289e333c82da35119cfa25109328c3db98fa84f965eJake Hamby            // Character.digit() supports ASCII and Unicode digits (fullwidth, Arabic-Indic, etc.)
290e333c82da35119cfa25109328c3db98fa84f965eJake Hamby            int digit = Character.digit(c, 10);
291e333c82da35119cfa25109328c3db98fa84f965eJake Hamby            if (digit != -1) {
292e333c82da35119cfa25109328c3db98fa84f965eJake Hamby                ret.append(digit);
293e333c82da35119cfa25109328c3db98fa84f965eJake Hamby            } else if (isNonSeparator(c)) {
2949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                ret.append(c);
2959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
2969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return ret.toString();
2999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3014eb45cc98bdcee575cc21f5ad5754cde57197a81inshik    /**
302510db8feb611a924d235b9b8a1d55ebbd36e9022Daisuke Miyakawa     * Translates keypad letters to actual digits (e.g. 1-800-GOOG-411 will
303510db8feb611a924d235b9b8a1d55ebbd36e9022Daisuke Miyakawa     * become 1-800-4664-411), and then strips all separators (e.g. 1-800-4664-411 will become
304510db8feb611a924d235b9b8a1d55ebbd36e9022Daisuke Miyakawa     * 18004664411).
305510db8feb611a924d235b9b8a1d55ebbd36e9022Daisuke Miyakawa     *
306510db8feb611a924d235b9b8a1d55ebbd36e9022Daisuke Miyakawa     * @see #convertKeypadLettersToDigits(String)
307510db8feb611a924d235b9b8a1d55ebbd36e9022Daisuke Miyakawa     * @see #stripSeparators(String)
308510db8feb611a924d235b9b8a1d55ebbd36e9022Daisuke Miyakawa     *
309510db8feb611a924d235b9b8a1d55ebbd36e9022Daisuke Miyakawa     * @hide
310510db8feb611a924d235b9b8a1d55ebbd36e9022Daisuke Miyakawa     */
311510db8feb611a924d235b9b8a1d55ebbd36e9022Daisuke Miyakawa    public static String convertAndStrip(String phoneNumber) {
312510db8feb611a924d235b9b8a1d55ebbd36e9022Daisuke Miyakawa        return stripSeparators(convertKeypadLettersToDigits(phoneNumber));
313510db8feb611a924d235b9b8a1d55ebbd36e9022Daisuke Miyakawa    }
314510db8feb611a924d235b9b8a1d55ebbd36e9022Daisuke Miyakawa
315510db8feb611a924d235b9b8a1d55ebbd36e9022Daisuke Miyakawa    /**
3164eb45cc98bdcee575cc21f5ad5754cde57197a81inshik     * Converts pause and tonewait pause characters
3174eb45cc98bdcee575cc21f5ad5754cde57197a81inshik     * to Android representation.
3184eb45cc98bdcee575cc21f5ad5754cde57197a81inshik     * RFC 3601 says pause is 'p' and tonewait is 'w'.
3194eb45cc98bdcee575cc21f5ad5754cde57197a81inshik     * @hide
3204eb45cc98bdcee575cc21f5ad5754cde57197a81inshik     */
3214eb45cc98bdcee575cc21f5ad5754cde57197a81inshik    public static String convertPreDial(String phoneNumber) {
3224eb45cc98bdcee575cc21f5ad5754cde57197a81inshik        if (phoneNumber == null) {
3234eb45cc98bdcee575cc21f5ad5754cde57197a81inshik            return null;
3244eb45cc98bdcee575cc21f5ad5754cde57197a81inshik        }
3254eb45cc98bdcee575cc21f5ad5754cde57197a81inshik        int len = phoneNumber.length();
3264eb45cc98bdcee575cc21f5ad5754cde57197a81inshik        StringBuilder ret = new StringBuilder(len);
3274eb45cc98bdcee575cc21f5ad5754cde57197a81inshik
3284eb45cc98bdcee575cc21f5ad5754cde57197a81inshik        for (int i = 0; i < len; i++) {
3294eb45cc98bdcee575cc21f5ad5754cde57197a81inshik            char c = phoneNumber.charAt(i);
3304eb45cc98bdcee575cc21f5ad5754cde57197a81inshik
3314eb45cc98bdcee575cc21f5ad5754cde57197a81inshik            if (isPause(c)) {
3324eb45cc98bdcee575cc21f5ad5754cde57197a81inshik                c = PAUSE;
3334eb45cc98bdcee575cc21f5ad5754cde57197a81inshik            } else if (isToneWait(c)) {
3344eb45cc98bdcee575cc21f5ad5754cde57197a81inshik                c = WAIT;
3354eb45cc98bdcee575cc21f5ad5754cde57197a81inshik            }
3364eb45cc98bdcee575cc21f5ad5754cde57197a81inshik            ret.append(c);
3374eb45cc98bdcee575cc21f5ad5754cde57197a81inshik        }
3384eb45cc98bdcee575cc21f5ad5754cde57197a81inshik        return ret.toString();
3394eb45cc98bdcee575cc21f5ad5754cde57197a81inshik    }
3404eb45cc98bdcee575cc21f5ad5754cde57197a81inshik
3419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** or -1 if both are negative */
3429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    static private int
3439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    minPositive (int a, int b) {
3449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (a >= 0 && b >= 0) {
3459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return (a < b) ? a : b;
3469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else if (a >= 0) { /* && b < 0 */
3479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return a;
3489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else if (b >= 0) { /* && a < 0 */
3499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return b;
3509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else { /* a < 0 && b < 0 */
3519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return -1;
3529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
3539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
35518e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com    private static void log(String msg) {
35618e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com        Log.d(LOG_TAG, msg);
35718e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com    }
3589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** index of the last character of the network portion
3599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *  (eg anything after is a post-dial string)
3609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
3619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    static private int
3629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    indexOfLastNetworkChar(String a) {
3639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int pIndex, wIndex;
3649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int origLength;
3659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int trimIndex;
3669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        origLength = a.length();
3689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        pIndex = a.indexOf(PAUSE);
3709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        wIndex = a.indexOf(WAIT);
3719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        trimIndex = minPositive(pIndex, wIndex);
3739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (trimIndex < 0) {
3759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return origLength - 1;
3769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
3779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return trimIndex - 1;
3789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
3799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
3829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Extracts the post-dial sequence of DTMF control digits, pauses, and
3839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * waits. Strips separators. This string may be empty, but will not be null
3849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * unless phoneNumber == null.
3859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
3869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Returns null if phoneNumber == null
3879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
3889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static String
3909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    extractPostDialPortion(String phoneNumber) {
3919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (phoneNumber == null) return null;
3929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int trimIndex;
3949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        StringBuilder ret = new StringBuilder();
3959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        trimIndex = indexOfLastNetworkChar (phoneNumber);
3979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (int i = trimIndex + 1, s = phoneNumber.length()
3999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                ; i < s; i++
4009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        ) {
4019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            char c = phoneNumber.charAt(i);
4029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (isNonSeparator(c)) {
4039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                ret.append(c);
4049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
4059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
4069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return ret.toString();
4089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
4119a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa     * Compare phone numbers a and b, return true if they're identical enough for caller ID purposes.
4129a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa     */
4139a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa    public static boolean compare(String a, String b) {
4149a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa        // We've used loose comparation at least Eclair, which may change in the future.
415db1f4993989bb03cae2f3e008d4db3e49577aa73Evan Millar
4169a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa        return compare(a, b, false);
4179a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa    }
4189a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa
4199a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa    /**
420db1f4993989bb03cae2f3e008d4db3e49577aa73Evan Millar     * Compare phone numbers a and b, and return true if they're identical
421db1f4993989bb03cae2f3e008d4db3e49577aa73Evan Millar     * enough for caller ID purposes. Checks a resource to determine whether
422db1f4993989bb03cae2f3e008d4db3e49577aa73Evan Millar     * to use a strict or loose comparison algorithm.
423db1f4993989bb03cae2f3e008d4db3e49577aa73Evan Millar     */
424db1f4993989bb03cae2f3e008d4db3e49577aa73Evan Millar    public static boolean compare(Context context, String a, String b) {
425db1f4993989bb03cae2f3e008d4db3e49577aa73Evan Millar        boolean useStrict = context.getResources().getBoolean(
426db1f4993989bb03cae2f3e008d4db3e49577aa73Evan Millar               com.android.internal.R.bool.config_use_strict_phone_number_comparation);
427db1f4993989bb03cae2f3e008d4db3e49577aa73Evan Millar        return compare(a, b, useStrict);
428db1f4993989bb03cae2f3e008d4db3e49577aa73Evan Millar    }
429db1f4993989bb03cae2f3e008d4db3e49577aa73Evan Millar
430db1f4993989bb03cae2f3e008d4db3e49577aa73Evan Millar    /**
4319a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa     * @hide only for testing.
4329a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa     */
4339a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa    public static boolean compare(String a, String b, boolean useStrictComparation) {
4349a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa        return (useStrictComparation ? compareStrictly(a, b) : compareLoosely(a, b));
4359a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa    }
4369a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa
4379a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa    /**
4389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Compare phone numbers a and b, return true if they're identical
4399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * enough for caller ID purposes.
4409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
4419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * - Compares from right to left
44202b5948a4375dba5d287a59ba023eaf1e02b45dcWei Huang     * - requires MIN_MATCH (7) characters to match
4439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * - handles common trunk prefixes and international prefixes
4449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *   (basically, everything except the Russian trunk prefix)
4459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
4469a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa     * Note that this method does not return false even when the two phone numbers
4479a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa     * are not exactly same; rather; we can call this method "similar()", not "equals()".
4489a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa     *
4499a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa     * @hide
4509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
4519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static boolean
4529a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa    compareLoosely(String a, String b) {
4539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int ia, ib;
4549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int matched;
455fd7b4f1d12779a0363e98a37e7f5a7ccacba5ee8Wei Huang        int numNonDialableCharsInA = 0;
456fd7b4f1d12779a0363e98a37e7f5a7ccacba5ee8Wei Huang        int numNonDialableCharsInB = 0;
4579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (a == null || b == null) return a == b;
4599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (a.length() == 0 || b.length() == 0) {
4619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
4629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
4639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        ia = indexOfLastNetworkChar (a);
4659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        ib = indexOfLastNetworkChar (b);
4669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        matched = 0;
4679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        while (ia >= 0 && ib >=0) {
4699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            char ca, cb;
4709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            boolean skipCmp = false;
4719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            ca = a.charAt(ia);
4739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (!isDialable(ca)) {
4759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                ia--;
4769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                skipCmp = true;
477fd7b4f1d12779a0363e98a37e7f5a7ccacba5ee8Wei Huang                numNonDialableCharsInA++;
4789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
4799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            cb = b.charAt(ib);
4819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (!isDialable(cb)) {
4839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                ib--;
4849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                skipCmp = true;
485fd7b4f1d12779a0363e98a37e7f5a7ccacba5ee8Wei Huang                numNonDialableCharsInB++;
4869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
4879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (!skipCmp) {
4899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (cb != ca && ca != WILD && cb != WILD) {
4909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    break;
4919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
4929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                ia--; ib--; matched++;
4939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
4949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
4959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (matched < MIN_MATCH) {
497fd7b4f1d12779a0363e98a37e7f5a7ccacba5ee8Wei Huang            int effectiveALen = a.length() - numNonDialableCharsInA;
498fd7b4f1d12779a0363e98a37e7f5a7ccacba5ee8Wei Huang            int effectiveBLen = b.length() - numNonDialableCharsInB;
4999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
500fd7b4f1d12779a0363e98a37e7f5a7ccacba5ee8Wei Huang
501fd7b4f1d12779a0363e98a37e7f5a7ccacba5ee8Wei Huang            // if the number of dialable chars in a and b match, but the matched chars < MIN_MATCH,
502fd7b4f1d12779a0363e98a37e7f5a7ccacba5ee8Wei Huang            // treat them as equal (i.e. 404-04 and 40404)
503fd7b4f1d12779a0363e98a37e7f5a7ccacba5ee8Wei Huang            if (effectiveALen == effectiveBLen && effectiveALen == matched) {
5049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return true;
5059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
506fd7b4f1d12779a0363e98a37e7f5a7ccacba5ee8Wei Huang
5079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
5089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // At least one string has matched completely;
5119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (matched >= MIN_MATCH && (ia < 0 || ib < 0)) {
5129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return true;
5139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /*
5169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * Now, what remains must be one of the following for a
5179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * match:
5189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         *
5199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         *  - a '+' on one and a '00' or a '011' on the other
5209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         *  - a '0' on one and a (+,00)<country code> on the other
5219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         *     (for this, a '0' and a '00' prefix would have succeeded above)
5229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
5239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (matchIntlPrefix(a, ia + 1)
5259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            && matchIntlPrefix (b, ib +1)
5269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        ) {
5279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return true;
5289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (matchTrunkPrefix(a, ia + 1)
5319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            && matchIntlPrefixAndCC(b, ib +1)
5329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        ) {
5339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return true;
5349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (matchTrunkPrefix(b, ib + 1)
5379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            && matchIntlPrefixAndCC(a, ia +1)
5389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        ) {
5399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return true;
5409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return false;
5439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
5469a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa     * @hide
5479a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa     */
5489a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa    public static boolean
5499a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa    compareStrictly(String a, String b) {
5509a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa        return compareStrictly(a, b, true);
5519a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa    }
5529a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa
5539a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa    /**
5549a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa     * @hide
5559a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa     */
5569a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa    public static boolean
5579a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa    compareStrictly(String a, String b, boolean acceptInvalidCCCPrefix) {
5589a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa        if (a == null || b == null) {
5599a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa            return a == b;
5609a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa        } else if (a.length() == 0 && b.length() == 0) {
5619a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa            return false;
5629a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa        }
5639a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa
5649a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa        int forwardIndexA = 0;
5659a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa        int forwardIndexB = 0;
5669a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa
5679a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa        CountryCallingCodeAndNewIndex cccA =
5689a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa            tryGetCountryCallingCodeAndNewIndex(a, acceptInvalidCCCPrefix);
5699a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa        CountryCallingCodeAndNewIndex cccB =
5709a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa            tryGetCountryCallingCodeAndNewIndex(b, acceptInvalidCCCPrefix);
5719a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa        boolean bothHasCountryCallingCode = false;
5729a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa        boolean okToIgnorePrefix = true;
5739a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa        boolean trunkPrefixIsOmittedA = false;
5749a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa        boolean trunkPrefixIsOmittedB = false;
5759a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa        if (cccA != null && cccB != null) {
5769a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa            if (cccA.countryCallingCode != cccB.countryCallingCode) {
5779a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                // Different Country Calling Code. Must be different phone number.
5789a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                return false;
5799a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa            }
5809a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa            // When both have ccc, do not ignore trunk prefix. Without this,
5819a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa            // "+81123123" becomes same as "+810123123" (+81 == Japan)
5829a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa            okToIgnorePrefix = false;
5839a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa            bothHasCountryCallingCode = true;
5849a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa            forwardIndexA = cccA.newIndex;
5859a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa            forwardIndexB = cccB.newIndex;
5869a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa        } else if (cccA == null && cccB == null) {
5879a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa            // When both do not have ccc, do not ignore trunk prefix. Without this,
5889a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa            // "123123" becomes same as "0123123"
5899a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa            okToIgnorePrefix = false;
5909a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa        } else {
5919a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa            if (cccA != null) {
5929a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                forwardIndexA = cccA.newIndex;
5939a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa            } else {
5949a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                int tmp = tryGetTrunkPrefixOmittedIndex(b, 0);
5959a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                if (tmp >= 0) {
5969a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                    forwardIndexA = tmp;
5979a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                    trunkPrefixIsOmittedA = true;
5989a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                }
5999a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa            }
6009a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa            if (cccB != null) {
6019a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                forwardIndexB = cccB.newIndex;
6029a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa            } else {
6039a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                int tmp = tryGetTrunkPrefixOmittedIndex(b, 0);
6049a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                if (tmp >= 0) {
6059a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                    forwardIndexB = tmp;
6069a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                    trunkPrefixIsOmittedB = true;
6079a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                }
6089a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa            }
6099a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa        }
6109a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa
6119a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa        int backwardIndexA = a.length() - 1;
6129a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa        int backwardIndexB = b.length() - 1;
6139a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa        while (backwardIndexA >= forwardIndexA && backwardIndexB >= forwardIndexB) {
6149a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa            boolean skip_compare = false;
6159a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa            final char chA = a.charAt(backwardIndexA);
6169a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa            final char chB = b.charAt(backwardIndexB);
6179a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa            if (isSeparator(chA)) {
6189a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                backwardIndexA--;
6199a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                skip_compare = true;
6209a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa            }
6219a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa            if (isSeparator(chB)) {
6229a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                backwardIndexB--;
6239a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                skip_compare = true;
6249a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa            }
6259a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa
6269a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa            if (!skip_compare) {
6279a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                if (chA != chB) {
6289a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                    return false;
6299a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                }
6309a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                backwardIndexA--;
6319a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                backwardIndexB--;
6329a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa            }
6339a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa        }
6349a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa
6359a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa        if (okToIgnorePrefix) {
6369a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa            if ((trunkPrefixIsOmittedA && forwardIndexA <= backwardIndexA) ||
6379a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                !checkPrefixIsIgnorable(a, forwardIndexA, backwardIndexA)) {
6389a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                if (acceptInvalidCCCPrefix) {
6399a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                    // Maybe the code handling the special case for Thailand makes the
6409a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                    // result garbled, so disable the code and try again.
6419a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                    // e.g. "16610001234" must equal to "6610001234", but with
6429a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                    //      Thailand-case handling code, they become equal to each other.
6439a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                    //
6449a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                    // Note: we select simplicity rather than adding some complicated
6459a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                    //       logic here for performance(like "checking whether remaining
6469a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                    //       numbers are just 66 or not"), assuming inputs are small
6479a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                    //       enough.
6489a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                    return compare(a, b, false);
6499a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                } else {
6509a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                    return false;
6519a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                }
6529a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa            }
6539a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa            if ((trunkPrefixIsOmittedB && forwardIndexB <= backwardIndexB) ||
6549a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                !checkPrefixIsIgnorable(b, forwardIndexA, backwardIndexB)) {
6559a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                if (acceptInvalidCCCPrefix) {
6569a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                    return compare(a, b, false);
6579a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                } else {
6589a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                    return false;
6599a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                }
6609a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa            }
6619a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa        } else {
6629a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa            // In the US, 1-650-555-1234 must be equal to 650-555-1234,
663bcd573229e5ec6d59bb7931a84a2baa86e0d200aJake Hamby            // while 090-1234-1234 must not be equal to 90-1234-1234 in Japan.
6649a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa            // This request exists just in US (with 1 trunk (NDD) prefix).
6659a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa            // In addition, "011 11 7005554141" must not equal to "+17005554141",
6669a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa            // while "011 1 7005554141" must equal to "+17005554141"
6679a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa            //
6689a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa            // In this comparison, we ignore the prefix '1' just once, when
6699a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa            // - at least either does not have CCC, or
6709a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa            // - the remaining non-separator number is 1
6719a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa            boolean maybeNamp = !bothHasCountryCallingCode;
6729a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa            while (backwardIndexA >= forwardIndexA) {
6739a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                final char chA = a.charAt(backwardIndexA);
6749a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                if (isDialable(chA)) {
6759a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                    if (maybeNamp && tryGetISODigit(chA) == 1) {
6769a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                        maybeNamp = false;
6779a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                    } else {
6789a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                        return false;
6799a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                    }
6809a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                }
6819a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                backwardIndexA--;
6829a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa            }
6839a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa            while (backwardIndexB >= forwardIndexB) {
6849a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                final char chB = b.charAt(backwardIndexB);
6859a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                if (isDialable(chB)) {
6869a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                    if (maybeNamp && tryGetISODigit(chB) == 1) {
6879a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                        maybeNamp = false;
6889a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                    } else {
6899a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                        return false;
6909a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                    }
6919a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                }
6929a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                backwardIndexB--;
6939a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa            }
6949a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa        }
6959a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa
6969a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa        return true;
6979a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa    }
6989a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa
6999a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa    /**
7009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Returns the rightmost MIN_MATCH (5) characters in the network portion
7019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * in *reversed* order
7029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
7039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * This can be used to do a database lookup against the column
7049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * that stores getStrippedReversed()
7059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
7069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Returns null if phoneNumber == null
7079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
7089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static String
7099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    toCallerIDMinMatch(String phoneNumber) {
7109e534153264138cfee383c626db92b934fafc1afTammo Spalink        String np = extractNetworkPortionAlt(phoneNumber);
7119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return internalGetStrippedReversed(np, MIN_MATCH);
7129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
7139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
7159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Returns the network portion reversed.
7169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * This string is intended to go into an index column for a
7179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * database lookup.
7189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
7199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Returns null if phoneNumber == null
7209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
7219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static String
7229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    getStrippedReversed(String phoneNumber) {
7239e534153264138cfee383c626db92b934fafc1afTammo Spalink        String np = extractNetworkPortionAlt(phoneNumber);
7249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (np == null) return null;
7269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return internalGetStrippedReversed(np, np.length());
7289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
7299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
7319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Returns the last numDigits of the reversed phone number
7329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Returns null if np == null
7339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
7349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static String
7359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    internalGetStrippedReversed(String np, int numDigits) {
7369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (np == null) return null;
7379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        StringBuilder ret = new StringBuilder(numDigits);
7399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int length = np.length();
7409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (int i = length - 1, s = length
7429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            ; i >= 0 && (s - i) <= numDigits ; i--
7439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        ) {
7449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            char c = np.charAt(i);
7459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            ret.append(c);
7479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
7489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return ret.toString();
7509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
7519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
7539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Basically: makes sure there's a + in front of a
7549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * TOA_International number
7559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
7569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Returns null if s == null
7579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
7589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static String
7599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    stringFromStringAndTOA(String s, int TOA) {
7609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (s == null) return null;
7619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (TOA == TOA_International && s.length() > 0 && s.charAt(0) != '+') {
7639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return "+" + s;
7649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
7659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return s;
7679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
7689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
7709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Returns the TOA for the given dial string
7719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Basically, returns TOA_International if there's a + prefix
7729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
7739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static int
7759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    toaFromString(String s) {
7769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (s != null && s.length() > 0 && s.charAt(0) == '+') {
7779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return TOA_International;
7789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
7799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return TOA_Unknown;
7819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
7829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
7849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *  3GPP TS 24.008 10.5.4.7
7859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *  Called Party BCD Number
7869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
7879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *  See Also TS 51.011 10.5.1 "dialing number/ssc string"
7889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *  and TS 11.11 "10.3.1 EF adn (Abbreviated dialing numbers)"
7899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
7909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param bytes the data buffer
7919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param offset should point to the TOA (aka. TON/NPI) octet after the length byte
7929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param length is the number of bytes including TOA byte
7939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *                and must be at least 2
7949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
7959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return partial string on invalid decode
7969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
7979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * FIXME(mkf) support alphanumeric address type
7989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *  currently implemented in SMSMessage.getAddress()
7999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
8009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static String
8019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    calledPartyBCDToString (byte[] bytes, int offset, int length) {
8029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        boolean prependPlus = false;
8039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        StringBuilder ret = new StringBuilder(1 + length * 2);
8049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (length < 2) {
8069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return "";
8079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
8089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
809b1110149cccc3b99e59ead34ca46e5ac026f6db9The Android Open Source Project        //Only TON field should be taken in consideration
810ce2a97aeb82d3f34a63472720ee9d53e53c248c2Samuel Holmberg        if ((bytes[offset] & 0xf0) == (TOA_International & 0xf0)) {
8119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            prependPlus = true;
8129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
8139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        internalCalledPartyBCDFragmentToString(
8159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                ret, bytes, offset + 1, length - 1);
8169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (prependPlus && ret.length() == 0) {
8189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // If the only thing there is a prepended plus, return ""
8199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return "";
8209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
8219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (prependPlus) {
8239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // This is an "international number" and should have
8249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // a plus prepended to the dialing number. But there
825145ff609de3206b585819ef974fab20cdc2d9f5eJake Hamby            // can also be GSM MMI codes as defined in TS 22.030 6.5.2
8269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // so we need to handle those also.
8279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            //
828145ff609de3206b585819ef974fab20cdc2d9f5eJake Hamby            // http://web.telia.com/~u47904776/gsmkode.htm
8299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // has a nice list of some of these GSM codes.
8309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            //
8319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // Examples are:
8329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            //   **21*+886988171479#
8339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            //   **21*8311234567#
8349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            //   *21#
8359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            //   #21#
8369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            //   *#21#
8379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            //   *31#+11234567890
8389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            //   #31#+18311234567
8399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            //   #31#8311234567
8409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            //   18311234567
8419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            //   +18311234567#
8429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            //   +18311234567
8439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // Odd ball cases that some phones handled
8449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // where there is no dialing number so they
8459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // append the "+"
8469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            //   *21#+
8479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            //   **21#+
8489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            String retString = ret.toString();
8499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Pattern p = Pattern.compile("(^[#*])(.*)([#*])(.*)(#)$");
8509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Matcher m = p.matcher(retString);
8519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (m.matches()) {
8529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if ("".equals(m.group(2))) {
8539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // Started with two [#*] ends with #
8549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // So no dialing number and we'll just
8559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // append a +, this handles **21#+
8569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    ret = new StringBuilder();
8579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    ret.append(m.group(1));
8589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    ret.append(m.group(3));
8599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    ret.append(m.group(4));
8609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    ret.append(m.group(5));
8619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    ret.append("+");
8629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } else {
8639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // Starts with [#*] and ends with #
8649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // Assume group 4 is a dialing number
8659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // such as *21*+1234554#
8669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    ret = new StringBuilder();
8679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    ret.append(m.group(1));
8689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    ret.append(m.group(2));
8699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    ret.append(m.group(3));
8709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    ret.append("+");
8719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    ret.append(m.group(4));
8729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    ret.append(m.group(5));
8739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
8749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else {
8759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                p = Pattern.compile("(^[#*])(.*)([#*])(.*)");
8769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                m = p.matcher(retString);
8779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (m.matches()) {
8789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // Starts with [#*] and only one other [#*]
8799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // Assume the data after last [#*] is dialing
8809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // number (i.e. group 4) such as *31#+11234567890.
8819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // This also includes the odd ball *21#+
8829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    ret = new StringBuilder();
8839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    ret.append(m.group(1));
8849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    ret.append(m.group(2));
8859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    ret.append(m.group(3));
8869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    ret.append("+");
8879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    ret.append(m.group(4));
8889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } else {
8899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // Does NOT start with [#*] just prepend '+'
8909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    ret = new StringBuilder();
8919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    ret.append('+');
8929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    ret.append(retString);
8939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
8949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
8959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
8969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return ret.toString();
8989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
8999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static void
9019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    internalCalledPartyBCDFragmentToString(
9029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        StringBuilder sb, byte [] bytes, int offset, int length) {
9039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (int i = offset ; i < length + offset ; i++) {
9049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            byte b;
9059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            char c;
9069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            c = bcdToChar((byte)(bytes[i] & 0xf));
9089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (c == 0) {
9109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return;
9119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
9129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            sb.append(c);
9139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // FIXME(mkf) TS 23.040 9.1.2.3 says
9159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // "if a mobile receives 1111 in a position prior to
916145ff609de3206b585819ef974fab20cdc2d9f5eJake Hamby            // the last semi-octet then processing shall commence with
9179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // the next semi-octet and the intervening
9189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // semi-octet shall be ignored"
919145ff609de3206b585819ef974fab20cdc2d9f5eJake Hamby            // How does this jive with 24.008 10.5.4.7
9209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            b = (byte)((bytes[i] >> 4) & 0xf);
9229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (b == 0xf && i + 1 == length + offset) {
9249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                //ignore final 0xf
9259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                break;
9269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
9279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            c = bcdToChar(b);
9299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (c == 0) {
9309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return;
9319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
9329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            sb.append(c);
9349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
9359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
9379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
9399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Like calledPartyBCDToString, but field does not start with a
9409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * TOA byte. For example: SIM ADN extension fields
9419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
9429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static String
9449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    calledPartyBCDFragmentToString(byte [] bytes, int offset, int length) {
9459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        StringBuilder ret = new StringBuilder(length * 2);
9469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        internalCalledPartyBCDFragmentToString(ret, bytes, offset, length);
9489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return ret.toString();
9509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
9519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** returns 0 on invalid value */
9539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static char
9549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    bcdToChar(byte b) {
9559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (b < 0xa) {
9569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return (char)('0' + b);
9579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else switch (b) {
9589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case 0xa: return '*';
9599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case 0xb: return '#';
9609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case 0xc: return PAUSE;
9619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case 0xd: return WILD;
9629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            default: return 0;
9649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
9659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
9669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static int
9689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    charToBCD(char c) {
9699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (c >= '0' && c <= '9') {
9709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return c - '0';
9719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else if (c == '*') {
9729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return 0xa;
9739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else if (c == '#') {
9749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return 0xb;
9759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else if (c == PAUSE) {
9769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return 0xc;
9779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else if (c == WILD) {
9789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return 0xd;
9799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
9809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            throw new RuntimeException ("invalid char for BCD " + c);
9819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
9829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
9839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
9859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Return true iff the network portion of <code>address</code> is,
9869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * as far as we can tell on the device, suitable for use as an SMS
9879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * destination address.
9889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
9899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static boolean isWellFormedSmsAddress(String address) {
9909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        String networkPortion =
9919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                PhoneNumberUtils.extractNetworkPortion(address);
9929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return (!(networkPortion.equals("+")
9949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                  || TextUtils.isEmpty(networkPortion)))
9959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project               && isDialable(networkPortion);
9969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
9979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static boolean isGlobalPhoneNumber(String phoneNumber) {
9999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (TextUtils.isEmpty(phoneNumber)) {
10009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
10019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
10029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Matcher match = GLOBAL_PHONE_NUMBER_PATTERN.matcher(phoneNumber);
10049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return match.matches();
10059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
10069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static boolean isDialable(String address) {
10089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (int i = 0, count = address.length(); i < count; i++) {
10099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (!isDialable(address.charAt(i))) {
10109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return false;
10119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
10129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
10139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return true;
10149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
10159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
101618e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com    private static boolean isNonSeparator(String address) {
101718e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com        for (int i = 0, count = address.length(); i < count; i++) {
101818e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com            if (!isNonSeparator(address.charAt(i))) {
101918e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com                return false;
102018e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com            }
102118e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com        }
102218e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com        return true;
102318e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com    }
10249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
10253a08cec99e104f74f28ba2463f00c8d4e6d1967eTammo Spalink     * Note: calls extractNetworkPortion(), so do not use for
10263a08cec99e104f74f28ba2463f00c8d4e6d1967eTammo Spalink     * SIM EF[ADN] style records
10273a08cec99e104f74f28ba2463f00c8d4e6d1967eTammo Spalink     *
10283a08cec99e104f74f28ba2463f00c8d4e6d1967eTammo Spalink     * Returns null if network portion is empty.
10293a08cec99e104f74f28ba2463f00c8d4e6d1967eTammo Spalink     */
10303a08cec99e104f74f28ba2463f00c8d4e6d1967eTammo Spalink    public static byte[]
10313a08cec99e104f74f28ba2463f00c8d4e6d1967eTammo Spalink    networkPortionToCalledPartyBCD(String s) {
10323a08cec99e104f74f28ba2463f00c8d4e6d1967eTammo Spalink        String networkPortion = extractNetworkPortion(s);
10333a08cec99e104f74f28ba2463f00c8d4e6d1967eTammo Spalink        return numberToCalledPartyBCDHelper(networkPortion, false);
10343a08cec99e104f74f28ba2463f00c8d4e6d1967eTammo Spalink    }
10353a08cec99e104f74f28ba2463f00c8d4e6d1967eTammo Spalink
10363a08cec99e104f74f28ba2463f00c8d4e6d1967eTammo Spalink    /**
10379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Same as {@link #networkPortionToCalledPartyBCD}, but includes a
10389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * one-byte length prefix.
10399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
10409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static byte[]
10419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    networkPortionToCalledPartyBCDWithLength(String s) {
10423a08cec99e104f74f28ba2463f00c8d4e6d1967eTammo Spalink        String networkPortion = extractNetworkPortion(s);
10433a08cec99e104f74f28ba2463f00c8d4e6d1967eTammo Spalink        return numberToCalledPartyBCDHelper(networkPortion, true);
10449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
10459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
10479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Convert a dialing number to BCD byte array
10489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
10499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param number dialing number string
1050145ff609de3206b585819ef974fab20cdc2d9f5eJake Hamby     *        if the dialing number starts with '+', set to international TOA
10519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return BCD byte array
10529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
10539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static byte[]
10549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    numberToCalledPartyBCD(String number) {
10553a08cec99e104f74f28ba2463f00c8d4e6d1967eTammo Spalink        return numberToCalledPartyBCDHelper(number, false);
10569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
10579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
10593a08cec99e104f74f28ba2463f00c8d4e6d1967eTammo Spalink     * If includeLength is true, prepend a one-byte length value to
10603a08cec99e104f74f28ba2463f00c8d4e6d1967eTammo Spalink     * the return array.
10619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
10629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static byte[]
10633a08cec99e104f74f28ba2463f00c8d4e6d1967eTammo Spalink    numberToCalledPartyBCDHelper(String number, boolean includeLength) {
10643a08cec99e104f74f28ba2463f00c8d4e6d1967eTammo Spalink        int numberLenReal = number.length();
10653a08cec99e104f74f28ba2463f00c8d4e6d1967eTammo Spalink        int numberLenEffective = numberLenReal;
10663a08cec99e104f74f28ba2463f00c8d4e6d1967eTammo Spalink        boolean hasPlus = number.indexOf('+') != -1;
10673a08cec99e104f74f28ba2463f00c8d4e6d1967eTammo Spalink        if (hasPlus) numberLenEffective--;
10689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10693a08cec99e104f74f28ba2463f00c8d4e6d1967eTammo Spalink        if (numberLenEffective == 0) return null;
10709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10713a08cec99e104f74f28ba2463f00c8d4e6d1967eTammo Spalink        int resultLen = (numberLenEffective + 1) / 2;  // Encoded numbers require only 4 bits each.
10723a08cec99e104f74f28ba2463f00c8d4e6d1967eTammo Spalink        int extraBytes = 1;                            // Prepended TOA byte.
10733a08cec99e104f74f28ba2463f00c8d4e6d1967eTammo Spalink        if (includeLength) extraBytes++;               // Optional prepended length byte.
10743a08cec99e104f74f28ba2463f00c8d4e6d1967eTammo Spalink        resultLen += extraBytes;
10759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10763a08cec99e104f74f28ba2463f00c8d4e6d1967eTammo Spalink        byte[] result = new byte[resultLen];
10779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10783a08cec99e104f74f28ba2463f00c8d4e6d1967eTammo Spalink        int digitCount = 0;
10793a08cec99e104f74f28ba2463f00c8d4e6d1967eTammo Spalink        for (int i = 0; i < numberLenReal; i++) {
10803a08cec99e104f74f28ba2463f00c8d4e6d1967eTammo Spalink            char c = number.charAt(i);
10813a08cec99e104f74f28ba2463f00c8d4e6d1967eTammo Spalink            if (c == '+') continue;
10823a08cec99e104f74f28ba2463f00c8d4e6d1967eTammo Spalink            int shift = ((digitCount & 0x01) == 1) ? 4 : 0;
10833a08cec99e104f74f28ba2463f00c8d4e6d1967eTammo Spalink            result[extraBytes + (digitCount >> 1)] |= (byte)((charToBCD(c) & 0x0F) << shift);
10843a08cec99e104f74f28ba2463f00c8d4e6d1967eTammo Spalink            digitCount++;
10859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
10869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10873a08cec99e104f74f28ba2463f00c8d4e6d1967eTammo Spalink        // 1-fill any trailing odd nibble/quartet.
10883a08cec99e104f74f28ba2463f00c8d4e6d1967eTammo Spalink        if ((digitCount & 0x01) == 1) result[extraBytes + (digitCount >> 1)] |= 0xF0;
10893a08cec99e104f74f28ba2463f00c8d4e6d1967eTammo Spalink
10903a08cec99e104f74f28ba2463f00c8d4e6d1967eTammo Spalink        int offset = 0;
10913a08cec99e104f74f28ba2463f00c8d4e6d1967eTammo Spalink        if (includeLength) result[offset++] = (byte)(resultLen - 1);
10923a08cec99e104f74f28ba2463f00c8d4e6d1967eTammo Spalink        result[offset] = (byte)(hasPlus ? TOA_International : TOA_Unknown);
10933a08cec99e104f74f28ba2463f00c8d4e6d1967eTammo Spalink
10943a08cec99e104f74f28ba2463f00c8d4e6d1967eTammo Spalink        return result;
10959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
10969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    //================ Number formatting =========================
10989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** The current locale is unknown, look for a country code or don't format */
11009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static final int FORMAT_UNKNOWN = 0;
11019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** NANP formatting */
11029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static final int FORMAT_NANP = 1;
11039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** Japanese formatting */
11049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static final int FORMAT_JAPAN = 2;
11059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** List of country codes for countries that use the NANP */
11079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final String[] NANP_COUNTRIES = new String[] {
11089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "US", // United States
11099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "CA", // Canada
11109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "AS", // American Samoa
11119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "AI", // Anguilla
11129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "AG", // Antigua and Barbuda
11139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "BS", // Bahamas
11149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "BB", // Barbados
11159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "BM", // Bermuda
11169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "VG", // British Virgin Islands
11179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "KY", // Cayman Islands
11189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "DM", // Dominica
11199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "DO", // Dominican Republic
11209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "GD", // Grenada
11219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "GU", // Guam
11229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "JM", // Jamaica
11239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "PR", // Puerto Rico
11249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "MS", // Montserrat
11257850cdde66705152b859aafda875833acdda9653Libin Tang        "MP", // Northern Mariana Islands
11269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "KN", // Saint Kitts and Nevis
11279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "LC", // Saint Lucia
11289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "VC", // Saint Vincent and the Grenadines
11299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "TT", // Trinidad and Tobago
11309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "TC", // Turks and Caicos Islands
11319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "VI", // U.S. Virgin Islands
11329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    };
11339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
11359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Breaks the given number down and formats it according to the rules
11369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * for the country the number is from.
11379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
1138d95a02c2a652ffe35dcc0336a3e35d91b1027d54Daisuke Miyakawa     * @param source The phone number to format
1139d95a02c2a652ffe35dcc0336a3e35d91b1027d54Daisuke Miyakawa     * @return A locally acceptable formatting of the input, or the raw input if
11409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *  formatting rules aren't known for the number
11419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
11429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static String formatNumber(String source) {
11439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        SpannableStringBuilder text = new SpannableStringBuilder(source);
11449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        formatNumber(text, getFormatTypeForLocale(Locale.getDefault()));
11459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return text.toString();
11469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
11479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1149d95a02c2a652ffe35dcc0336a3e35d91b1027d54Daisuke Miyakawa     * Formats the given number with the given formatting type. Currently
1150d95a02c2a652ffe35dcc0336a3e35d91b1027d54Daisuke Miyakawa     * {@link #FORMAT_NANP} and {@link #FORMAT_JAPAN} are supported as a formating type.
1151d95a02c2a652ffe35dcc0336a3e35d91b1027d54Daisuke Miyakawa     *
1152d95a02c2a652ffe35dcc0336a3e35d91b1027d54Daisuke Miyakawa     * @param source the phone number to format
1153d95a02c2a652ffe35dcc0336a3e35d91b1027d54Daisuke Miyakawa     * @param defaultFormattingType The default formatting rules to apply if the number does
1154145ff609de3206b585819ef974fab20cdc2d9f5eJake Hamby     * not begin with +[country_code]
1155d95a02c2a652ffe35dcc0336a3e35d91b1027d54Daisuke Miyakawa     * @return The phone number formatted with the given formatting type.
1156d95a02c2a652ffe35dcc0336a3e35d91b1027d54Daisuke Miyakawa     *
1157145ff609de3206b585819ef974fab20cdc2d9f5eJake Hamby     * @hide TODO: Should be unhidden.
1158d95a02c2a652ffe35dcc0336a3e35d91b1027d54Daisuke Miyakawa     */
1159d95a02c2a652ffe35dcc0336a3e35d91b1027d54Daisuke Miyakawa    public static String formatNumber(String source, int defaultFormattingType) {
1160d95a02c2a652ffe35dcc0336a3e35d91b1027d54Daisuke Miyakawa        SpannableStringBuilder text = new SpannableStringBuilder(source);
1161d95a02c2a652ffe35dcc0336a3e35d91b1027d54Daisuke Miyakawa        formatNumber(text, defaultFormattingType);
1162d95a02c2a652ffe35dcc0336a3e35d91b1027d54Daisuke Miyakawa        return text.toString();
1163d95a02c2a652ffe35dcc0336a3e35d91b1027d54Daisuke Miyakawa    }
1164d95a02c2a652ffe35dcc0336a3e35d91b1027d54Daisuke Miyakawa
1165d95a02c2a652ffe35dcc0336a3e35d91b1027d54Daisuke Miyakawa    /**
11669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Returns the phone number formatting type for the given locale.
11679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
11689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param locale The locale of interest, usually {@link Locale#getDefault()}
1169d95a02c2a652ffe35dcc0336a3e35d91b1027d54Daisuke Miyakawa     * @return The formatting type for the given locale, or FORMAT_UNKNOWN if the formatting
11709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * rules are not known for the given locale
11719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
11729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static int getFormatTypeForLocale(Locale locale) {
11739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        String country = locale.getCountry();
11749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11757850cdde66705152b859aafda875833acdda9653Libin Tang        return getFormatTypeFromCountryCode(country);
11769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
11779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1179d95a02c2a652ffe35dcc0336a3e35d91b1027d54Daisuke Miyakawa     * Formats a phone number in-place. Currently {@link #FORMAT_JAPAN} and {@link #FORMAT_NANP}
1180d95a02c2a652ffe35dcc0336a3e35d91b1027d54Daisuke Miyakawa     * is supported as a second argument.
11819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
11829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param text The number to be formatted, will be modified with the formatting
11839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param defaultFormattingType The default formatting rules to apply if the number does
1184145ff609de3206b585819ef974fab20cdc2d9f5eJake Hamby     * not begin with +[country_code]
11859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
11869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static void formatNumber(Editable text, int defaultFormattingType) {
11879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int formatType = defaultFormattingType;
11889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (text.length() > 2 && text.charAt(0) == '+') {
11909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (text.charAt(1) == '1') {
11919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                formatType = FORMAT_NANP;
11929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else if (text.length() >= 3 && text.charAt(1) == '8'
11939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                && text.charAt(2) == '1') {
11949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                formatType = FORMAT_JAPAN;
11959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else {
119647633f86279bc1854660d95a0b02bfa5ff14ad04Lars Dunemark                formatType = FORMAT_UNKNOWN;
11979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
11989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
11999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        switch (formatType) {
12019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case FORMAT_NANP:
12029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                formatNanpNumber(text);
12039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return;
12049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case FORMAT_JAPAN:
12059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                formatJapaneseNumber(text);
12069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return;
120747633f86279bc1854660d95a0b02bfa5ff14ad04Lars Dunemark            case FORMAT_UNKNOWN:
120847633f86279bc1854660d95a0b02bfa5ff14ad04Lars Dunemark                removeDashes(text);
120947633f86279bc1854660d95a0b02bfa5ff14ad04Lars Dunemark                return;
12109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
12119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
12129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int NANP_STATE_DIGIT = 1;
12149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int NANP_STATE_PLUS = 2;
12159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int NANP_STATE_ONE = 3;
12169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int NANP_STATE_DASH = 4;
12179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
12199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Formats a phone number in-place using the NANP formatting rules. Numbers will be formatted
12209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * as:
12219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
12229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * <p><code>
12235214376d2b1ce082765f766be1c7d56b50df74a7Ficus Kirkpatrick     * xxxxx
12249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * xxx-xxxx
12259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * xxx-xxx-xxxx
12269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * 1-xxx-xxx-xxxx
12279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * +1-xxx-xxx-xxxx
12289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * </code></p>
12299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
12309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param text the number to be formatted, will be modified with the formatting
12319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
12329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static void formatNanpNumber(Editable text) {
12339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int length = text.length();
12349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (length > "+1-nnn-nnn-nnnn".length()) {
12359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // The string is too long to be formatted
12369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return;
12375214376d2b1ce082765f766be1c7d56b50df74a7Ficus Kirkpatrick        } else if (length <= 5) {
12385214376d2b1ce082765f766be1c7d56b50df74a7Ficus Kirkpatrick            // The string is either a shortcode or too short to be formatted
12395214376d2b1ce082765f766be1c7d56b50df74a7Ficus Kirkpatrick            return;
12409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
12415214376d2b1ce082765f766be1c7d56b50df74a7Ficus Kirkpatrick
12429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        CharSequence saved = text.subSequence(0, length);
12439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Strip the dashes first, as we're going to add them back
124547633f86279bc1854660d95a0b02bfa5ff14ad04Lars Dunemark        removeDashes(text);
12469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        length = text.length();
12479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // When scanning the number we record where dashes need to be added,
12499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // if they're non-0 at the end of the scan the dashes will be added in
12509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // the proper places.
12519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int dashPositions[] = new int[3];
12529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int numDashes = 0;
12539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int state = NANP_STATE_DIGIT;
12559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int numDigits = 0;
12569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (int i = 0; i < length; i++) {
12579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            char c = text.charAt(i);
12589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            switch (c) {
12599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                case '1':
12609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    if (numDigits == 0 || state == NANP_STATE_PLUS) {
12619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        state = NANP_STATE_ONE;
12629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        break;
12639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
12649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // fall through
12659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                case '2':
12669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                case '3':
12679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                case '4':
12689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                case '5':
12699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                case '6':
12709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                case '7':
12719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                case '8':
12729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                case '9':
12739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                case '0':
12749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    if (state == NANP_STATE_PLUS) {
12759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        // Only NANP number supported for now
12769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        text.replace(0, length, saved);
12779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        return;
12789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    } else if (state == NANP_STATE_ONE) {
12799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        // Found either +1 or 1, follow it up with a dash
12809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        dashPositions[numDashes++] = i;
12819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    } else if (state != NANP_STATE_DASH && (numDigits == 3 || numDigits == 6)) {
12829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        // Found a digit that should be after a dash that isn't
12839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        dashPositions[numDashes++] = i;
12849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
12859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    state = NANP_STATE_DIGIT;
12869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    numDigits++;
12879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    break;
12889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                case '-':
12909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    state = NANP_STATE_DASH;
12919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    break;
12929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                case '+':
12949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    if (i == 0) {
12959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        // Plus is only allowed as the first character
12969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        state = NANP_STATE_PLUS;
12979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        break;
12989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
12999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // Fall through
13009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                default:
13019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // Unknown character, bail on formatting
13029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    text.replace(0, length, saved);
13039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    return;
13049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
13059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
13069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
13079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (numDigits == 7) {
13089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // With 7 digits we want xxx-xxxx, not xxx-xxx-x
13099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            numDashes--;
13109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
13119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
13129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Actually put the dashes in place
13139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (int i = 0; i < numDashes; i++) {
13149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int pos = dashPositions[i];
13159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            text.replace(pos + i, pos + i, "-");
13169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
13179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
13189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Remove trailing dashes
13199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int len = text.length();
13209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        while (len > 0) {
13219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (text.charAt(len - 1) == '-') {
13229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                text.delete(len - 1, len);
13239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                len--;
13249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else {
13259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                break;
13269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
13279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
13289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
13299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
13309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
13319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Formats a phone number in-place using the Japanese formatting rules.
13329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Numbers will be formatted as:
13339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
13349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * <p><code>
13359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * 03-xxxx-xxxx
13369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * 090-xxxx-xxxx
13379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * 0120-xxx-xxx
13389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * +81-3-xxxx-xxxx
13399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * +81-90-xxxx-xxxx
13409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * </code></p>
13419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
13429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param text the number to be formatted, will be modified with
13439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * the formatting
13449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
13459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static void formatJapaneseNumber(Editable text) {
13469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        JapanesePhoneNumberFormatter.format(text);
13479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
13489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
134947633f86279bc1854660d95a0b02bfa5ff14ad04Lars Dunemark    /**
135047633f86279bc1854660d95a0b02bfa5ff14ad04Lars Dunemark     * Removes all dashes from the number.
135147633f86279bc1854660d95a0b02bfa5ff14ad04Lars Dunemark     *
135247633f86279bc1854660d95a0b02bfa5ff14ad04Lars Dunemark     * @param text the number to clear from dashes
135347633f86279bc1854660d95a0b02bfa5ff14ad04Lars Dunemark     */
135447633f86279bc1854660d95a0b02bfa5ff14ad04Lars Dunemark    private static void removeDashes(Editable text) {
135547633f86279bc1854660d95a0b02bfa5ff14ad04Lars Dunemark        int p = 0;
135647633f86279bc1854660d95a0b02bfa5ff14ad04Lars Dunemark        while (p < text.length()) {
135747633f86279bc1854660d95a0b02bfa5ff14ad04Lars Dunemark            if (text.charAt(p) == '-') {
135847633f86279bc1854660d95a0b02bfa5ff14ad04Lars Dunemark                text.delete(p, p + 1);
135947633f86279bc1854660d95a0b02bfa5ff14ad04Lars Dunemark           } else {
136047633f86279bc1854660d95a0b02bfa5ff14ad04Lars Dunemark                p++;
136147633f86279bc1854660d95a0b02bfa5ff14ad04Lars Dunemark           }
136247633f86279bc1854660d95a0b02bfa5ff14ad04Lars Dunemark        }
136347633f86279bc1854660d95a0b02bfa5ff14ad04Lars Dunemark    }
136447633f86279bc1854660d95a0b02bfa5ff14ad04Lars Dunemark
1365fae6ec9e9673e96085fdbde69866a41b5491fa0dBai Tao    /**
1366fae6ec9e9673e96085fdbde69866a41b5491fa0dBai Tao     * Format the given phoneNumber to the E.164 representation.
1367fae6ec9e9673e96085fdbde69866a41b5491fa0dBai Tao     * <p>
1368fae6ec9e9673e96085fdbde69866a41b5491fa0dBai Tao     * The given phone number must have an area code and could have a country
1369fae6ec9e9673e96085fdbde69866a41b5491fa0dBai Tao     * code.
1370fae6ec9e9673e96085fdbde69866a41b5491fa0dBai Tao     * <p>
1371fae6ec9e9673e96085fdbde69866a41b5491fa0dBai Tao     * The defaultCountryIso is used to validate the given number and generate
1372fae6ec9e9673e96085fdbde69866a41b5491fa0dBai Tao     * the E.164 phone number if the given number doesn't have a country code.
1373fae6ec9e9673e96085fdbde69866a41b5491fa0dBai Tao     *
1374fae6ec9e9673e96085fdbde69866a41b5491fa0dBai Tao     * @param phoneNumber
1375fae6ec9e9673e96085fdbde69866a41b5491fa0dBai Tao     *            the phone number to format
1376fae6ec9e9673e96085fdbde69866a41b5491fa0dBai Tao     * @param defaultCountryIso
1377fae6ec9e9673e96085fdbde69866a41b5491fa0dBai Tao     *            the ISO 3166-1 two letters country code
1378fae6ec9e9673e96085fdbde69866a41b5491fa0dBai Tao     * @return the E.164 representation, or null if the given phone number is
1379fae6ec9e9673e96085fdbde69866a41b5491fa0dBai Tao     *         not valid.
1380fae6ec9e9673e96085fdbde69866a41b5491fa0dBai Tao     *
1381fae6ec9e9673e96085fdbde69866a41b5491fa0dBai Tao     * @hide
1382fae6ec9e9673e96085fdbde69866a41b5491fa0dBai Tao     */
1383fae6ec9e9673e96085fdbde69866a41b5491fa0dBai Tao    public static String formatNumberToE164(String phoneNumber, String defaultCountryIso) {
1384fae6ec9e9673e96085fdbde69866a41b5491fa0dBai Tao        PhoneNumberUtil util = PhoneNumberUtil.getInstance();
1385fae6ec9e9673e96085fdbde69866a41b5491fa0dBai Tao        String result = null;
1386fae6ec9e9673e96085fdbde69866a41b5491fa0dBai Tao        try {
1387fae6ec9e9673e96085fdbde69866a41b5491fa0dBai Tao            PhoneNumber pn = util.parse(phoneNumber, defaultCountryIso);
1388fae6ec9e9673e96085fdbde69866a41b5491fa0dBai Tao            if (util.isValidNumber(pn)) {
1389fae6ec9e9673e96085fdbde69866a41b5491fa0dBai Tao                result = util.format(pn, PhoneNumberFormat.E164);
1390fae6ec9e9673e96085fdbde69866a41b5491fa0dBai Tao            }
1391fae6ec9e9673e96085fdbde69866a41b5491fa0dBai Tao        } catch (NumberParseException e) {
1392fae6ec9e9673e96085fdbde69866a41b5491fa0dBai Tao        }
1393fae6ec9e9673e96085fdbde69866a41b5491fa0dBai Tao        return result;
1394fae6ec9e9673e96085fdbde69866a41b5491fa0dBai Tao    }
1395fae6ec9e9673e96085fdbde69866a41b5491fa0dBai Tao
1396fae6ec9e9673e96085fdbde69866a41b5491fa0dBai Tao    /**
1397fae6ec9e9673e96085fdbde69866a41b5491fa0dBai Tao     * Format a phone number.
1398fae6ec9e9673e96085fdbde69866a41b5491fa0dBai Tao     * <p>
1399fae6ec9e9673e96085fdbde69866a41b5491fa0dBai Tao     * If the given number doesn't have the country code, the phone will be
1400fae6ec9e9673e96085fdbde69866a41b5491fa0dBai Tao     * formatted to the default country's convention.
1401fae6ec9e9673e96085fdbde69866a41b5491fa0dBai Tao     *
1402fae6ec9e9673e96085fdbde69866a41b5491fa0dBai Tao     * @param phoneNumber
1403fae6ec9e9673e96085fdbde69866a41b5491fa0dBai Tao     *            the number to be formatted.
1404fae6ec9e9673e96085fdbde69866a41b5491fa0dBai Tao     * @param defaultCountryIso
1405fae6ec9e9673e96085fdbde69866a41b5491fa0dBai Tao     *            the ISO 3166-1 two letters country code whose convention will
1406fae6ec9e9673e96085fdbde69866a41b5491fa0dBai Tao     *            be used if the given number doesn't have the country code.
1407fae6ec9e9673e96085fdbde69866a41b5491fa0dBai Tao     * @return the formatted number, or null if the given number is not valid.
1408fae6ec9e9673e96085fdbde69866a41b5491fa0dBai Tao     *
1409fae6ec9e9673e96085fdbde69866a41b5491fa0dBai Tao     * @hide
1410fae6ec9e9673e96085fdbde69866a41b5491fa0dBai Tao     */
1411fae6ec9e9673e96085fdbde69866a41b5491fa0dBai Tao    public static String formatNumber(String phoneNumber, String defaultCountryIso) {
14122613e0064b4a43b7de4205d5a6aaae64416972edFlavio Lerda        // Do not attempt to format numbers that start with a hash or star symbol.
14132613e0064b4a43b7de4205d5a6aaae64416972edFlavio Lerda        if (phoneNumber.startsWith("#") || phoneNumber.startsWith("*")) {
14142613e0064b4a43b7de4205d5a6aaae64416972edFlavio Lerda            return phoneNumber;
14152613e0064b4a43b7de4205d5a6aaae64416972edFlavio Lerda        }
14162613e0064b4a43b7de4205d5a6aaae64416972edFlavio Lerda
1417fae6ec9e9673e96085fdbde69866a41b5491fa0dBai Tao        PhoneNumberUtil util = PhoneNumberUtil.getInstance();
1418fae6ec9e9673e96085fdbde69866a41b5491fa0dBai Tao        String result = null;
1419fae6ec9e9673e96085fdbde69866a41b5491fa0dBai Tao        try {
14202a4e96067d074ef78aeafea13469a85690346b60Bai Tao            PhoneNumber pn = util.parseAndKeepRawInput(phoneNumber, defaultCountryIso);
1421fae6ec9e9673e96085fdbde69866a41b5491fa0dBai Tao            result = util.formatInOriginalFormat(pn, defaultCountryIso);
1422fae6ec9e9673e96085fdbde69866a41b5491fa0dBai Tao        } catch (NumberParseException e) {
1423fae6ec9e9673e96085fdbde69866a41b5491fa0dBai Tao        }
1424fae6ec9e9673e96085fdbde69866a41b5491fa0dBai Tao        return result;
1425fae6ec9e9673e96085fdbde69866a41b5491fa0dBai Tao    }
1426fae6ec9e9673e96085fdbde69866a41b5491fa0dBai Tao
1427fae6ec9e9673e96085fdbde69866a41b5491fa0dBai Tao    /**
14282a4e96067d074ef78aeafea13469a85690346b60Bai Tao     * Format the phone number only if the given number hasn't been formatted.
14292a4e96067d074ef78aeafea13469a85690346b60Bai Tao     * <p>
14302a4e96067d074ef78aeafea13469a85690346b60Bai Tao     * The number which has only dailable character is treated as not being
14312a4e96067d074ef78aeafea13469a85690346b60Bai Tao     * formatted.
14322a4e96067d074ef78aeafea13469a85690346b60Bai Tao     *
14332a4e96067d074ef78aeafea13469a85690346b60Bai Tao     * @param phoneNumber
14342a4e96067d074ef78aeafea13469a85690346b60Bai Tao     *            the number to be formatted.
14352a4e96067d074ef78aeafea13469a85690346b60Bai Tao     * @param phoneNumberE164
14362a4e96067d074ef78aeafea13469a85690346b60Bai Tao     *            the E164 format number whose country code is used if the given
14372a4e96067d074ef78aeafea13469a85690346b60Bai Tao     *            phoneNumber doesn't have the country code.
14382a4e96067d074ef78aeafea13469a85690346b60Bai Tao     * @param defaultCountryIso
14392a4e96067d074ef78aeafea13469a85690346b60Bai Tao     *            the ISO 3166-1 two letters country code whose convention will
144026cd243601fc05c5ed39c2d1e3ab203a8eb97c25Shaopeng Jia     *            be used if the phoneNumberE164 is null or invalid, or if phoneNumber
144126cd243601fc05c5ed39c2d1e3ab203a8eb97c25Shaopeng Jia     *            contains IDD.
14422a4e96067d074ef78aeafea13469a85690346b60Bai Tao     * @return the formatted number if the given number has been formatted,
14432a4e96067d074ef78aeafea13469a85690346b60Bai Tao     *            otherwise, return the given number.
14442a4e96067d074ef78aeafea13469a85690346b60Bai Tao     *
14452a4e96067d074ef78aeafea13469a85690346b60Bai Tao     * @hide
14462a4e96067d074ef78aeafea13469a85690346b60Bai Tao     */
14472a4e96067d074ef78aeafea13469a85690346b60Bai Tao    public static String formatNumber(
14482a4e96067d074ef78aeafea13469a85690346b60Bai Tao            String phoneNumber, String phoneNumberE164, String defaultCountryIso) {
14492a4e96067d074ef78aeafea13469a85690346b60Bai Tao        int len = phoneNumber.length();
14502a4e96067d074ef78aeafea13469a85690346b60Bai Tao        for (int i = 0; i < len; i++) {
14512a4e96067d074ef78aeafea13469a85690346b60Bai Tao            if (!isDialable(phoneNumber.charAt(i))) {
14522a4e96067d074ef78aeafea13469a85690346b60Bai Tao                return phoneNumber;
14532a4e96067d074ef78aeafea13469a85690346b60Bai Tao            }
14542a4e96067d074ef78aeafea13469a85690346b60Bai Tao        }
14552a4e96067d074ef78aeafea13469a85690346b60Bai Tao        PhoneNumberUtil util = PhoneNumberUtil.getInstance();
14562a4e96067d074ef78aeafea13469a85690346b60Bai Tao        // Get the country code from phoneNumberE164
14572a4e96067d074ef78aeafea13469a85690346b60Bai Tao        if (phoneNumberE164 != null && phoneNumberE164.length() >= 2
14582a4e96067d074ef78aeafea13469a85690346b60Bai Tao                && phoneNumberE164.charAt(0) == '+') {
14592a4e96067d074ef78aeafea13469a85690346b60Bai Tao            try {
146026cd243601fc05c5ed39c2d1e3ab203a8eb97c25Shaopeng Jia                // The number to be parsed is in E164 format, so the default region used doesn't
146126cd243601fc05c5ed39c2d1e3ab203a8eb97c25Shaopeng Jia                // matter.
146226cd243601fc05c5ed39c2d1e3ab203a8eb97c25Shaopeng Jia                PhoneNumber pn = util.parse(phoneNumberE164, "ZZ");
14632a4e96067d074ef78aeafea13469a85690346b60Bai Tao                String regionCode = util.getRegionCodeForNumber(pn);
146426cd243601fc05c5ed39c2d1e3ab203a8eb97c25Shaopeng Jia                if (!TextUtils.isEmpty(regionCode) &&
146526cd243601fc05c5ed39c2d1e3ab203a8eb97c25Shaopeng Jia                    // This makes sure phoneNumber doesn't contain an IDD
146626cd243601fc05c5ed39c2d1e3ab203a8eb97c25Shaopeng Jia                    normalizeNumber(phoneNumber).indexOf(phoneNumberE164.substring(1)) <= 0) {
14672a4e96067d074ef78aeafea13469a85690346b60Bai Tao                    defaultCountryIso = regionCode;
14682a4e96067d074ef78aeafea13469a85690346b60Bai Tao                }
14692a4e96067d074ef78aeafea13469a85690346b60Bai Tao            } catch (NumberParseException e) {
14702a4e96067d074ef78aeafea13469a85690346b60Bai Tao            }
14712a4e96067d074ef78aeafea13469a85690346b60Bai Tao        }
14722a4e96067d074ef78aeafea13469a85690346b60Bai Tao        String result = formatNumber(phoneNumber, defaultCountryIso);
14732a4e96067d074ef78aeafea13469a85690346b60Bai Tao        return result != null ? result : phoneNumber;
14742a4e96067d074ef78aeafea13469a85690346b60Bai Tao    }
14752a4e96067d074ef78aeafea13469a85690346b60Bai Tao
14762a4e96067d074ef78aeafea13469a85690346b60Bai Tao    /**
1477fae6ec9e9673e96085fdbde69866a41b5491fa0dBai Tao     * Normalize a phone number by removing the characters other than digits. If
1478fae6ec9e9673e96085fdbde69866a41b5491fa0dBai Tao     * the given number has keypad letters, the letters will be converted to
1479fae6ec9e9673e96085fdbde69866a41b5491fa0dBai Tao     * digits first.
14803e4b7c332fcdeb3adf359b5fcf8cba08c474c9c0Dmitri Plotnikov     *
1481fae6ec9e9673e96085fdbde69866a41b5491fa0dBai Tao     * @param phoneNumber
1482fae6ec9e9673e96085fdbde69866a41b5491fa0dBai Tao     *            the number to be normalized.
1483fae6ec9e9673e96085fdbde69866a41b5491fa0dBai Tao     * @return the normalized number.
1484fae6ec9e9673e96085fdbde69866a41b5491fa0dBai Tao     *
1485fae6ec9e9673e96085fdbde69866a41b5491fa0dBai Tao     * @hide
1486fae6ec9e9673e96085fdbde69866a41b5491fa0dBai Tao     */
1487fae6ec9e9673e96085fdbde69866a41b5491fa0dBai Tao    public static String normalizeNumber(String phoneNumber) {
1488fae6ec9e9673e96085fdbde69866a41b5491fa0dBai Tao        StringBuilder sb = new StringBuilder();
1489fae6ec9e9673e96085fdbde69866a41b5491fa0dBai Tao        int len = phoneNumber.length();
1490fae6ec9e9673e96085fdbde69866a41b5491fa0dBai Tao        for (int i = 0; i < len; i++) {
1491fae6ec9e9673e96085fdbde69866a41b5491fa0dBai Tao            char c = phoneNumber.charAt(i);
1492e333c82da35119cfa25109328c3db98fa84f965eJake Hamby            // Character.digit() supports ASCII and Unicode digits (fullwidth, Arabic-Indic, etc.)
1493e333c82da35119cfa25109328c3db98fa84f965eJake Hamby            int digit = Character.digit(c, 10);
1494e333c82da35119cfa25109328c3db98fa84f965eJake Hamby            if (digit != -1) {
1495e333c82da35119cfa25109328c3db98fa84f965eJake Hamby                sb.append(digit);
1496e333c82da35119cfa25109328c3db98fa84f965eJake Hamby            } else if (i == 0 && c == '+') {
1497fae6ec9e9673e96085fdbde69866a41b5491fa0dBai Tao                sb.append(c);
14983e4b7c332fcdeb3adf359b5fcf8cba08c474c9c0Dmitri Plotnikov            } else if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) {
1499fae6ec9e9673e96085fdbde69866a41b5491fa0dBai Tao                return normalizeNumber(PhoneNumberUtils.convertKeypadLettersToDigits(phoneNumber));
1500fae6ec9e9673e96085fdbde69866a41b5491fa0dBai Tao            }
1501fae6ec9e9673e96085fdbde69866a41b5491fa0dBai Tao        }
1502fae6ec9e9673e96085fdbde69866a41b5491fa0dBai Tao        return sb.toString();
1503fae6ec9e9673e96085fdbde69866a41b5491fa0dBai Tao    }
1504fae6ec9e9673e96085fdbde69866a41b5491fa0dBai Tao
1505f80310d3c56387091ccd4111b698c09f76b8c53djshin    /**
1506f80310d3c56387091ccd4111b698c09f76b8c53djshin     * Replace arabic/unicode digits with decimal digits.
1507f80310d3c56387091ccd4111b698c09f76b8c53djshin     * @param number
1508f80310d3c56387091ccd4111b698c09f76b8c53djshin     *            the number to be normalized.
1509f80310d3c56387091ccd4111b698c09f76b8c53djshin     * @return the replaced number.
1510f80310d3c56387091ccd4111b698c09f76b8c53djshin     *
1511f80310d3c56387091ccd4111b698c09f76b8c53djshin     * @hide
1512f80310d3c56387091ccd4111b698c09f76b8c53djshin     */
1513f80310d3c56387091ccd4111b698c09f76b8c53djshin    public static String replaceUnicodeDigits(String number) {
1514f80310d3c56387091ccd4111b698c09f76b8c53djshin        StringBuilder normalizedDigits = new StringBuilder(number.length());
1515f80310d3c56387091ccd4111b698c09f76b8c53djshin        for (char c : number.toCharArray()) {
1516f80310d3c56387091ccd4111b698c09f76b8c53djshin            int digit = Character.digit(c, 10);
1517f80310d3c56387091ccd4111b698c09f76b8c53djshin            if (digit != -1) {
1518f80310d3c56387091ccd4111b698c09f76b8c53djshin                normalizedDigits.append(digit);
1519f80310d3c56387091ccd4111b698c09f76b8c53djshin            } else {
1520f80310d3c56387091ccd4111b698c09f76b8c53djshin                normalizedDigits.append(c);
1521f80310d3c56387091ccd4111b698c09f76b8c53djshin            }
1522f80310d3c56387091ccd4111b698c09f76b8c53djshin        }
1523f80310d3c56387091ccd4111b698c09f76b8c53djshin        return normalizedDigits.toString();
1524f80310d3c56387091ccd4111b698c09f76b8c53djshin    }
1525f80310d3c56387091ccd4111b698c09f76b8c53djshin
152602b5948a4375dba5d287a59ba023eaf1e02b45dcWei Huang    // Three and four digit phone numbers for either special services,
152702b5948a4375dba5d287a59ba023eaf1e02b45dcWei Huang    // or 3-6 digit addresses from the network (eg carrier-originated SMS messages) should
152802b5948a4375dba5d287a59ba023eaf1e02b45dcWei Huang    // not match.
152902b5948a4375dba5d287a59ba023eaf1e02b45dcWei Huang    //
153002b5948a4375dba5d287a59ba023eaf1e02b45dcWei Huang    // This constant used to be 5, but SMS short codes has increased in length and
153102b5948a4375dba5d287a59ba023eaf1e02b45dcWei Huang    // can be easily 6 digits now days. Most countries have SMS short code length between
153202b5948a4375dba5d287a59ba023eaf1e02b45dcWei Huang    // 3 to 6 digits. The exceptions are
153302b5948a4375dba5d287a59ba023eaf1e02b45dcWei Huang    //
153402b5948a4375dba5d287a59ba023eaf1e02b45dcWei Huang    // Australia: Short codes are six or eight digits in length, starting with the prefix "19"
153502b5948a4375dba5d287a59ba023eaf1e02b45dcWei Huang    //            followed by an additional four or six digits and two.
153602b5948a4375dba5d287a59ba023eaf1e02b45dcWei Huang    // Czech Republic: Codes are seven digits in length for MO and five (not billed) or
153702b5948a4375dba5d287a59ba023eaf1e02b45dcWei Huang    //            eight (billed) for MT direction
153802b5948a4375dba5d287a59ba023eaf1e02b45dcWei Huang    //
153902b5948a4375dba5d287a59ba023eaf1e02b45dcWei Huang    // see http://en.wikipedia.org/wiki/Short_code#Regional_differences for reference
154002b5948a4375dba5d287a59ba023eaf1e02b45dcWei Huang    //
154102b5948a4375dba5d287a59ba023eaf1e02b45dcWei Huang    // However, in order to loose match 650-555-1212 and 555-1212, we need to set the min match
154202b5948a4375dba5d287a59ba023eaf1e02b45dcWei Huang    // to 7.
154302b5948a4375dba5d287a59ba023eaf1e02b45dcWei Huang    static final int MIN_MATCH = 7;
15449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
15459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
15461a811695f9ae2ac806a64fd3b6c440c83262dc52David Brown     * Checks a given number against the list of
15471a811695f9ae2ac806a64fd3b6c440c83262dc52David Brown     * emergency numbers provided by the RIL and SIM card.
15489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
15499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param number the number to look up.
15501a811695f9ae2ac806a64fd3b6c440c83262dc52David Brown     * @return true if the number is in the list of emergency numbers
15511a811695f9ae2ac806a64fd3b6c440c83262dc52David Brown     *         listed in the RIL / SIM, otherwise return false.
15529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
15539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static boolean isEmergencyNumber(String number) {
15541a811695f9ae2ac806a64fd3b6c440c83262dc52David Brown        // Return true only if the specified number *exactly* matches
15551a811695f9ae2ac806a64fd3b6c440c83262dc52David Brown        // one of the emergency numbers listed by the RIL / SIM.
15561a811695f9ae2ac806a64fd3b6c440c83262dc52David Brown        return isEmergencyNumberInternal(number, true /* useExactMatch */);
15571a811695f9ae2ac806a64fd3b6c440c83262dc52David Brown    }
15581a811695f9ae2ac806a64fd3b6c440c83262dc52David Brown
15591a811695f9ae2ac806a64fd3b6c440c83262dc52David Brown    /**
15601a811695f9ae2ac806a64fd3b6c440c83262dc52David Brown     * Checks if given number might *potentially* result in
15611a811695f9ae2ac806a64fd3b6c440c83262dc52David Brown     * a call to an emergency service on the current network.
15621a811695f9ae2ac806a64fd3b6c440c83262dc52David Brown     *
15631a811695f9ae2ac806a64fd3b6c440c83262dc52David Brown     * Specifically, this method will return true if the specified number
15641a811695f9ae2ac806a64fd3b6c440c83262dc52David Brown     * is an emergency number according to the list managed by the RIL or
15651a811695f9ae2ac806a64fd3b6c440c83262dc52David Brown     * SIM, *or* if the specified number simply starts with the same
15661a811695f9ae2ac806a64fd3b6c440c83262dc52David Brown     * digits as any of the emergency numbers listed in the RIL / SIM.
15671a811695f9ae2ac806a64fd3b6c440c83262dc52David Brown     *
15681a811695f9ae2ac806a64fd3b6c440c83262dc52David Brown     * This method is intended for internal use by the phone app when
15691a811695f9ae2ac806a64fd3b6c440c83262dc52David Brown     * deciding whether to allow ACTION_CALL intents from 3rd party apps
15701a811695f9ae2ac806a64fd3b6c440c83262dc52David Brown     * (where we're required to *not* allow emergency calls to be placed.)
15711a811695f9ae2ac806a64fd3b6c440c83262dc52David Brown     *
15721a811695f9ae2ac806a64fd3b6c440c83262dc52David Brown     * @param number the number to look up.
15731a811695f9ae2ac806a64fd3b6c440c83262dc52David Brown     * @return true if the number is in the list of emergency numbers
15741a811695f9ae2ac806a64fd3b6c440c83262dc52David Brown     *         listed in the RIL / SIM, *or* if the number starts with the
15751a811695f9ae2ac806a64fd3b6c440c83262dc52David Brown     *         same digits as any of those emergency numbers.
15761a811695f9ae2ac806a64fd3b6c440c83262dc52David Brown     *
15771a811695f9ae2ac806a64fd3b6c440c83262dc52David Brown     * @hide
15781a811695f9ae2ac806a64fd3b6c440c83262dc52David Brown     */
15791a811695f9ae2ac806a64fd3b6c440c83262dc52David Brown    public static boolean isPotentialEmergencyNumber(String number) {
15801a811695f9ae2ac806a64fd3b6c440c83262dc52David Brown        // Check against the emergency numbers listed by the RIL / SIM,
15811a811695f9ae2ac806a64fd3b6c440c83262dc52David Brown        // and *don't* require an exact match.
15821a811695f9ae2ac806a64fd3b6c440c83262dc52David Brown        return isEmergencyNumberInternal(number, false /* useExactMatch */);
15831a811695f9ae2ac806a64fd3b6c440c83262dc52David Brown    }
15841a811695f9ae2ac806a64fd3b6c440c83262dc52David Brown
15851a811695f9ae2ac806a64fd3b6c440c83262dc52David Brown    /**
15861a811695f9ae2ac806a64fd3b6c440c83262dc52David Brown     * Helper function for isEmergencyNumber(String) and
15871a811695f9ae2ac806a64fd3b6c440c83262dc52David Brown     * isPotentialEmergencyNumber(String).
15881a811695f9ae2ac806a64fd3b6c440c83262dc52David Brown     *
15891a811695f9ae2ac806a64fd3b6c440c83262dc52David Brown     * @param number the number to look up.
15901a811695f9ae2ac806a64fd3b6c440c83262dc52David Brown     *
15911a811695f9ae2ac806a64fd3b6c440c83262dc52David Brown     * @param useExactMatch if true, consider a number to be an emergency
15921a811695f9ae2ac806a64fd3b6c440c83262dc52David Brown     *           number only if it *exactly* matches a number listed in
15931a811695f9ae2ac806a64fd3b6c440c83262dc52David Brown     *           the RIL / SIM.  If false, a number is considered to be an
15941a811695f9ae2ac806a64fd3b6c440c83262dc52David Brown     *           emergency number if it simply starts with the same digits
15951a811695f9ae2ac806a64fd3b6c440c83262dc52David Brown     *           as any of the emergency numbers listed in the RIL / SIM.
15961a811695f9ae2ac806a64fd3b6c440c83262dc52David Brown     *           (Setting useExactMatch to false allows you to identify
15971a811695f9ae2ac806a64fd3b6c440c83262dc52David Brown     *           number that could *potentially* result in emergency calls
15981a811695f9ae2ac806a64fd3b6c440c83262dc52David Brown     *           since many networks will actually ignore trailing digits
15991a811695f9ae2ac806a64fd3b6c440c83262dc52David Brown     *           after a valid emergency number.)
16001a811695f9ae2ac806a64fd3b6c440c83262dc52David Brown     *
16011a811695f9ae2ac806a64fd3b6c440c83262dc52David Brown     * @return true if the number is in the list of emergency numbers
16021a811695f9ae2ac806a64fd3b6c440c83262dc52David Brown     *         listed in the RIL / sim, otherwise return false.
16031a811695f9ae2ac806a64fd3b6c440c83262dc52David Brown     */
16041a811695f9ae2ac806a64fd3b6c440c83262dc52David Brown    private static boolean isEmergencyNumberInternal(String number, boolean useExactMatch) {
1605ab971d3c26346cfd94a37e40591318bf3b3ae4fdShaopeng Jia        return isEmergencyNumberInternal(number, null, useExactMatch);
16069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
16079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
16089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
16099683f990a282776ac8a588a9d5e1a73b61f43dcfShaopeng Jia     * Checks if a given number is an emergency number for a specific country.
16109683f990a282776ac8a588a9d5e1a73b61f43dcfShaopeng Jia     *
16119683f990a282776ac8a588a9d5e1a73b61f43dcfShaopeng Jia     * @param number the number to look up.
16129683f990a282776ac8a588a9d5e1a73b61f43dcfShaopeng Jia     * @param defaultCountryIso the specific country which the number should be checked against
16139683f990a282776ac8a588a9d5e1a73b61f43dcfShaopeng Jia     * @return if the number is an emergency number for the specific country, then return true,
16149683f990a282776ac8a588a9d5e1a73b61f43dcfShaopeng Jia     * otherwise false
16151a811695f9ae2ac806a64fd3b6c440c83262dc52David Brown     *
16169683f990a282776ac8a588a9d5e1a73b61f43dcfShaopeng Jia     * @hide
16179683f990a282776ac8a588a9d5e1a73b61f43dcfShaopeng Jia     */
16189683f990a282776ac8a588a9d5e1a73b61f43dcfShaopeng Jia    public static boolean isEmergencyNumber(String number, String defaultCountryIso) {
16191a811695f9ae2ac806a64fd3b6c440c83262dc52David Brown        return isEmergencyNumberInternal(number,
16201a811695f9ae2ac806a64fd3b6c440c83262dc52David Brown                                         defaultCountryIso,
16211a811695f9ae2ac806a64fd3b6c440c83262dc52David Brown                                         true /* useExactMatch */);
16221a811695f9ae2ac806a64fd3b6c440c83262dc52David Brown    }
16231a811695f9ae2ac806a64fd3b6c440c83262dc52David Brown
16241a811695f9ae2ac806a64fd3b6c440c83262dc52David Brown    /**
16251a811695f9ae2ac806a64fd3b6c440c83262dc52David Brown     * Checks if a given number might *potentially* result in a call to an
16261a811695f9ae2ac806a64fd3b6c440c83262dc52David Brown     * emergency service, for a specific country.
16271a811695f9ae2ac806a64fd3b6c440c83262dc52David Brown     *
16281a811695f9ae2ac806a64fd3b6c440c83262dc52David Brown     * Specifically, this method will return true if the specified number
16291a811695f9ae2ac806a64fd3b6c440c83262dc52David Brown     * is an emergency number in the specified country, *or* if the number
16301a811695f9ae2ac806a64fd3b6c440c83262dc52David Brown     * simply starts with the same digits as any emergency number for that
16311a811695f9ae2ac806a64fd3b6c440c83262dc52David Brown     * country.
16321a811695f9ae2ac806a64fd3b6c440c83262dc52David Brown     *
16331a811695f9ae2ac806a64fd3b6c440c83262dc52David Brown     * This method is intended for internal use by the phone app when
16341a811695f9ae2ac806a64fd3b6c440c83262dc52David Brown     * deciding whether to allow ACTION_CALL intents from 3rd party apps
16351a811695f9ae2ac806a64fd3b6c440c83262dc52David Brown     * (where we're required to *not* allow emergency calls to be placed.)
16361a811695f9ae2ac806a64fd3b6c440c83262dc52David Brown     *
16371a811695f9ae2ac806a64fd3b6c440c83262dc52David Brown     * @param number the number to look up.
16381a811695f9ae2ac806a64fd3b6c440c83262dc52David Brown     * @param defaultCountryIso the specific country which the number should be checked against
16391a811695f9ae2ac806a64fd3b6c440c83262dc52David Brown     * @return true if the number is an emergency number for the specific
16401a811695f9ae2ac806a64fd3b6c440c83262dc52David Brown     *         country, *or* if the number starts with the same digits as
16411a811695f9ae2ac806a64fd3b6c440c83262dc52David Brown     *         any of those emergency numbers.
16421a811695f9ae2ac806a64fd3b6c440c83262dc52David Brown     *
16431a811695f9ae2ac806a64fd3b6c440c83262dc52David Brown     * @hide
16441a811695f9ae2ac806a64fd3b6c440c83262dc52David Brown     */
16451a811695f9ae2ac806a64fd3b6c440c83262dc52David Brown    public static boolean isPotentialEmergencyNumber(String number, String defaultCountryIso) {
16461a811695f9ae2ac806a64fd3b6c440c83262dc52David Brown        return isEmergencyNumberInternal(number,
16471a811695f9ae2ac806a64fd3b6c440c83262dc52David Brown                                         defaultCountryIso,
16481a811695f9ae2ac806a64fd3b6c440c83262dc52David Brown                                         false /* useExactMatch */);
16491a811695f9ae2ac806a64fd3b6c440c83262dc52David Brown    }
16501a811695f9ae2ac806a64fd3b6c440c83262dc52David Brown
16511a811695f9ae2ac806a64fd3b6c440c83262dc52David Brown    /**
16521a811695f9ae2ac806a64fd3b6c440c83262dc52David Brown     * Helper function for isEmergencyNumber(String, String) and
16531a811695f9ae2ac806a64fd3b6c440c83262dc52David Brown     * isPotentialEmergencyNumber(String, String).
16541a811695f9ae2ac806a64fd3b6c440c83262dc52David Brown     *
16551a811695f9ae2ac806a64fd3b6c440c83262dc52David Brown     * @param number the number to look up.
16561a811695f9ae2ac806a64fd3b6c440c83262dc52David Brown     * @param defaultCountryIso the specific country which the number should be checked against
16571a811695f9ae2ac806a64fd3b6c440c83262dc52David Brown     * @param useExactMatch if true, consider a number to be an emergency
16581a811695f9ae2ac806a64fd3b6c440c83262dc52David Brown     *           number only if it *exactly* matches a number listed in
16591a811695f9ae2ac806a64fd3b6c440c83262dc52David Brown     *           the RIL / SIM.  If false, a number is considered to be an
16601a811695f9ae2ac806a64fd3b6c440c83262dc52David Brown     *           emergency number if it simply starts with the same digits
16611a811695f9ae2ac806a64fd3b6c440c83262dc52David Brown     *           as any of the emergency numbers listed in the RIL / SIM.
16621a811695f9ae2ac806a64fd3b6c440c83262dc52David Brown     *
16631a811695f9ae2ac806a64fd3b6c440c83262dc52David Brown     * @return true if the number is an emergency number for the specified country.
16641a811695f9ae2ac806a64fd3b6c440c83262dc52David Brown     */
16651a811695f9ae2ac806a64fd3b6c440c83262dc52David Brown    private static boolean isEmergencyNumberInternal(String number,
16661a811695f9ae2ac806a64fd3b6c440c83262dc52David Brown                                                     String defaultCountryIso,
16671a811695f9ae2ac806a64fd3b6c440c83262dc52David Brown                                                     boolean useExactMatch) {
1668ab971d3c26346cfd94a37e40591318bf3b3ae4fdShaopeng Jia        // If the number passed in is null, just return false:
1669ab971d3c26346cfd94a37e40591318bf3b3ae4fdShaopeng Jia        if (number == null) return false;
1670ab971d3c26346cfd94a37e40591318bf3b3ae4fdShaopeng Jia
1671ab971d3c26346cfd94a37e40591318bf3b3ae4fdShaopeng Jia        // If the number passed in is a SIP address, return false, since the
1672ab971d3c26346cfd94a37e40591318bf3b3ae4fdShaopeng Jia        // concept of "emergency numbers" is only meaningful for calls placed
1673ab971d3c26346cfd94a37e40591318bf3b3ae4fdShaopeng Jia        // over the cell network.
1674ab971d3c26346cfd94a37e40591318bf3b3ae4fdShaopeng Jia        // (Be sure to do this check *before* calling extractNetworkPortionAlt(),
1675ab971d3c26346cfd94a37e40591318bf3b3ae4fdShaopeng Jia        // since the whole point of extractNetworkPortionAlt() is to filter out
1676ab971d3c26346cfd94a37e40591318bf3b3ae4fdShaopeng Jia        // any non-dialable characters (which would turn 'abc911def@example.com'
1677ab971d3c26346cfd94a37e40591318bf3b3ae4fdShaopeng Jia        // into '911', for example.))
1678ab971d3c26346cfd94a37e40591318bf3b3ae4fdShaopeng Jia        if (isUriNumber(number)) {
1679ab971d3c26346cfd94a37e40591318bf3b3ae4fdShaopeng Jia            return false;
1680ab971d3c26346cfd94a37e40591318bf3b3ae4fdShaopeng Jia        }
1681ab971d3c26346cfd94a37e40591318bf3b3ae4fdShaopeng Jia
1682ab971d3c26346cfd94a37e40591318bf3b3ae4fdShaopeng Jia        // Strip the separators from the number before comparing it
1683ab971d3c26346cfd94a37e40591318bf3b3ae4fdShaopeng Jia        // to the list.
1684ab971d3c26346cfd94a37e40591318bf3b3ae4fdShaopeng Jia        number = extractNetworkPortionAlt(number);
1685ab971d3c26346cfd94a37e40591318bf3b3ae4fdShaopeng Jia
1686ab971d3c26346cfd94a37e40591318bf3b3ae4fdShaopeng Jia        // retrieve the list of emergency numbers
1687ab971d3c26346cfd94a37e40591318bf3b3ae4fdShaopeng Jia        // check read-write ecclist property first
1688ab971d3c26346cfd94a37e40591318bf3b3ae4fdShaopeng Jia        String numbers = SystemProperties.get("ril.ecclist");
1689ab971d3c26346cfd94a37e40591318bf3b3ae4fdShaopeng Jia        if (TextUtils.isEmpty(numbers)) {
1690ab971d3c26346cfd94a37e40591318bf3b3ae4fdShaopeng Jia            // then read-only ecclist property since old RIL only uses this
1691ab971d3c26346cfd94a37e40591318bf3b3ae4fdShaopeng Jia            numbers = SystemProperties.get("ro.ril.ecclist");
1692ab971d3c26346cfd94a37e40591318bf3b3ae4fdShaopeng Jia        }
1693ab971d3c26346cfd94a37e40591318bf3b3ae4fdShaopeng Jia
1694ab971d3c26346cfd94a37e40591318bf3b3ae4fdShaopeng Jia        if (!TextUtils.isEmpty(numbers)) {
1695ab971d3c26346cfd94a37e40591318bf3b3ae4fdShaopeng Jia            // searches through the comma-separated list for a match,
1696ab971d3c26346cfd94a37e40591318bf3b3ae4fdShaopeng Jia            // return true if one is found.
1697ab971d3c26346cfd94a37e40591318bf3b3ae4fdShaopeng Jia            for (String emergencyNum : numbers.split(",")) {
1698ab971d3c26346cfd94a37e40591318bf3b3ae4fdShaopeng Jia                // It is not possible to append additional digits to an emergency number to dial
1699ab971d3c26346cfd94a37e40591318bf3b3ae4fdShaopeng Jia                // the number in Brazil - it won't connect.
1700ab971d3c26346cfd94a37e40591318bf3b3ae4fdShaopeng Jia                if (useExactMatch || "BR".equalsIgnoreCase(defaultCountryIso)) {
1701ab971d3c26346cfd94a37e40591318bf3b3ae4fdShaopeng Jia                    if (number.equals(emergencyNum)) {
1702ab971d3c26346cfd94a37e40591318bf3b3ae4fdShaopeng Jia                        return true;
1703ab971d3c26346cfd94a37e40591318bf3b3ae4fdShaopeng Jia                    }
1704ab971d3c26346cfd94a37e40591318bf3b3ae4fdShaopeng Jia                } else {
1705ab971d3c26346cfd94a37e40591318bf3b3ae4fdShaopeng Jia                    if (number.startsWith(emergencyNum)) {
1706ab971d3c26346cfd94a37e40591318bf3b3ae4fdShaopeng Jia                        return true;
1707ab971d3c26346cfd94a37e40591318bf3b3ae4fdShaopeng Jia                    }
1708ab971d3c26346cfd94a37e40591318bf3b3ae4fdShaopeng Jia                }
1709ab971d3c26346cfd94a37e40591318bf3b3ae4fdShaopeng Jia            }
1710ab971d3c26346cfd94a37e40591318bf3b3ae4fdShaopeng Jia            // no matches found against the list!
1711ab971d3c26346cfd94a37e40591318bf3b3ae4fdShaopeng Jia            return false;
1712ab971d3c26346cfd94a37e40591318bf3b3ae4fdShaopeng Jia        }
1713ab971d3c26346cfd94a37e40591318bf3b3ae4fdShaopeng Jia
17140205537536431204b11459e9d2d2eccf3924c6cdDaisuke Miyakawa        Log.d(LOG_TAG, "System property doesn't provide any emergency numbers."
1715e69ec2253cd2e151a6a98e87d1bbf5d5cfa05bedDaisuke Miyakawa                + " Use embedded logic for determining ones.");
17160205537536431204b11459e9d2d2eccf3924c6cdDaisuke Miyakawa
1717ab971d3c26346cfd94a37e40591318bf3b3ae4fdShaopeng Jia        // No ecclist system property, so use our own list.
1718ab971d3c26346cfd94a37e40591318bf3b3ae4fdShaopeng Jia        if (defaultCountryIso != null) {
1719ab971d3c26346cfd94a37e40591318bf3b3ae4fdShaopeng Jia            ShortNumberUtil util = new ShortNumberUtil();
1720ab971d3c26346cfd94a37e40591318bf3b3ae4fdShaopeng Jia            if (useExactMatch) {
1721ab971d3c26346cfd94a37e40591318bf3b3ae4fdShaopeng Jia                return util.isEmergencyNumber(number, defaultCountryIso);
1722ab971d3c26346cfd94a37e40591318bf3b3ae4fdShaopeng Jia            } else {
1723ab971d3c26346cfd94a37e40591318bf3b3ae4fdShaopeng Jia                return util.connectsToEmergencyNumber(number, defaultCountryIso);
1724ab971d3c26346cfd94a37e40591318bf3b3ae4fdShaopeng Jia            }
1725ab971d3c26346cfd94a37e40591318bf3b3ae4fdShaopeng Jia        } else {
1726ab971d3c26346cfd94a37e40591318bf3b3ae4fdShaopeng Jia            if (useExactMatch) {
1727ab971d3c26346cfd94a37e40591318bf3b3ae4fdShaopeng Jia                return (number.equals("112") || number.equals("911"));
1728ab971d3c26346cfd94a37e40591318bf3b3ae4fdShaopeng Jia            } else {
1729ab971d3c26346cfd94a37e40591318bf3b3ae4fdShaopeng Jia                return (number.startsWith("112") || number.startsWith("911"));
17301a811695f9ae2ac806a64fd3b6c440c83262dc52David Brown            }
17319683f990a282776ac8a588a9d5e1a73b61f43dcfShaopeng Jia        }
17329683f990a282776ac8a588a9d5e1a73b61f43dcfShaopeng Jia    }
17339683f990a282776ac8a588a9d5e1a73b61f43dcfShaopeng Jia
17349683f990a282776ac8a588a9d5e1a73b61f43dcfShaopeng Jia    /**
17356b7c3f8a1cd8b638defc28a3249746e99b8039aeShaopeng Jia     * Checks if a given number is an emergency number for the country that the user is in. The
17366b7c3f8a1cd8b638defc28a3249746e99b8039aeShaopeng Jia     * current country is determined using the CountryDetector.
17376b7c3f8a1cd8b638defc28a3249746e99b8039aeShaopeng Jia     *
17386b7c3f8a1cd8b638defc28a3249746e99b8039aeShaopeng Jia     * @param number the number to look up.
17396b7c3f8a1cd8b638defc28a3249746e99b8039aeShaopeng Jia     * @param context the specific context which the number should be checked against
17401a811695f9ae2ac806a64fd3b6c440c83262dc52David Brown     * @return true if the specified number is an emergency number for a local country, based on the
17411a811695f9ae2ac806a64fd3b6c440c83262dc52David Brown     *              CountryDetector.
17421a811695f9ae2ac806a64fd3b6c440c83262dc52David Brown     *
17436b7c3f8a1cd8b638defc28a3249746e99b8039aeShaopeng Jia     * @see android.location.CountryDetector
17446b7c3f8a1cd8b638defc28a3249746e99b8039aeShaopeng Jia     * @hide
17456b7c3f8a1cd8b638defc28a3249746e99b8039aeShaopeng Jia     */
17466b7c3f8a1cd8b638defc28a3249746e99b8039aeShaopeng Jia    public static boolean isLocalEmergencyNumber(String number, Context context) {
17471a811695f9ae2ac806a64fd3b6c440c83262dc52David Brown        return isLocalEmergencyNumberInternal(number,
17481a811695f9ae2ac806a64fd3b6c440c83262dc52David Brown                                              context,
17491a811695f9ae2ac806a64fd3b6c440c83262dc52David Brown                                              true /* useExactMatch */);
17501a811695f9ae2ac806a64fd3b6c440c83262dc52David Brown    }
17511a811695f9ae2ac806a64fd3b6c440c83262dc52David Brown
17521a811695f9ae2ac806a64fd3b6c440c83262dc52David Brown    /**
17531a811695f9ae2ac806a64fd3b6c440c83262dc52David Brown     * Checks if a given number might *potentially* result in a call to an
17541a811695f9ae2ac806a64fd3b6c440c83262dc52David Brown     * emergency service, for the country that the user is in. The current
17551a811695f9ae2ac806a64fd3b6c440c83262dc52David Brown     * country is determined using the CountryDetector.
17561a811695f9ae2ac806a64fd3b6c440c83262dc52David Brown     *
17571a811695f9ae2ac806a64fd3b6c440c83262dc52David Brown     * Specifically, this method will return true if the specified number
17581a811695f9ae2ac806a64fd3b6c440c83262dc52David Brown     * is an emergency number in the current country, *or* if the number
17591a811695f9ae2ac806a64fd3b6c440c83262dc52David Brown     * simply starts with the same digits as any emergency number for the
17601a811695f9ae2ac806a64fd3b6c440c83262dc52David Brown     * current country.
17611a811695f9ae2ac806a64fd3b6c440c83262dc52David Brown     *
17621a811695f9ae2ac806a64fd3b6c440c83262dc52David Brown     * This method is intended for internal use by the phone app when
17631a811695f9ae2ac806a64fd3b6c440c83262dc52David Brown     * deciding whether to allow ACTION_CALL intents from 3rd party apps
17641a811695f9ae2ac806a64fd3b6c440c83262dc52David Brown     * (where we're required to *not* allow emergency calls to be placed.)
17651a811695f9ae2ac806a64fd3b6c440c83262dc52David Brown     *
17661a811695f9ae2ac806a64fd3b6c440c83262dc52David Brown     * @param number the number to look up.
17671a811695f9ae2ac806a64fd3b6c440c83262dc52David Brown     * @param context the specific context which the number should be checked against
17681a811695f9ae2ac806a64fd3b6c440c83262dc52David Brown     * @return true if the specified number is an emergency number for a local country, based on the
17691a811695f9ae2ac806a64fd3b6c440c83262dc52David Brown     *              CountryDetector.
17701a811695f9ae2ac806a64fd3b6c440c83262dc52David Brown     *
17711a811695f9ae2ac806a64fd3b6c440c83262dc52David Brown     * @see android.location.CountryDetector
17721a811695f9ae2ac806a64fd3b6c440c83262dc52David Brown     * @hide
17731a811695f9ae2ac806a64fd3b6c440c83262dc52David Brown     */
17741a811695f9ae2ac806a64fd3b6c440c83262dc52David Brown    public static boolean isPotentialLocalEmergencyNumber(String number, Context context) {
17751a811695f9ae2ac806a64fd3b6c440c83262dc52David Brown        return isLocalEmergencyNumberInternal(number,
17761a811695f9ae2ac806a64fd3b6c440c83262dc52David Brown                                              context,
17771a811695f9ae2ac806a64fd3b6c440c83262dc52David Brown                                              false /* useExactMatch */);
17781a811695f9ae2ac806a64fd3b6c440c83262dc52David Brown    }
17791a811695f9ae2ac806a64fd3b6c440c83262dc52David Brown
17801a811695f9ae2ac806a64fd3b6c440c83262dc52David Brown    /**
17811a811695f9ae2ac806a64fd3b6c440c83262dc52David Brown     * Helper function for isLocalEmergencyNumber() and
17821a811695f9ae2ac806a64fd3b6c440c83262dc52David Brown     * isPotentialLocalEmergencyNumber().
17831a811695f9ae2ac806a64fd3b6c440c83262dc52David Brown     *
17841a811695f9ae2ac806a64fd3b6c440c83262dc52David Brown     * @param number the number to look up.
17851a811695f9ae2ac806a64fd3b6c440c83262dc52David Brown     * @param context the specific context which the number should be checked against
17861a811695f9ae2ac806a64fd3b6c440c83262dc52David Brown     * @param useExactMatch if true, consider a number to be an emergency
17871a811695f9ae2ac806a64fd3b6c440c83262dc52David Brown     *           number only if it *exactly* matches a number listed in
17881a811695f9ae2ac806a64fd3b6c440c83262dc52David Brown     *           the RIL / SIM.  If false, a number is considered to be an
17891a811695f9ae2ac806a64fd3b6c440c83262dc52David Brown     *           emergency number if it simply starts with the same digits
17901a811695f9ae2ac806a64fd3b6c440c83262dc52David Brown     *           as any of the emergency numbers listed in the RIL / SIM.
17911a811695f9ae2ac806a64fd3b6c440c83262dc52David Brown     *
17921a811695f9ae2ac806a64fd3b6c440c83262dc52David Brown     * @return true if the specified number is an emergency number for a
17931a811695f9ae2ac806a64fd3b6c440c83262dc52David Brown     *              local country, based on the CountryDetector.
17941a811695f9ae2ac806a64fd3b6c440c83262dc52David Brown     *
17951a811695f9ae2ac806a64fd3b6c440c83262dc52David Brown     * @see android.location.CountryDetector
17961a811695f9ae2ac806a64fd3b6c440c83262dc52David Brown     */
17971a811695f9ae2ac806a64fd3b6c440c83262dc52David Brown    private static boolean isLocalEmergencyNumberInternal(String number,
17981a811695f9ae2ac806a64fd3b6c440c83262dc52David Brown                                                          Context context,
17991a811695f9ae2ac806a64fd3b6c440c83262dc52David Brown                                                          boolean useExactMatch) {
18006b7c3f8a1cd8b638defc28a3249746e99b8039aeShaopeng Jia        String countryIso;
18016b7c3f8a1cd8b638defc28a3249746e99b8039aeShaopeng Jia        CountryDetector detector = (CountryDetector) context.getSystemService(
18026b7c3f8a1cd8b638defc28a3249746e99b8039aeShaopeng Jia                Context.COUNTRY_DETECTOR);
18036b7c3f8a1cd8b638defc28a3249746e99b8039aeShaopeng Jia        if (detector != null) {
18046b7c3f8a1cd8b638defc28a3249746e99b8039aeShaopeng Jia            countryIso = detector.detectCountry().getCountryIso();
18056b7c3f8a1cd8b638defc28a3249746e99b8039aeShaopeng Jia        } else {
18066b7c3f8a1cd8b638defc28a3249746e99b8039aeShaopeng Jia            Locale locale = context.getResources().getConfiguration().locale;
18076b7c3f8a1cd8b638defc28a3249746e99b8039aeShaopeng Jia            countryIso = locale.getCountry();
18086b7c3f8a1cd8b638defc28a3249746e99b8039aeShaopeng Jia            Log.w(LOG_TAG, "No CountryDetector; falling back to countryIso based on locale: "
18096b7c3f8a1cd8b638defc28a3249746e99b8039aeShaopeng Jia                    + countryIso);
18106b7c3f8a1cd8b638defc28a3249746e99b8039aeShaopeng Jia        }
18111a811695f9ae2ac806a64fd3b6c440c83262dc52David Brown        return isEmergencyNumberInternal(number, countryIso, useExactMatch);
18126b7c3f8a1cd8b638defc28a3249746e99b8039aeShaopeng Jia    }
18136b7c3f8a1cd8b638defc28a3249746e99b8039aeShaopeng Jia
18146b7c3f8a1cd8b638defc28a3249746e99b8039aeShaopeng Jia    /**
181560d45f0f0320801a16db2ad038453c098e98966cNicolas Catania     * isVoiceMailNumber: checks a given number against the voicemail
181660d45f0f0320801a16db2ad038453c098e98966cNicolas Catania     *   number provided by the RIL and SIM card. The caller must have
181760d45f0f0320801a16db2ad038453c098e98966cNicolas Catania     *   the READ_PHONE_STATE credential.
181860d45f0f0320801a16db2ad038453c098e98966cNicolas Catania     *
181960d45f0f0320801a16db2ad038453c098e98966cNicolas Catania     * @param number the number to look up.
182060d45f0f0320801a16db2ad038453c098e98966cNicolas Catania     * @return true if the number is in the list of voicemail. False
182160d45f0f0320801a16db2ad038453c098e98966cNicolas Catania     * otherwise, including if the caller does not have the permission
182260d45f0f0320801a16db2ad038453c098e98966cNicolas Catania     * to read the VM number.
182360d45f0f0320801a16db2ad038453c098e98966cNicolas Catania     * @hide TODO: pending API Council approval
182460d45f0f0320801a16db2ad038453c098e98966cNicolas Catania     */
182560d45f0f0320801a16db2ad038453c098e98966cNicolas Catania    public static boolean isVoiceMailNumber(String number) {
182660d45f0f0320801a16db2ad038453c098e98966cNicolas Catania        String vmNumber;
182760d45f0f0320801a16db2ad038453c098e98966cNicolas Catania
182860d45f0f0320801a16db2ad038453c098e98966cNicolas Catania        try {
182960d45f0f0320801a16db2ad038453c098e98966cNicolas Catania            vmNumber = TelephonyManager.getDefault().getVoiceMailNumber();
183060d45f0f0320801a16db2ad038453c098e98966cNicolas Catania        } catch (SecurityException ex) {
183160d45f0f0320801a16db2ad038453c098e98966cNicolas Catania            return false;
183260d45f0f0320801a16db2ad038453c098e98966cNicolas Catania        }
183360d45f0f0320801a16db2ad038453c098e98966cNicolas Catania
183460d45f0f0320801a16db2ad038453c098e98966cNicolas Catania        // Strip the separators from the number before comparing it
183560d45f0f0320801a16db2ad038453c098e98966cNicolas Catania        // to the list.
18369e534153264138cfee383c626db92b934fafc1afTammo Spalink        number = extractNetworkPortionAlt(number);
183760d45f0f0320801a16db2ad038453c098e98966cNicolas Catania
183860d45f0f0320801a16db2ad038453c098e98966cNicolas Catania        // compare tolerates null so we need to make sure that we
183960d45f0f0320801a16db2ad038453c098e98966cNicolas Catania        // don't return true when both are null.
184060d45f0f0320801a16db2ad038453c098e98966cNicolas Catania        return !TextUtils.isEmpty(number) && compare(number, vmNumber);
184160d45f0f0320801a16db2ad038453c098e98966cNicolas Catania    }
184260d45f0f0320801a16db2ad038453c098e98966cNicolas Catania
184360d45f0f0320801a16db2ad038453c098e98966cNicolas Catania    /**
18449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Translates any alphabetic letters (i.e. [A-Za-z]) in the
18459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * specified phone number into the equivalent numeric digits,
18469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * according to the phone keypad letter mapping described in
18479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * ITU E.161 and ISO/IEC 9995-8.
18489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
18499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return the input string, with alpha letters converted to numeric
18509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *         digits using the phone keypad letter mapping.  For example,
18519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *         an input of "1-800-GOOG-411" will return "1-800-4664-411".
18529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
18539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static String convertKeypadLettersToDigits(String input) {
18549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (input == null) {
18559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return input;
18569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
18579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int len = input.length();
18589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (len == 0) {
18599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return input;
18609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
18619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
18629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        char[] out = input.toCharArray();
18639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
18649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (int i = 0; i < len; i++) {
18659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            char c = out[i];
18669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // If this char isn't in KEYPAD_MAP at all, just leave it alone.
18679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            out[i] = (char) KEYPAD_MAP.get(c, c);
18689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
18699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
18709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return new String(out);
18719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
18729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
18739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
18749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * The phone keypad letter mapping (see ITU E.161 or ISO/IEC 9995-8.)
18759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * TODO: This should come from a resource.
18769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
18779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final SparseIntArray KEYPAD_MAP = new SparseIntArray();
18789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    static {
18799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        KEYPAD_MAP.put('a', '2'); KEYPAD_MAP.put('b', '2'); KEYPAD_MAP.put('c', '2');
18809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        KEYPAD_MAP.put('A', '2'); KEYPAD_MAP.put('B', '2'); KEYPAD_MAP.put('C', '2');
18819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
18829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        KEYPAD_MAP.put('d', '3'); KEYPAD_MAP.put('e', '3'); KEYPAD_MAP.put('f', '3');
18839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        KEYPAD_MAP.put('D', '3'); KEYPAD_MAP.put('E', '3'); KEYPAD_MAP.put('F', '3');
18849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
18859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        KEYPAD_MAP.put('g', '4'); KEYPAD_MAP.put('h', '4'); KEYPAD_MAP.put('i', '4');
18869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        KEYPAD_MAP.put('G', '4'); KEYPAD_MAP.put('H', '4'); KEYPAD_MAP.put('I', '4');
18879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
18889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        KEYPAD_MAP.put('j', '5'); KEYPAD_MAP.put('k', '5'); KEYPAD_MAP.put('l', '5');
18899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        KEYPAD_MAP.put('J', '5'); KEYPAD_MAP.put('K', '5'); KEYPAD_MAP.put('L', '5');
18909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
18919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        KEYPAD_MAP.put('m', '6'); KEYPAD_MAP.put('n', '6'); KEYPAD_MAP.put('o', '6');
18929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        KEYPAD_MAP.put('M', '6'); KEYPAD_MAP.put('N', '6'); KEYPAD_MAP.put('O', '6');
18939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
18949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        KEYPAD_MAP.put('p', '7'); KEYPAD_MAP.put('q', '7'); KEYPAD_MAP.put('r', '7'); KEYPAD_MAP.put('s', '7');
18959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        KEYPAD_MAP.put('P', '7'); KEYPAD_MAP.put('Q', '7'); KEYPAD_MAP.put('R', '7'); KEYPAD_MAP.put('S', '7');
18969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
18979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        KEYPAD_MAP.put('t', '8'); KEYPAD_MAP.put('u', '8'); KEYPAD_MAP.put('v', '8');
18989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        KEYPAD_MAP.put('T', '8'); KEYPAD_MAP.put('U', '8'); KEYPAD_MAP.put('V', '8');
18999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
19009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        KEYPAD_MAP.put('w', '9'); KEYPAD_MAP.put('x', '9'); KEYPAD_MAP.put('y', '9'); KEYPAD_MAP.put('z', '9');
19019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        KEYPAD_MAP.put('W', '9'); KEYPAD_MAP.put('X', '9'); KEYPAD_MAP.put('Y', '9'); KEYPAD_MAP.put('Z', '9');
19029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
190318e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com
190418e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com    //================ Plus Code formatting =========================
190518e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com    private static final char PLUS_SIGN_CHAR = '+';
190618e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com    private static final String PLUS_SIGN_STRING = "+";
190718e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com    private static final String NANP_IDP_STRING = "011";
190818e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com    private static final int NANP_LENGTH = 10;
190918e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com
191018e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com    /**
191118e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com     * This function checks if there is a plus sign (+) in the passed-in dialing number.
191218e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com     * If there is, it processes the plus sign based on the default telephone
191318e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com     * numbering plan of the system when the phone is activated and the current
191418e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com     * telephone numbering plan of the system that the phone is camped on.
191518e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com     * Currently, we only support the case that the default and current telephone
191618e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com     * numbering plans are North American Numbering Plan(NANP).
191718e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com     *
191818e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com     * The passed-in dialStr should only contain the valid format as described below,
191918e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com     * 1) the 1st character in the dialStr should be one of the really dialable
192018e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com     *    characters listed below
192118e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com     *    ISO-LATIN characters 0-9, *, # , +
192218e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com     * 2) the dialStr should already strip out the separator characters,
192318e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com     *    every character in the dialStr should be one of the non separator characters
192418e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com     *    listed below
192518e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com     *    ISO-LATIN characters 0-9, *, # , +, WILD, WAIT, PAUSE
192618e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com     *
192718e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com     * Otherwise, this function returns the dial string passed in
192818e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com     *
19297850cdde66705152b859aafda875833acdda9653Libin Tang     * @param dialStr the original dial string
19307850cdde66705152b859aafda875833acdda9653Libin Tang     * @return the converted dial string if the current/default countries belong to NANP,
19317850cdde66705152b859aafda875833acdda9653Libin Tang     * and if there is the "+" in the original dial string. Otherwise, the original dial
19327850cdde66705152b859aafda875833acdda9653Libin Tang     * string returns.
19337850cdde66705152b859aafda875833acdda9653Libin Tang     *
193418e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com     * This API is for CDMA only
193518e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com     *
193618e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com     * @hide TODO: pending API Council approval
193718e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com     */
193818e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com    public static String cdmaCheckAndProcessPlusCode(String dialStr) {
193918e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com        if (!TextUtils.isEmpty(dialStr)) {
194018e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com            if (isReallyDialable(dialStr.charAt(0)) &&
194118e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com                isNonSeparator(dialStr)) {
19427850cdde66705152b859aafda875833acdda9653Libin Tang                String currIso = SystemProperties.get(PROPERTY_OPERATOR_ISO_COUNTRY, "");
19437850cdde66705152b859aafda875833acdda9653Libin Tang                String defaultIso = SystemProperties.get(PROPERTY_ICC_OPERATOR_ISO_COUNTRY, "");
19447850cdde66705152b859aafda875833acdda9653Libin Tang                if (!TextUtils.isEmpty(currIso) && !TextUtils.isEmpty(defaultIso)) {
19457850cdde66705152b859aafda875833acdda9653Libin Tang                    return cdmaCheckAndProcessPlusCodeByNumberFormat(dialStr,
19467850cdde66705152b859aafda875833acdda9653Libin Tang                            getFormatTypeFromCountryCode(currIso),
19477850cdde66705152b859aafda875833acdda9653Libin Tang                            getFormatTypeFromCountryCode(defaultIso));
19487850cdde66705152b859aafda875833acdda9653Libin Tang                }
194918e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com            }
195018e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com        }
195118e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com        return dialStr;
195218e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com    }
195318e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com
195418e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com    /**
195518e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com     * This function should be called from checkAndProcessPlusCode only
195618e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com     * And it is used for test purpose also.
195718e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com     *
195818e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com     * It checks the dial string by looping through the network portion,
195918e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com     * post dial portion 1, post dial porting 2, etc. If there is any
196018e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com     * plus sign, then process the plus sign.
196118e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com     * Currently, this function supports the plus sign conversion within NANP only.
196218e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com     * Specifically, it handles the plus sign in the following ways:
19637850cdde66705152b859aafda875833acdda9653Libin Tang     * 1)+1NANP,remove +, e.g.
196418e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com     *   +18475797000 is converted to 18475797000,
19657850cdde66705152b859aafda875833acdda9653Libin Tang     * 2)+NANP or +non-NANP Numbers,replace + with the current NANP IDP, e.g,
19667850cdde66705152b859aafda875833acdda9653Libin Tang     *   +8475797000 is converted to 0118475797000,
196718e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com     *   +11875767800 is converted to 01111875767800
19687850cdde66705152b859aafda875833acdda9653Libin Tang     * 3)+1NANP in post dial string(s), e.g.
19697850cdde66705152b859aafda875833acdda9653Libin Tang     *   8475797000;+18475231753 is converted to 8475797000;18475231753
19707850cdde66705152b859aafda875833acdda9653Libin Tang     *
197118e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com     *
19727850cdde66705152b859aafda875833acdda9653Libin Tang     * @param dialStr the original dial string
19737850cdde66705152b859aafda875833acdda9653Libin Tang     * @param currFormat the numbering system of the current country that the phone is camped on
19747850cdde66705152b859aafda875833acdda9653Libin Tang     * @param defaultFormat the numbering system of the country that the phone is activated on
19757850cdde66705152b859aafda875833acdda9653Libin Tang     * @return the converted dial string if the current/default countries belong to NANP,
19767850cdde66705152b859aafda875833acdda9653Libin Tang     * and if there is the "+" in the original dial string. Otherwise, the original dial
19777850cdde66705152b859aafda875833acdda9653Libin Tang     * string returns.
197818e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com     *
197918e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com     * @hide
198018e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com     */
19817850cdde66705152b859aafda875833acdda9653Libin Tang    public static String
1982145ff609de3206b585819ef974fab20cdc2d9f5eJake Hamby    cdmaCheckAndProcessPlusCodeByNumberFormat(String dialStr,int currFormat,int defaultFormat) {
198318e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com        String retStr = dialStr;
198418e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com
198518e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com        // Checks if the plus sign character is in the passed-in dial string
198618e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com        if (dialStr != null &&
198718e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com            dialStr.lastIndexOf(PLUS_SIGN_STRING) != -1) {
19887850cdde66705152b859aafda875833acdda9653Libin Tang            // Format the string based on the rules for the country the number is from,
19897850cdde66705152b859aafda875833acdda9653Libin Tang            // and the current country the phone is camped on.
1990145ff609de3206b585819ef974fab20cdc2d9f5eJake Hamby            if ((currFormat == defaultFormat) && (currFormat == FORMAT_NANP)) {
19917850cdde66705152b859aafda875833acdda9653Libin Tang                // Handle case where default and current telephone numbering plans are NANP.
19927850cdde66705152b859aafda875833acdda9653Libin Tang                String postDialStr = null;
19937850cdde66705152b859aafda875833acdda9653Libin Tang                String tempDialStr = dialStr;
19947850cdde66705152b859aafda875833acdda9653Libin Tang
19957850cdde66705152b859aafda875833acdda9653Libin Tang                // Sets the retStr to null since the conversion will be performed below.
19967850cdde66705152b859aafda875833acdda9653Libin Tang                retStr = null;
19977850cdde66705152b859aafda875833acdda9653Libin Tang                if (DBG) log("checkAndProcessPlusCode,dialStr=" + dialStr);
19987850cdde66705152b859aafda875833acdda9653Libin Tang                // This routine is to process the plus sign in the dial string by loop through
19997850cdde66705152b859aafda875833acdda9653Libin Tang                // the network portion, post dial portion 1, post dial portion 2... etc. if
20007850cdde66705152b859aafda875833acdda9653Libin Tang                // applied
20017850cdde66705152b859aafda875833acdda9653Libin Tang                do {
20027850cdde66705152b859aafda875833acdda9653Libin Tang                    String networkDialStr;
200318e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com                    networkDialStr = extractNetworkPortion(tempDialStr);
200418e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com                    // Handles the conversion within NANP
200518e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com                    networkDialStr = processPlusCodeWithinNanp(networkDialStr);
20067850cdde66705152b859aafda875833acdda9653Libin Tang
20077850cdde66705152b859aafda875833acdda9653Libin Tang                    // Concatenates the string that is converted from network portion
20087850cdde66705152b859aafda875833acdda9653Libin Tang                    if (!TextUtils.isEmpty(networkDialStr)) {
20097850cdde66705152b859aafda875833acdda9653Libin Tang                        if (retStr == null) {
20107850cdde66705152b859aafda875833acdda9653Libin Tang                            retStr = networkDialStr;
20117850cdde66705152b859aafda875833acdda9653Libin Tang                        } else {
20127850cdde66705152b859aafda875833acdda9653Libin Tang                            retStr = retStr.concat(networkDialStr);
20137850cdde66705152b859aafda875833acdda9653Libin Tang                        }
201418e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com                    } else {
20157850cdde66705152b859aafda875833acdda9653Libin Tang                        // This should never happen since we checked the if dialStr is null
20167850cdde66705152b859aafda875833acdda9653Libin Tang                        // and if it contains the plus sign in the beginning of this function.
20177850cdde66705152b859aafda875833acdda9653Libin Tang                        // The plus sign is part of the network portion.
20187850cdde66705152b859aafda875833acdda9653Libin Tang                        Log.e("checkAndProcessPlusCode: null newDialStr", networkDialStr);
20197850cdde66705152b859aafda875833acdda9653Libin Tang                        return dialStr;
202018e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com                    }
20217850cdde66705152b859aafda875833acdda9653Libin Tang                    postDialStr = extractPostDialPortion(tempDialStr);
20227850cdde66705152b859aafda875833acdda9653Libin Tang                    if (!TextUtils.isEmpty(postDialStr)) {
20237850cdde66705152b859aafda875833acdda9653Libin Tang                        int dialableIndex = findDialableIndexFromPostDialStr(postDialStr);
20247850cdde66705152b859aafda875833acdda9653Libin Tang
20257850cdde66705152b859aafda875833acdda9653Libin Tang                        // dialableIndex should always be greater than 0
20267850cdde66705152b859aafda875833acdda9653Libin Tang                        if (dialableIndex >= 1) {
20277850cdde66705152b859aafda875833acdda9653Libin Tang                            retStr = appendPwCharBackToOrigDialStr(dialableIndex,
20287850cdde66705152b859aafda875833acdda9653Libin Tang                                     retStr,postDialStr);
20297850cdde66705152b859aafda875833acdda9653Libin Tang                            // Skips the P/W character, extracts the dialable portion
20307850cdde66705152b859aafda875833acdda9653Libin Tang                            tempDialStr = postDialStr.substring(dialableIndex);
20317850cdde66705152b859aafda875833acdda9653Libin Tang                        } else {
20327850cdde66705152b859aafda875833acdda9653Libin Tang                            // Non-dialable character such as P/W should not be at the end of
20337850cdde66705152b859aafda875833acdda9653Libin Tang                            // the dial string after P/W processing in CdmaConnection.java
20347850cdde66705152b859aafda875833acdda9653Libin Tang                            // Set the postDialStr to "" to break out of the loop
20357850cdde66705152b859aafda875833acdda9653Libin Tang                            if (dialableIndex < 0) {
20367850cdde66705152b859aafda875833acdda9653Libin Tang                                postDialStr = "";
20377850cdde66705152b859aafda875833acdda9653Libin Tang                            }
20387850cdde66705152b859aafda875833acdda9653Libin Tang                            Log.e("wrong postDialStr=", postDialStr);
203918e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com                        }
204018e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com                    }
20417850cdde66705152b859aafda875833acdda9653Libin Tang                    if (DBG) log("checkAndProcessPlusCode,postDialStr=" + postDialStr);
20427850cdde66705152b859aafda875833acdda9653Libin Tang                } while (!TextUtils.isEmpty(postDialStr) && !TextUtils.isEmpty(tempDialStr));
20437850cdde66705152b859aafda875833acdda9653Libin Tang            } else {
20447850cdde66705152b859aafda875833acdda9653Libin Tang                // TODO: Support NANP international conversion and other telephone numbering plans.
20457850cdde66705152b859aafda875833acdda9653Libin Tang                // Currently the phone is never used in non-NANP system, so return the original
20467850cdde66705152b859aafda875833acdda9653Libin Tang                // dial string.
20477850cdde66705152b859aafda875833acdda9653Libin Tang                Log.e("checkAndProcessPlusCode:non-NANP not supported", dialStr);
20487850cdde66705152b859aafda875833acdda9653Libin Tang            }
204918e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com        }
205018e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com        return retStr;
205118e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com     }
205218e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com
205318e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com    // This function gets the default international dialing prefix
205418e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com    private static String getDefaultIdp( ) {
205518e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com        String ps = null;
205618e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com        SystemProperties.get(PROPERTY_IDP_STRING, ps);
205718e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com        if (TextUtils.isEmpty(ps)) {
205818e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com            ps = NANP_IDP_STRING;
205918e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com        }
206018e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com        return ps;
206118e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com    }
206218e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com
206318e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com    private static boolean isTwoToNine (char c) {
206418e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com        if (c >= '2' && c <= '9') {
206518e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com            return true;
206618e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com        } else {
206718e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com            return false;
206818e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com        }
206918e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com    }
207018e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com
20717850cdde66705152b859aafda875833acdda9653Libin Tang    private static int getFormatTypeFromCountryCode (String country) {
20727850cdde66705152b859aafda875833acdda9653Libin Tang        // Check for the NANP countries
20737850cdde66705152b859aafda875833acdda9653Libin Tang        int length = NANP_COUNTRIES.length;
20747850cdde66705152b859aafda875833acdda9653Libin Tang        for (int i = 0; i < length; i++) {
20757850cdde66705152b859aafda875833acdda9653Libin Tang            if (NANP_COUNTRIES[i].compareToIgnoreCase(country) == 0) {
20767850cdde66705152b859aafda875833acdda9653Libin Tang                return FORMAT_NANP;
20777850cdde66705152b859aafda875833acdda9653Libin Tang            }
20787850cdde66705152b859aafda875833acdda9653Libin Tang        }
20797850cdde66705152b859aafda875833acdda9653Libin Tang        if ("jp".compareToIgnoreCase(country) == 0) {
20807850cdde66705152b859aafda875833acdda9653Libin Tang            return FORMAT_JAPAN;
20817850cdde66705152b859aafda875833acdda9653Libin Tang        }
20827850cdde66705152b859aafda875833acdda9653Libin Tang        return FORMAT_UNKNOWN;
20837850cdde66705152b859aafda875833acdda9653Libin Tang    }
20847850cdde66705152b859aafda875833acdda9653Libin Tang
208518e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com    /**
208618e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com     * This function checks if the passed in string conforms to the NANP format
208718e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com     * i.e. NXX-NXX-XXXX, N is any digit 2-9 and X is any digit 0-9
208818e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com     */
208918e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com    private static boolean isNanp (String dialStr) {
209018e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com        boolean retVal = false;
209118e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com        if (dialStr != null) {
209218e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com            if (dialStr.length() == NANP_LENGTH) {
209318e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com                if (isTwoToNine(dialStr.charAt(0)) &&
209418e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com                    isTwoToNine(dialStr.charAt(3))) {
209518e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com                    retVal = true;
209618e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com                    for (int i=1; i<NANP_LENGTH; i++ ) {
209718e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com                        char c=dialStr.charAt(i);
209818e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com                        if (!PhoneNumberUtils.isISODigit(c)) {
209918e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com                            retVal = false;
210018e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com                            break;
210118e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com                        }
210218e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com                    }
210318e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com                }
210418e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com            }
210518e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com        } else {
210618e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com            Log.e("isNanp: null dialStr passed in", dialStr);
210718e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com        }
210818e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com        return retVal;
210918e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com    }
211018e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com
211118e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com   /**
211218e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com    * This function checks if the passed in string conforms to 1-NANP format
211318e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com    */
211418e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com    private static boolean isOneNanp(String dialStr) {
211518e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com        boolean retVal = false;
211618e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com        if (dialStr != null) {
211718e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com            String newDialStr = dialStr.substring(1);
211818e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com            if ((dialStr.charAt(0) == '1') && isNanp(newDialStr)) {
211918e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com                retVal = true;
212018e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com            }
212118e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com        } else {
212218e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com            Log.e("isOneNanp: null dialStr passed in", dialStr);
212318e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com        }
212418e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com        return retVal;
212518e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com    }
212618e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com
212718e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com    /**
2128d07833f54b6e8e361b666ae16efa15fdf60159deDavid Brown     * Determines if the specified number is actually a URI
2129d07833f54b6e8e361b666ae16efa15fdf60159deDavid Brown     * (i.e. a SIP address) rather than a regular PSTN phone number,
2130d07833f54b6e8e361b666ae16efa15fdf60159deDavid Brown     * based on whether or not the number contains an "@" character.
2131d07833f54b6e8e361b666ae16efa15fdf60159deDavid Brown     *
2132c159c84699d4b739a14cdfb22c5807f419e1754fJohn Wang     * @hide
2133c159c84699d4b739a14cdfb22c5807f419e1754fJohn Wang     * @param number
2134c159c84699d4b739a14cdfb22c5807f419e1754fJohn Wang     * @return true if number contains @
2135c159c84699d4b739a14cdfb22c5807f419e1754fJohn Wang     */
2136c159c84699d4b739a14cdfb22c5807f419e1754fJohn Wang    public static boolean isUriNumber(String number) {
2137d07833f54b6e8e361b666ae16efa15fdf60159deDavid Brown        // Note we allow either "@" or "%40" to indicate a URI, in case
2138d07833f54b6e8e361b666ae16efa15fdf60159deDavid Brown        // the passed-in string is URI-escaped.  (Neither "@" nor "%40"
2139d07833f54b6e8e361b666ae16efa15fdf60159deDavid Brown        // will ever be found in a legal PSTN number.)
2140d07833f54b6e8e361b666ae16efa15fdf60159deDavid Brown        return number != null && (number.contains("@") || number.contains("%40"));
2141c159c84699d4b739a14cdfb22c5807f419e1754fJohn Wang    }
2142c159c84699d4b739a14cdfb22c5807f419e1754fJohn Wang
2143c159c84699d4b739a14cdfb22c5807f419e1754fJohn Wang    /**
2144158f116eb7fdc23a12d6822d34a549f33605bc8cDavid Brown     * @return the "username" part of the specified SIP address,
2145158f116eb7fdc23a12d6822d34a549f33605bc8cDavid Brown     *         i.e. the part before the "@" character (or "%40").
2146158f116eb7fdc23a12d6822d34a549f33605bc8cDavid Brown     *
2147158f116eb7fdc23a12d6822d34a549f33605bc8cDavid Brown     * @param number SIP address of the form "username@domainname"
2148158f116eb7fdc23a12d6822d34a549f33605bc8cDavid Brown     *               (or the URI-escaped equivalent "username%40domainname")
2149158f116eb7fdc23a12d6822d34a549f33605bc8cDavid Brown     * @see isUriNumber
2150158f116eb7fdc23a12d6822d34a549f33605bc8cDavid Brown     *
2151158f116eb7fdc23a12d6822d34a549f33605bc8cDavid Brown     * @hide
2152158f116eb7fdc23a12d6822d34a549f33605bc8cDavid Brown     */
2153158f116eb7fdc23a12d6822d34a549f33605bc8cDavid Brown    public static String getUsernameFromUriNumber(String number) {
2154158f116eb7fdc23a12d6822d34a549f33605bc8cDavid Brown        // The delimiter between username and domain name can be
2155158f116eb7fdc23a12d6822d34a549f33605bc8cDavid Brown        // either "@" or "%40" (the URI-escaped equivalent.)
2156158f116eb7fdc23a12d6822d34a549f33605bc8cDavid Brown        int delimiterIndex = number.indexOf('@');
2157158f116eb7fdc23a12d6822d34a549f33605bc8cDavid Brown        if (delimiterIndex < 0) {
2158158f116eb7fdc23a12d6822d34a549f33605bc8cDavid Brown            delimiterIndex = number.indexOf("%40");
2159158f116eb7fdc23a12d6822d34a549f33605bc8cDavid Brown        }
2160158f116eb7fdc23a12d6822d34a549f33605bc8cDavid Brown        if (delimiterIndex < 0) {
2161158f116eb7fdc23a12d6822d34a549f33605bc8cDavid Brown            Log.w(LOG_TAG,
2162158f116eb7fdc23a12d6822d34a549f33605bc8cDavid Brown                  "getUsernameFromUriNumber: no delimiter found in SIP addr '" + number + "'");
2163158f116eb7fdc23a12d6822d34a549f33605bc8cDavid Brown            delimiterIndex = number.length();
2164158f116eb7fdc23a12d6822d34a549f33605bc8cDavid Brown        }
2165158f116eb7fdc23a12d6822d34a549f33605bc8cDavid Brown        return number.substring(0, delimiterIndex);
2166158f116eb7fdc23a12d6822d34a549f33605bc8cDavid Brown    }
2167158f116eb7fdc23a12d6822d34a549f33605bc8cDavid Brown
2168158f116eb7fdc23a12d6822d34a549f33605bc8cDavid Brown    /**
216918e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com     * This function handles the plus code conversion within NANP CDMA network
217018e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com     * If the number format is
21717850cdde66705152b859aafda875833acdda9653Libin Tang     * 1)+1NANP,remove +,
21727850cdde66705152b859aafda875833acdda9653Libin Tang     * 2)other than +1NANP, any + numbers,replace + with the current IDP
217318e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com     */
217418e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com    private static String processPlusCodeWithinNanp(String networkDialStr) {
217518e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com        String retStr = networkDialStr;
217618e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com
217718e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com        if (DBG) log("processPlusCodeWithinNanp,networkDialStr=" + networkDialStr);
217818e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com        // If there is a plus sign at the beginning of the dial string,
217918e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com        // Convert the plus sign to the default IDP since it's an international number
21807ae17760462e4c16ef0ea4289612c5950258d5daKenny Root        if (networkDialStr != null &&
218118e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com            networkDialStr.charAt(0) == PLUS_SIGN_CHAR &&
218218e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com            networkDialStr.length() > 1) {
218318e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com            String newStr = networkDialStr.substring(1);
21847850cdde66705152b859aafda875833acdda9653Libin Tang            if (isOneNanp(newStr)) {
218518e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com                // Remove the leading plus sign
218618e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com                retStr = newStr;
218718e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com             } else {
218818e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com                 String idpStr = getDefaultIdp();
218918e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com                 // Replaces the plus sign with the default IDP
219018e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com                 retStr = networkDialStr.replaceFirst("[+]", idpStr);
219118e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com            }
219218e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com        }
219318e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com        if (DBG) log("processPlusCodeWithinNanp,retStr=" + retStr);
219418e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com        return retStr;
219518e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com    }
219618e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com
219718e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com    // This function finds the index of the dialable character(s)
219818e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com    // in the post dial string
219918e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com    private static int findDialableIndexFromPostDialStr(String postDialStr) {
220018e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com        for (int index = 0;index < postDialStr.length();index++) {
220118e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com             char c = postDialStr.charAt(index);
220218e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com             if (isReallyDialable(c)) {
220318e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com                return index;
220418e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com             }
220518e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com        }
220618e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com        return -1;
220718e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com    }
220818e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com
2209145ff609de3206b585819ef974fab20cdc2d9f5eJake Hamby    // This function appends the non-dialable P/W character to the original
221018e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com    // dial string based on the dialable index passed in
221118e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com    private static String
221218e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com    appendPwCharBackToOrigDialStr(int dialableIndex,String origStr, String dialStr) {
221318e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com        String retStr;
221418e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com
221518e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com        // There is only 1 P/W character before the dialable characters
221618e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com        if (dialableIndex == 1) {
221718e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com            StringBuilder ret = new StringBuilder(origStr);
221818e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com            ret = ret.append(dialStr.charAt(0));
221918e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com            retStr = ret.toString();
222018e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com        } else {
222118e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com            // It means more than 1 P/W characters in the post dial string,
222218e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com            // appends to retStr
222318e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com            String nonDigitStr = dialStr.substring(0,dialableIndex);
222418e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com            retStr = origStr.concat(nonDigitStr);
222518e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com        }
222618e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com        return retStr;
222718e7b98c1c7e3cf340e39e93be67b777e7036cc4Tang@Motorola.com    }
22289a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa
2229145ff609de3206b585819ef974fab20cdc2d9f5eJake Hamby    //===== Beginning of utility methods used in compareLoosely() =====
22309a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa
22319a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa    /**
22329a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa     * Phone numbers are stored in "lookup" form in the database
22339a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa     * as reversed strings to allow for caller ID lookup
22349a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa     *
22359a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa     * This method takes a phone number and makes a valid SQL "LIKE"
22369a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa     * string that will match the lookup form
22379a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa     *
22389a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa     */
22399a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa    /** all of a up to len must be an international prefix or
22409a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa     *  separators/non-dialing digits
22419a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa     */
22429a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa    private static boolean
22439a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa    matchIntlPrefix(String a, int len) {
22449a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa        /* '([^0-9*#+pwn]\+[^0-9*#+pwn] | [^0-9*#+pwn]0(0|11)[^0-9*#+pwn] )$' */
22459a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa        /*        0       1                           2 3 45               */
22469a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa
22479a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa        int state = 0;
22489a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa        for (int i = 0 ; i < len ; i++) {
22499a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa            char c = a.charAt(i);
22509a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa
22519a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa            switch (state) {
22529a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                case 0:
22539a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                    if      (c == '+') state = 1;
22549a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                    else if (c == '0') state = 2;
22559a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                    else if (isNonSeparator(c)) return false;
22569a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                break;
22579a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa
22589a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                case 2:
22599a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                    if      (c == '0') state = 3;
22609a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                    else if (c == '1') state = 4;
22619a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                    else if (isNonSeparator(c)) return false;
22629a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                break;
22639a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa
22649a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                case 4:
22659a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                    if      (c == '1') state = 5;
22669a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                    else if (isNonSeparator(c)) return false;
22679a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                break;
22689a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa
22699a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                default:
22709a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                    if (isNonSeparator(c)) return false;
22719a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                break;
22729a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa
22739a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa            }
22749a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa        }
22759a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa
22769a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa        return state == 1 || state == 3 || state == 5;
22779a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa    }
22789a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa
22799a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa    /** all of 'a' up to len must be a (+|00|011)country code)
22809a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa     *  We're fast and loose with the country code. Any \d{1,3} matches */
22819a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa    private static boolean
22829a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa    matchIntlPrefixAndCC(String a, int len) {
22839a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa        /*  [^0-9*#+pwn]*(\+|0(0|11)\d\d?\d? [^0-9*#+pwn] $ */
22849a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa        /*      0          1 2 3 45  6 7  8                 */
22859a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa
22869a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa        int state = 0;
22879a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa        for (int i = 0 ; i < len ; i++ ) {
22889a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa            char c = a.charAt(i);
22899a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa
22909a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa            switch (state) {
22919a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                case 0:
22929a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                    if      (c == '+') state = 1;
22939a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                    else if (c == '0') state = 2;
22949a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                    else if (isNonSeparator(c)) return false;
22959a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                break;
22969a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa
22979a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                case 2:
22989a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                    if      (c == '0') state = 3;
22999a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                    else if (c == '1') state = 4;
23009a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                    else if (isNonSeparator(c)) return false;
23019a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                break;
23029a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa
23039a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                case 4:
23049a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                    if      (c == '1') state = 5;
23059a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                    else if (isNonSeparator(c)) return false;
23069a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                break;
23079a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa
23089a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                case 1:
23099a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                case 3:
23109a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                case 5:
23119a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                    if      (isISODigit(c)) state = 6;
23129a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                    else if (isNonSeparator(c)) return false;
23139a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                break;
23149a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa
23159a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                case 6:
23169a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                case 7:
23179a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                    if      (isISODigit(c)) state++;
23189a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                    else if (isNonSeparator(c)) return false;
23199a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                break;
23209a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa
23219a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                default:
23229a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                    if (isNonSeparator(c)) return false;
23239a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa            }
23249a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa        }
23259a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa
23269a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa        return state == 6 || state == 7 || state == 8;
23279a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa    }
23289a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa
23299a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa    /** all of 'a' up to len must match non-US trunk prefix ('0') */
23309a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa    private static boolean
23319a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa    matchTrunkPrefix(String a, int len) {
23329a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa        boolean found;
23339a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa
23349a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa        found = false;
23359a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa
23369a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa        for (int i = 0 ; i < len ; i++) {
23379a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa            char c = a.charAt(i);
23389a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa
23399a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa            if (c == '0' && !found) {
23409a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                found = true;
23419a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa            } else if (isNonSeparator(c)) {
23429a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                return false;
23439a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa            }
23449a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa        }
23459a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa
23469a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa        return found;
23479a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa    }
23489a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa
23499a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa    //===== End of utility methods used only in compareLoosely() =====
23509a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa
2351145ff609de3206b585819ef974fab20cdc2d9f5eJake Hamby    //===== Beginning of utility methods used only in compareStrictly() ====
23529a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa
23539a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa    /*
23549a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa     * If true, the number is country calling code.
23559a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa     */
2356145ff609de3206b585819ef974fab20cdc2d9f5eJake Hamby    private static final boolean COUNTRY_CALLING_CALL[] = {
23579a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa        true, true, false, false, false, false, false, true, false, false,
23589a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa        false, false, false, false, false, false, false, false, false, false,
23599a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa        true, false, false, false, false, false, false, true, true, false,
23609a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa        true, true, true, true, true, false, true, false, false, true,
23619a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa        true, false, false, true, true, true, true, true, true, true,
23629a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa        false, true, true, true, true, true, true, true, true, false,
23639a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa        true, true, true, true, true, true, true, false, false, false,
23649a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa        false, false, false, false, false, false, false, false, false, false,
23659a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa        false, true, true, true, true, false, true, false, false, true,
23669a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa        true, true, true, true, true, true, false, false, true, false,
23679a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa    };
2368145ff609de3206b585819ef974fab20cdc2d9f5eJake Hamby    private static final int CCC_LENGTH = COUNTRY_CALLING_CALL.length;
23699a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa
23709a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa    /**
23719a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa     * @return true when input is valid Country Calling Code.
23729a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa     */
23739a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa    private static boolean isCountryCallingCode(int countryCallingCodeCandidate) {
23749a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa        return countryCallingCodeCandidate > 0 && countryCallingCodeCandidate < CCC_LENGTH &&
2375145ff609de3206b585819ef974fab20cdc2d9f5eJake Hamby                COUNTRY_CALLING_CALL[countryCallingCodeCandidate];
23769a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa    }
23779a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa
23789a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa    /**
2379145ff609de3206b585819ef974fab20cdc2d9f5eJake Hamby     * Returns integer corresponding to the input if input "ch" is
23809a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa     * ISO-LATIN characters 0-9.
23819a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa     * Returns -1 otherwise
23829a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa     */
23839a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa    private static int tryGetISODigit(char ch) {
23849a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa        if ('0' <= ch && ch <= '9') {
23859a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa            return ch - '0';
23869a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa        } else {
23879a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa            return -1;
23889a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa        }
23899a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa    }
23909a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa
23919a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa    private static class CountryCallingCodeAndNewIndex {
23929a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa        public final int countryCallingCode;
23939a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa        public final int newIndex;
23949a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa        public CountryCallingCodeAndNewIndex(int countryCode, int newIndex) {
23959a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa            this.countryCallingCode = countryCode;
23969a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa            this.newIndex = newIndex;
23979a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa        }
23989a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa    }
23999a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa
24009a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa    /*
24019a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa     * Note that this function does not strictly care the country calling code with
24029a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa     * 3 length (like Morocco: +212), assuming it is enough to use the first two
24039a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa     * digit to compare two phone numbers.
24049a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa     */
24059a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa    private static CountryCallingCodeAndNewIndex tryGetCountryCallingCodeAndNewIndex(
24069a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa        String str, boolean acceptThailandCase) {
24079a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa        // Rough regexp:
24089a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa        //  ^[^0-9*#+]*((\+|0(0|11)\d\d?|166) [^0-9*#+] $
24099a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa        //         0        1 2 3 45  6 7  89
24109a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa        //
24119a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa        // In all the states, this function ignores separator characters.
24129a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa        // "166" is the special case for the call from Thailand to the US. Uguu!
24139a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa        int state = 0;
24149a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa        int ccc = 0;
24159a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa        final int length = str.length();
24169a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa        for (int i = 0 ; i < length ; i++ ) {
24179a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa            char ch = str.charAt(i);
24189a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa            switch (state) {
24199a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                case 0:
24209a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                    if      (ch == '+') state = 1;
24219a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                    else if (ch == '0') state = 2;
24229a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                    else if (ch == '1') {
24239a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                        if (acceptThailandCase) {
24249a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                            state = 8;
24259a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                        } else {
24269a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                            return null;
24279a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                        }
24289a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                    } else if (isDialable(ch)) {
24299a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                        return null;
24309a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                    }
24319a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                break;
24329a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa
24339a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                case 2:
24349a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                    if      (ch == '0') state = 3;
24359a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                    else if (ch == '1') state = 4;
24369a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                    else if (isDialable(ch)) {
24379a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                        return null;
24389a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                    }
24399a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                break;
24409a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa
24419a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                case 4:
24429a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                    if      (ch == '1') state = 5;
24439a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                    else if (isDialable(ch)) {
24449a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                        return null;
24459a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                    }
24469a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                break;
24479a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa
24489a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                case 1:
24499a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                case 3:
24509a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                case 5:
24519a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                case 6:
24529a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                case 7:
24539a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                    {
24549a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                        int ret = tryGetISODigit(ch);
24559a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                        if (ret > 0) {
24569a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                            ccc = ccc * 10 + ret;
24579a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                            if (ccc >= 100 || isCountryCallingCode(ccc)) {
24589a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                                return new CountryCallingCodeAndNewIndex(ccc, i + 1);
24599a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                            }
24609a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                            if (state == 1 || state == 3 || state == 5) {
24619a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                                state = 6;
24629a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                            } else {
24639a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                                state++;
24649a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                            }
24659a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                        } else if (isDialable(ch)) {
24669a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                            return null;
24679a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                        }
24689a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                    }
24699a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                    break;
24709a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                case 8:
24719a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                    if (ch == '6') state = 9;
24729a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                    else if (isDialable(ch)) {
24739a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                        return null;
24749a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                    }
24759a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                    break;
24769a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                case 9:
24779a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                    if (ch == '6') {
24789a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                        return new CountryCallingCodeAndNewIndex(66, i + 1);
24799a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                    } else {
24809a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                        return null;
24819a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                    }
24829a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                default:
24839a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                    return null;
24849a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa            }
24859a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa        }
24869a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa
24879a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa        return null;
24889a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa    }
24899a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa
24909a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa    /**
24919a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa     * Currently this function simply ignore the first digit assuming it is
24929a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa     * trunk prefix. Actually trunk prefix is different in each country.
24939a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa     *
24949a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa     * e.g.
24959a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa     * "+79161234567" equals "89161234567" (Russian trunk digit is 8)
24969a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa     * "+33123456789" equals "0123456789" (French trunk digit is 0)
24979a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa     *
24989a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa     */
24999a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa    private static int tryGetTrunkPrefixOmittedIndex(String str, int currentIndex) {
25009a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa        int length = str.length();
25019a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa        for (int i = currentIndex ; i < length ; i++) {
25029a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa            final char ch = str.charAt(i);
25039a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa            if (tryGetISODigit(ch) >= 0) {
25049a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                return i + 1;
25059a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa            } else if (isDialable(ch)) {
25069a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                return -1;
25079a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa            }
25089a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa        }
25099a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa        return -1;
25109a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa    }
25119a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa
25129a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa    /**
25139a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa     * Return true if the prefix of "str" is "ignorable". Here, "ignorable" means
2514145ff609de3206b585819ef974fab20cdc2d9f5eJake Hamby     * that "str" has only one digit and separator characters. The one digit is
25159a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa     * assumed to be trunk prefix.
25169a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa     */
25179a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa    private static boolean checkPrefixIsIgnorable(final String str,
25189a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa            int forwardIndex, int backwardIndex) {
25199a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa        boolean trunk_prefix_was_read = false;
25209a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa        while (backwardIndex >= forwardIndex) {
25219a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa            if (tryGetISODigit(str.charAt(backwardIndex)) >= 0) {
25229a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                if (trunk_prefix_was_read) {
25239a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                    // More than one digit appeared, meaning that "a" and "b"
25249a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                    // is different.
25259a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                    return false;
25269a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                } else {
25279a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                    // Ignore just one digit, assuming it is trunk prefix.
25289a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                    trunk_prefix_was_read = true;
25299a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                }
25309a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa            } else if (isDialable(str.charAt(backwardIndex))) {
25319a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                // Trunk prefix is a digit, not "*", "#"...
25329a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa                return false;
25339a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa            }
25349a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa            backwardIndex--;
25359a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa        }
25369a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa
25379a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa        return true;
25389a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa    }
25399a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa
25409a24bc563f28d8489c7178b93ff05f02e8b8a893Daisuke Miyakawa    //==== End of utility methods used only in compareStrictly() =====
25419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
2542