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