PhoneNumberUtil.java revision 77aadd284847681bd66af639636c2fa43e418c2b
11524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia/* 2ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia * Copyright (C) 2009 The Libphonenumber Authors 31524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * 41524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * Licensed under the Apache License, Version 2.0 (the "License"); 51524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * you may not use this file except in compliance with the License. 61524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * You may obtain a copy of the License at 71524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * 81524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * http://www.apache.org/licenses/LICENSE-2.0 91524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * 101524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * Unless required by applicable law or agreed to in writing, software 111524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * distributed under the License is distributed on an "AS IS" BASIS, 121524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 131524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * See the License for the specific language governing permissions and 141524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * limitations under the License. 151524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia */ 161524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia 1793f6965c2c041ac707bf1b3bcf5a3f60e452f421Shaopeng Jiapackage com.android.i18n.phonenumbers; 181524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia 1993f6965c2c041ac707bf1b3bcf5a3f60e452f421Shaopeng Jiaimport com.android.i18n.phonenumbers.Phonemetadata.NumberFormat; 2093f6965c2c041ac707bf1b3bcf5a3f60e452f421Shaopeng Jiaimport com.android.i18n.phonenumbers.Phonemetadata.PhoneMetadata; 2193f6965c2c041ac707bf1b3bcf5a3f60e452f421Shaopeng Jiaimport com.android.i18n.phonenumbers.Phonemetadata.PhoneMetadataCollection; 2293f6965c2c041ac707bf1b3bcf5a3f60e452f421Shaopeng Jiaimport com.android.i18n.phonenumbers.Phonemetadata.PhoneNumberDesc; 2393f6965c2c041ac707bf1b3bcf5a3f60e452f421Shaopeng Jiaimport com.android.i18n.phonenumbers.Phonenumber.PhoneNumber; 2493f6965c2c041ac707bf1b3bcf5a3f60e452f421Shaopeng Jiaimport com.android.i18n.phonenumbers.Phonenumber.PhoneNumber.CountryCodeSource; 251524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia 261524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jiaimport java.io.IOException; 2752699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jiaimport java.io.InputStream; 285724d94f83d41d33bfdf9fdbaddbfebb1a0e77f0Shaopeng Jiaimport java.io.ObjectInputStream; 294b7846722d1a5acb0577b07e98324f744f5e7942Shaopeng Jiaimport java.util.ArrayList; 301524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jiaimport java.util.Arrays; 311524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jiaimport java.util.Collections; 321524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jiaimport java.util.HashMap; 331524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jiaimport java.util.HashSet; 3452699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jiaimport java.util.Iterator; 351524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jiaimport java.util.List; 361524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jiaimport java.util.Map; 371524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jiaimport java.util.Set; 381524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jiaimport java.util.logging.Level; 391524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jiaimport java.util.logging.Logger; 401524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jiaimport java.util.regex.Matcher; 411524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jiaimport java.util.regex.Pattern; 421524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia 431524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia/** 441524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * Utility for international phone numbers. Functionality includes formatting, parsing and 451524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * validation. 461524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * 47372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * <p>If you use this library, and want to be notified about important changes, please sign up to 48372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * our <a href="http://groups.google.com/group/libphonenumber-discuss/about">mailing list</a>. 49372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * 50d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia * NOTE: A lot of methods in this class require Region Code strings. These must be provided using 51d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia * ISO 3166-1 two-letter country-code format. These should be in upper-case. The list of the codes 52bf5d9756fe9b13f5b2e0696c62949cea77396687Shaopeng Jia * can be found here: 53bf5d9756fe9b13f5b2e0696c62949cea77396687Shaopeng Jia * http://www.iso.org/iso/country_codes/iso_3166_code_lists/country_names_and_code_elements.htm 54d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia * 551524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * @author Shaopeng Jia 561524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * @author Lara Rennie 571524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia */ 581524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jiapublic class PhoneNumberUtil { 5974aa862e30b4d1b2722e90b1a8684274441a7541Shaopeng Jia /** Flags to use when compiling regular expressions for phone numbers. */ 6074aa862e30b4d1b2722e90b1a8684274441a7541Shaopeng Jia static final int REGEX_FLAGS = Pattern.UNICODE_CASE | Pattern.CASE_INSENSITIVE; 617900ea273b8c33b3c6f70d7dd559127938d0fc3dShaopeng Jia // The minimum and maximum length of the national significant number. 62bf5d9756fe9b13f5b2e0696c62949cea77396687Shaopeng Jia private static final int MIN_LENGTH_FOR_NSN = 2; 63ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia // The ITU says the maximum length should be 15, but we have found longer numbers in Germany. 64ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia static final int MAX_LENGTH_FOR_NSN = 16; 65372bff8dd464574d36737d47e495cad14346653cShaopeng Jia // The maximum length of the country calling code. 6674aa862e30b4d1b2722e90b1a8684274441a7541Shaopeng Jia static final int MAX_LENGTH_COUNTRY_CODE = 3; 67b0e21c22b1ca6b9aeb1426924cdf42a221c3d416Shaopeng Jia // We don't allow input strings for parsing to be longer than 250 chars. This prevents malicious 68b0e21c22b1ca6b9aeb1426924cdf42a221c3d416Shaopeng Jia // input from overflowing the regular-expression engine. 69b0e21c22b1ca6b9aeb1426924cdf42a221c3d416Shaopeng Jia private static final int MAX_INPUT_STRING_LENGTH = 250; 70b2697412130f6d087dde01fb1a978f7e5840a5faShaopeng Jia static final String META_DATA_FILE_PREFIX = 718a26ae2f2ce661b8d90c93eb62899abe8df408adShaopeng Jia "/com/android/i18n/phonenumbers/data/PhoneNumberMetadataProto"; 72fa42140081949568565af7dc8c22f0600ad90a8aShaopeng Jia private String currentFilePrefix = META_DATA_FILE_PREFIX; 731524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia private static final Logger LOGGER = Logger.getLogger(PhoneNumberUtil.class.getName()); 741524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia 75372bff8dd464574d36737d47e495cad14346653cShaopeng Jia // A mapping from a country calling code to the region codes which denote the region represented 76372bff8dd464574d36737d47e495cad14346653cShaopeng Jia // by that country calling code. In the case of multiple regions sharing a calling code, such as 77372bff8dd464574d36737d47e495cad14346653cShaopeng Jia // the NANPA regions, the one indicated with "isMainCountryForCode" in the metadata should be 78372bff8dd464574d36737d47e495cad14346653cShaopeng Jia // first. 79372bff8dd464574d36737d47e495cad14346653cShaopeng Jia private Map<Integer, List<String>> countryCallingCodeToRegionCodeMap = null; 80fa42140081949568565af7dc8c22f0600ad90a8aShaopeng Jia 81372bff8dd464574d36737d47e495cad14346653cShaopeng Jia // The set of regions the library supports. 82528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia // There are roughly 240 of them and we set the initial capacity of the HashSet to 320 to offer a 83f59ccfca9dd02c4e3cf3e06b5cf184a8d0e67626Shaopeng Jia // load factor of roughly 0.75. 84528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia private final Set<String> supportedRegions = new HashSet<String>(320); 85f59ccfca9dd02c4e3cf3e06b5cf184a8d0e67626Shaopeng Jia 8674aa862e30b4d1b2722e90b1a8684274441a7541Shaopeng Jia // Region-code for the unknown region. 8774aa862e30b4d1b2722e90b1a8684274441a7541Shaopeng Jia private static final String UNKNOWN_REGION = "ZZ"; 88be1af2f8b62d5435eca48f3dd5c82e3d2c9bfa17Shaopeng Jia 89d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia // The set of regions that share country calling code 1. 90372bff8dd464574d36737d47e495cad14346653cShaopeng Jia // There are roughly 26 regions and we set the initial capacity of the HashSet to 35 to offer a 91372bff8dd464574d36737d47e495cad14346653cShaopeng Jia // load factor of roughly 0.75. 92372bff8dd464574d36737d47e495cad14346653cShaopeng Jia private final Set<String> nanpaRegions = new HashSet<String>(35); 931524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia private static final int NANPA_COUNTRY_CODE = 1; 941524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia 95ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia // The prefix that needs to be inserted in front of a Colombian landline number when dialed from 96ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia // a mobile phone in Colombia. 97ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia private static final String COLOMBIA_MOBILE_TO_FIXED_LINE_PREFIX = "3"; 98ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia 991524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia // The PLUS_SIGN signifies the international prefix. 1001524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia static final char PLUS_SIGN = '+'; 1011524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia 102cc0ae7326023c5da91dd9a84035c3dc3f6cc372fShaopeng Jia private static final char STAR_SIGN = '*'; 103cc0ae7326023c5da91dd9a84035c3dc3f6cc372fShaopeng Jia 104372bff8dd464574d36737d47e495cad14346653cShaopeng Jia private static final String RFC3966_EXTN_PREFIX = ";ext="; 105b210e301245cb5dc90aa3142f378632bd41cb172Shaopeng Jia private static final String RFC3966_PREFIX = "tel:"; 106bf5d9756fe9b13f5b2e0696c62949cea77396687Shaopeng Jia private static final String RFC3966_PHONE_CONTEXT = ";phone-context="; 107bf5d9756fe9b13f5b2e0696c62949cea77396687Shaopeng Jia private static final String RFC3966_ISDN_SUBADDRESS = ";isub="; 108372bff8dd464574d36737d47e495cad14346653cShaopeng Jia 10996a7214cdabf08f53f5b1a560304601c9f65e0b9Shaopeng Jia // A map that contains characters that are essential when dialling. That means any of the 110203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia // characters in this map must not be removed from a number when dialling, otherwise the call 111203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia // will not reach the intended destination. 11296a7214cdabf08f53f5b1a560304601c9f65e0b9Shaopeng Jia private static final Map<Character, Character> DIALLABLE_CHAR_MAPPINGS; 11396a7214cdabf08f53f5b1a560304601c9f65e0b9Shaopeng Jia 1141524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia // Only upper-case variants of alpha characters are stored. 115be1af2f8b62d5435eca48f3dd5c82e3d2c9bfa17Shaopeng Jia private static final Map<Character, Character> ALPHA_MAPPINGS; 1161524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia 1171524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia // For performance reasons, amalgamate both into one map. 118d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia private static final Map<Character, Character> ALPHA_PHONE_MAPPINGS; 119be1af2f8b62d5435eca48f3dd5c82e3d2c9bfa17Shaopeng Jia 120372bff8dd464574d36737d47e495cad14346653cShaopeng Jia // Separate map of all symbols that we wish to retain when formatting alpha numbers. This 121372bff8dd464574d36737d47e495cad14346653cShaopeng Jia // includes digits, ASCII letters and number grouping symbols such as "-" and " ". 122372bff8dd464574d36737d47e495cad14346653cShaopeng Jia private static final Map<Character, Character> ALL_PLUS_NUMBER_GROUPING_SYMBOLS; 123372bff8dd464574d36737d47e495cad14346653cShaopeng Jia 124be1af2f8b62d5435eca48f3dd5c82e3d2c9bfa17Shaopeng Jia static { 125d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia // Simple ASCII digits map used to populate ALPHA_PHONE_MAPPINGS and 126372bff8dd464574d36737d47e495cad14346653cShaopeng Jia // ALL_PLUS_NUMBER_GROUPING_SYMBOLS. 127372bff8dd464574d36737d47e495cad14346653cShaopeng Jia HashMap<Character, Character> asciiDigitMappings = new HashMap<Character, Character>(); 128372bff8dd464574d36737d47e495cad14346653cShaopeng Jia asciiDigitMappings.put('0', '0'); 129372bff8dd464574d36737d47e495cad14346653cShaopeng Jia asciiDigitMappings.put('1', '1'); 130372bff8dd464574d36737d47e495cad14346653cShaopeng Jia asciiDigitMappings.put('2', '2'); 131372bff8dd464574d36737d47e495cad14346653cShaopeng Jia asciiDigitMappings.put('3', '3'); 132372bff8dd464574d36737d47e495cad14346653cShaopeng Jia asciiDigitMappings.put('4', '4'); 133372bff8dd464574d36737d47e495cad14346653cShaopeng Jia asciiDigitMappings.put('5', '5'); 134372bff8dd464574d36737d47e495cad14346653cShaopeng Jia asciiDigitMappings.put('6', '6'); 135372bff8dd464574d36737d47e495cad14346653cShaopeng Jia asciiDigitMappings.put('7', '7'); 136372bff8dd464574d36737d47e495cad14346653cShaopeng Jia asciiDigitMappings.put('8', '8'); 137372bff8dd464574d36737d47e495cad14346653cShaopeng Jia asciiDigitMappings.put('9', '9'); 138372bff8dd464574d36737d47e495cad14346653cShaopeng Jia 139be1af2f8b62d5435eca48f3dd5c82e3d2c9bfa17Shaopeng Jia HashMap<Character, Character> alphaMap = new HashMap<Character, Character>(40); 140be1af2f8b62d5435eca48f3dd5c82e3d2c9bfa17Shaopeng Jia alphaMap.put('A', '2'); 141be1af2f8b62d5435eca48f3dd5c82e3d2c9bfa17Shaopeng Jia alphaMap.put('B', '2'); 142be1af2f8b62d5435eca48f3dd5c82e3d2c9bfa17Shaopeng Jia alphaMap.put('C', '2'); 143be1af2f8b62d5435eca48f3dd5c82e3d2c9bfa17Shaopeng Jia alphaMap.put('D', '3'); 144be1af2f8b62d5435eca48f3dd5c82e3d2c9bfa17Shaopeng Jia alphaMap.put('E', '3'); 145be1af2f8b62d5435eca48f3dd5c82e3d2c9bfa17Shaopeng Jia alphaMap.put('F', '3'); 146be1af2f8b62d5435eca48f3dd5c82e3d2c9bfa17Shaopeng Jia alphaMap.put('G', '4'); 147be1af2f8b62d5435eca48f3dd5c82e3d2c9bfa17Shaopeng Jia alphaMap.put('H', '4'); 148be1af2f8b62d5435eca48f3dd5c82e3d2c9bfa17Shaopeng Jia alphaMap.put('I', '4'); 149be1af2f8b62d5435eca48f3dd5c82e3d2c9bfa17Shaopeng Jia alphaMap.put('J', '5'); 150be1af2f8b62d5435eca48f3dd5c82e3d2c9bfa17Shaopeng Jia alphaMap.put('K', '5'); 151be1af2f8b62d5435eca48f3dd5c82e3d2c9bfa17Shaopeng Jia alphaMap.put('L', '5'); 152be1af2f8b62d5435eca48f3dd5c82e3d2c9bfa17Shaopeng Jia alphaMap.put('M', '6'); 153be1af2f8b62d5435eca48f3dd5c82e3d2c9bfa17Shaopeng Jia alphaMap.put('N', '6'); 154be1af2f8b62d5435eca48f3dd5c82e3d2c9bfa17Shaopeng Jia alphaMap.put('O', '6'); 155be1af2f8b62d5435eca48f3dd5c82e3d2c9bfa17Shaopeng Jia alphaMap.put('P', '7'); 156be1af2f8b62d5435eca48f3dd5c82e3d2c9bfa17Shaopeng Jia alphaMap.put('Q', '7'); 157be1af2f8b62d5435eca48f3dd5c82e3d2c9bfa17Shaopeng Jia alphaMap.put('R', '7'); 158be1af2f8b62d5435eca48f3dd5c82e3d2c9bfa17Shaopeng Jia alphaMap.put('S', '7'); 159be1af2f8b62d5435eca48f3dd5c82e3d2c9bfa17Shaopeng Jia alphaMap.put('T', '8'); 160be1af2f8b62d5435eca48f3dd5c82e3d2c9bfa17Shaopeng Jia alphaMap.put('U', '8'); 161be1af2f8b62d5435eca48f3dd5c82e3d2c9bfa17Shaopeng Jia alphaMap.put('V', '8'); 162be1af2f8b62d5435eca48f3dd5c82e3d2c9bfa17Shaopeng Jia alphaMap.put('W', '9'); 163be1af2f8b62d5435eca48f3dd5c82e3d2c9bfa17Shaopeng Jia alphaMap.put('X', '9'); 164be1af2f8b62d5435eca48f3dd5c82e3d2c9bfa17Shaopeng Jia alphaMap.put('Y', '9'); 165be1af2f8b62d5435eca48f3dd5c82e3d2c9bfa17Shaopeng Jia alphaMap.put('Z', '9'); 166be1af2f8b62d5435eca48f3dd5c82e3d2c9bfa17Shaopeng Jia ALPHA_MAPPINGS = Collections.unmodifiableMap(alphaMap); 167be1af2f8b62d5435eca48f3dd5c82e3d2c9bfa17Shaopeng Jia 168be1af2f8b62d5435eca48f3dd5c82e3d2c9bfa17Shaopeng Jia HashMap<Character, Character> combinedMap = new HashMap<Character, Character>(100); 169d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia combinedMap.putAll(ALPHA_MAPPINGS); 170d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia combinedMap.putAll(asciiDigitMappings); 171d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia ALPHA_PHONE_MAPPINGS = Collections.unmodifiableMap(combinedMap); 1721524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia 17396a7214cdabf08f53f5b1a560304601c9f65e0b9Shaopeng Jia HashMap<Character, Character> diallableCharMap = new HashMap<Character, Character>(); 17496a7214cdabf08f53f5b1a560304601c9f65e0b9Shaopeng Jia diallableCharMap.putAll(asciiDigitMappings); 175bf5d9756fe9b13f5b2e0696c62949cea77396687Shaopeng Jia diallableCharMap.put(PLUS_SIGN, PLUS_SIGN); 17696a7214cdabf08f53f5b1a560304601c9f65e0b9Shaopeng Jia diallableCharMap.put('*', '*'); 17796a7214cdabf08f53f5b1a560304601c9f65e0b9Shaopeng Jia DIALLABLE_CHAR_MAPPINGS = Collections.unmodifiableMap(diallableCharMap); 17896a7214cdabf08f53f5b1a560304601c9f65e0b9Shaopeng Jia 179372bff8dd464574d36737d47e495cad14346653cShaopeng Jia HashMap<Character, Character> allPlusNumberGroupings = new HashMap<Character, Character>(); 180372bff8dd464574d36737d47e495cad14346653cShaopeng Jia // Put (lower letter -> upper letter) and (upper letter -> upper letter) mappings. 181372bff8dd464574d36737d47e495cad14346653cShaopeng Jia for (char c : ALPHA_MAPPINGS.keySet()) { 182372bff8dd464574d36737d47e495cad14346653cShaopeng Jia allPlusNumberGroupings.put(Character.toLowerCase(c), c); 183372bff8dd464574d36737d47e495cad14346653cShaopeng Jia allPlusNumberGroupings.put(c, c); 184372bff8dd464574d36737d47e495cad14346653cShaopeng Jia } 185372bff8dd464574d36737d47e495cad14346653cShaopeng Jia allPlusNumberGroupings.putAll(asciiDigitMappings); 186372bff8dd464574d36737d47e495cad14346653cShaopeng Jia // Put grouping symbols. 187372bff8dd464574d36737d47e495cad14346653cShaopeng Jia allPlusNumberGroupings.put('-', '-'); 188372bff8dd464574d36737d47e495cad14346653cShaopeng Jia allPlusNumberGroupings.put('\uFF0D', '-'); 189372bff8dd464574d36737d47e495cad14346653cShaopeng Jia allPlusNumberGroupings.put('\u2010', '-'); 190372bff8dd464574d36737d47e495cad14346653cShaopeng Jia allPlusNumberGroupings.put('\u2011', '-'); 191372bff8dd464574d36737d47e495cad14346653cShaopeng Jia allPlusNumberGroupings.put('\u2012', '-'); 192372bff8dd464574d36737d47e495cad14346653cShaopeng Jia allPlusNumberGroupings.put('\u2013', '-'); 193372bff8dd464574d36737d47e495cad14346653cShaopeng Jia allPlusNumberGroupings.put('\u2014', '-'); 194372bff8dd464574d36737d47e495cad14346653cShaopeng Jia allPlusNumberGroupings.put('\u2015', '-'); 195372bff8dd464574d36737d47e495cad14346653cShaopeng Jia allPlusNumberGroupings.put('\u2212', '-'); 196372bff8dd464574d36737d47e495cad14346653cShaopeng Jia allPlusNumberGroupings.put('/', '/'); 197372bff8dd464574d36737d47e495cad14346653cShaopeng Jia allPlusNumberGroupings.put('\uFF0F', '/'); 198372bff8dd464574d36737d47e495cad14346653cShaopeng Jia allPlusNumberGroupings.put(' ', ' '); 199372bff8dd464574d36737d47e495cad14346653cShaopeng Jia allPlusNumberGroupings.put('\u3000', ' '); 200372bff8dd464574d36737d47e495cad14346653cShaopeng Jia allPlusNumberGroupings.put('\u2060', ' '); 201372bff8dd464574d36737d47e495cad14346653cShaopeng Jia allPlusNumberGroupings.put('.', '.'); 202372bff8dd464574d36737d47e495cad14346653cShaopeng Jia allPlusNumberGroupings.put('\uFF0E', '.'); 203372bff8dd464574d36737d47e495cad14346653cShaopeng Jia ALL_PLUS_NUMBER_GROUPING_SYMBOLS = Collections.unmodifiableMap(allPlusNumberGroupings); 204372bff8dd464574d36737d47e495cad14346653cShaopeng Jia } 205372bff8dd464574d36737d47e495cad14346653cShaopeng Jia 206372bff8dd464574d36737d47e495cad14346653cShaopeng Jia // Pattern that makes it easy to distinguish whether a region has a unique international dialing 207372bff8dd464574d36737d47e495cad14346653cShaopeng Jia // prefix or not. If a region has a unique international prefix (e.g. 011 in USA), it will be 2081524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia // represented as a string that contains a sequence of ASCII digits. If there are multiple 209372bff8dd464574d36737d47e495cad14346653cShaopeng Jia // available international prefixes in a region, they will be represented as a regex string that 2101524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia // always contains character(s) other than ASCII digits. 2111524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia // Note this regex also includes tilde, which signals waiting for the tone. 2121524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia private static final Pattern UNIQUE_INTERNATIONAL_PREFIX = 2137900ea273b8c33b3c6f70d7dd559127938d0fc3dShaopeng Jia Pattern.compile("[\\d]+(?:[~\u2053\u223C\uFF5E][\\d]+)?"); 2141524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia 2151524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia // Regular expression of acceptable punctuation found in phone numbers. This excludes punctuation 2161524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia // found as a leading character only. 2171524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia // This consists of dash characters, white space characters, full stops, slashes, 2181524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia // square brackets, parentheses and tildes. It also includes the letter 'x' as that is found as a 219d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia // placeholder for carrier information in some phone numbers. Full-width variants are also 220d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia // present. 22174aa862e30b4d1b2722e90b1a8684274441a7541Shaopeng Jia static final String VALID_PUNCTUATION = "-x\u2010-\u2015\u2212\u30FC\uFF0D-\uFF0F " + 222bf5d9756fe9b13f5b2e0696c62949cea77396687Shaopeng Jia "\u00A0\u00AD\u200B\u2060\u3000()\uFF08\uFF09\uFF3B\uFF3D.\\[\\]/~\u2053\u223C\uFF5E"; 2231524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia 224d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia private static final String DIGITS = "\\p{Nd}"; 2251524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia // We accept alpha characters in phone numbers, ASCII only, upper and lower case. 2261524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia private static final String VALID_ALPHA = 22774aa862e30b4d1b2722e90b1a8684274441a7541Shaopeng Jia Arrays.toString(ALPHA_MAPPINGS.keySet().toArray()).replaceAll("[, \\[\\]]", "") + 22874aa862e30b4d1b2722e90b1a8684274441a7541Shaopeng Jia Arrays.toString(ALPHA_MAPPINGS.keySet().toArray()).toLowerCase().replaceAll("[, \\[\\]]", ""); 22974aa862e30b4d1b2722e90b1a8684274441a7541Shaopeng Jia static final String PLUS_CHARS = "+\uFF0B"; 23016b56da4e787a614d16bedcd02b5086d40efbbdbShaopeng Jia static final Pattern PLUS_CHARS_PATTERN = Pattern.compile("[" + PLUS_CHARS + "]+"); 231372bff8dd464574d36737d47e495cad14346653cShaopeng Jia private static final Pattern SEPARATOR_PATTERN = Pattern.compile("[" + VALID_PUNCTUATION + "]+"); 232d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia private static final Pattern CAPTURING_DIGIT_PATTERN = Pattern.compile("(" + DIGITS + ")"); 2331524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia 2341524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia // Regular expression of acceptable characters that may start a phone number for the purposes of 2351524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia // parsing. This allows us to strip away meaningless prefixes to phone numbers that may be 2361524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia // mistakenly given to us. This consists of digits, the plus symbol and arabic-indic digits. This 2371524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia // does not contain alpha characters, although they may be used later in the number. It also does 2381524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia // not include other punctuation, as this will be stripped later during parsing and is of no 2391524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia // information value when parsing a number. 240d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia private static final String VALID_START_CHAR = "[" + PLUS_CHARS + DIGITS + "]"; 24116b56da4e787a614d16bedcd02b5086d40efbbdbShaopeng Jia private static final Pattern VALID_START_CHAR_PATTERN = Pattern.compile(VALID_START_CHAR); 2421524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia 2431524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia // Regular expression of characters typically used to start a second phone number for the purposes 2441524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia // of parsing. This allows us to strip off parts of the number that are actually the start of 2451524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia // another number, such as for: (530) 583-6985 x302/x2303 -> the second extension here makes this 2461524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia // actually two phone numbers, (530) 583-6985 x302 and (530) 583-6985 x2303. We remove the second 2471524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia // extension so that the first number is parsed correctly. 2481524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia private static final String SECOND_NUMBER_START = "[\\\\/] *x"; 24974aa862e30b4d1b2722e90b1a8684274441a7541Shaopeng Jia static final Pattern SECOND_NUMBER_START_PATTERN = Pattern.compile(SECOND_NUMBER_START); 2501524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia 2517900ea273b8c33b3c6f70d7dd559127938d0fc3dShaopeng Jia // Regular expression of trailing characters that we want to remove. We remove all characters that 2527900ea273b8c33b3c6f70d7dd559127938d0fc3dShaopeng Jia // are not alpha or numerical characters. The hash character is retained here, as it may signify 2537900ea273b8c33b3c6f70d7dd559127938d0fc3dShaopeng Jia // the previous block was an extension. 2547900ea273b8c33b3c6f70d7dd559127938d0fc3dShaopeng Jia private static final String UNWANTED_END_CHARS = "[[\\P{N}&&\\P{L}]&&[^#]]+$"; 255372bff8dd464574d36737d47e495cad14346653cShaopeng Jia static final Pattern UNWANTED_END_CHAR_PATTERN = Pattern.compile(UNWANTED_END_CHARS); 2567900ea273b8c33b3c6f70d7dd559127938d0fc3dShaopeng Jia 2577900ea273b8c33b3c6f70d7dd559127938d0fc3dShaopeng Jia // We use this pattern to check if the phone number has at least three letters in it - if so, then 2587900ea273b8c33b3c6f70d7dd559127938d0fc3dShaopeng Jia // we treat it as a number where some phone-number digits are represented by letters. 2597900ea273b8c33b3c6f70d7dd559127938d0fc3dShaopeng Jia private static final Pattern VALID_ALPHA_PHONE_PATTERN = Pattern.compile("(?:.*?[A-Za-z]){3}.*"); 2607900ea273b8c33b3c6f70d7dd559127938d0fc3dShaopeng Jia 2611524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia // Regular expression of viable phone numbers. This is location independent. Checks we have at 2621524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia // least three leading digits, and only valid punctuation, alpha characters and 2637900ea273b8c33b3c6f70d7dd559127938d0fc3dShaopeng Jia // digits in the phone number. Does not include extension data. 2641524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia // The symbol 'x' is allowed here as valid punctuation since it is often used as a placeholder for 265256a5f71a05ffd182a0fda2cfed6f93345cc889fLara Rennie // carrier codes, for example in Brazilian phone numbers. We also allow multiple "+" characters at 266256a5f71a05ffd182a0fda2cfed6f93345cc889fLara Rennie // the start. 2671524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia // Corresponds to the following: 2684b867acb917b73e699a596df94445c634c916519Shaopeng Jia // [digits]{minLengthNsn}| 269cc0ae7326023c5da91dd9a84035c3dc3f6cc372fShaopeng Jia // plus_sign*(([punctuation]|[star])*[digits]){3,}([punctuation]|[star]|[digits]|[alpha])* 2704b867acb917b73e699a596df94445c634c916519Shaopeng Jia // 2714b867acb917b73e699a596df94445c634c916519Shaopeng Jia // The first reg-ex is to allow short numbers (two digits long) to be parsed if they are entered 2724b867acb917b73e699a596df94445c634c916519Shaopeng Jia // as "15" etc, but only if there is no punctuation in them. The second expression restricts the 2734b867acb917b73e699a596df94445c634c916519Shaopeng Jia // number of digits to three or more, but then allows them to be in international form, and to 2744b867acb917b73e699a596df94445c634c916519Shaopeng Jia // have alpha-characters and punctuation. 2754b867acb917b73e699a596df94445c634c916519Shaopeng Jia // 27674aa862e30b4d1b2722e90b1a8684274441a7541Shaopeng Jia // Note VALID_PUNCTUATION starts with a -, so must be the first in the range. 2771524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia private static final String VALID_PHONE_NUMBER = 2784b867acb917b73e699a596df94445c634c916519Shaopeng Jia DIGITS + "{" + MIN_LENGTH_FOR_NSN + "}" + "|" + 279b0e21c22b1ca6b9aeb1426924cdf42a221c3d416Shaopeng Jia "[" + PLUS_CHARS + "]*+(?:[" + VALID_PUNCTUATION + STAR_SIGN + "]*" + DIGITS + "){3,}[" + 280cc0ae7326023c5da91dd9a84035c3dc3f6cc372fShaopeng Jia VALID_PUNCTUATION + STAR_SIGN + VALID_ALPHA + DIGITS + "]*"; 2811524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia 2821524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia // Default extension prefix to use when formatting. This will be put in front of any extension 2831524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia // component of the number, after the main national number is formatted. For example, if you wish 2841524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia // the default extension formatting to be " extn: 3456", then you should specify " extn: " here 285372bff8dd464574d36737d47e495cad14346653cShaopeng Jia // as the default extension prefix. This can be overridden by region-specific preferences. 2861524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia private static final String DEFAULT_EXTN_PREFIX = " ext. "; 2871524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia 288f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia // Pattern to capture digits used in an extension. Places a maximum length of "7" for an 289f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia // extension. 290f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia private static final String CAPTURING_EXTN_DIGITS = "(" + DIGITS + "{1,7})"; 2911524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia // Regexp of all possible ways to write extensions, for use when parsing. This will be run as a 292372bff8dd464574d36737d47e495cad14346653cShaopeng Jia // case-insensitive regexp match. Wide character versions are also provided after each ASCII 293f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia // version. 294f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia private static final String EXTN_PATTERNS_FOR_PARSING; 295f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia static final String EXTN_PATTERNS_FOR_MATCHING; 296f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia static { 297f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia // One-character symbols that can be used to indicate an extension. 298f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia String singleExtnSymbolsForMatching = "x\uFF58#\uFF03~\uFF5E"; 299f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia // For parsing, we are slightly more lenient in our interpretation than for matching. Here we 300f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia // allow a "comma" as a possible extension indicator. When matching, this is hardly ever used to 301f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia // indicate this. 302f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia String singleExtnSymbolsForParsing = "," + singleExtnSymbolsForMatching; 303f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia 304f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia EXTN_PATTERNS_FOR_PARSING = createExtnPattern(singleExtnSymbolsForParsing); 305f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia EXTN_PATTERNS_FOR_MATCHING = createExtnPattern(singleExtnSymbolsForMatching); 306f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia } 307f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia 308f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia /** 309f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia * Helper initialiser method to create the regular-expression pattern to match extensions, 310f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia * allowing the one-char extension symbols provided by {@code singleExtnSymbols}. 311f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia */ 312f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia private static String createExtnPattern(String singleExtnSymbols) { 313f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia // There are three regular expressions here. The first covers RFC 3966 format, where the 314f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia // extension is added using ";ext=". The second more generic one starts with optional white 315f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia // space and ends with an optional full stop (.), followed by zero or more spaces/tabs and then 316f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia // the numbers themselves. The other one covers the special case of American numbers where the 317f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia // extension is written with a hash at the end, such as "- 503#". 318f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia // Note that the only capturing groups should be around the digits that you want to capture as 319f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia // part of the extension, or else parsing will fail! 320f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia // Canonical-equivalence doesn't seem to be an option with Android java, so we allow two options 321f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia // for representing the accented o - the character itself, and one in the unicode decomposed 322f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia // form with the combining acute accent. 323f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia return (RFC3966_EXTN_PREFIX + CAPTURING_EXTN_DIGITS + "|" + "[ \u00A0\\t,]*" + 324528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia "(?:e?xt(?:ensi(?:o\u0301?|\u00F3))?n?|\uFF45?\uFF58\uFF54\uFF4E?|" + 325f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia "[" + singleExtnSymbols + "]|int|anexo|\uFF49\uFF4E\uFF54)" + 326f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia "[:\\.\uFF0E]?[ \u00A0\\t,-]*" + CAPTURING_EXTN_DIGITS + "#?|" + 327f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia "[- ]+(" + DIGITS + "{1,5})#"); 328f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia } 3291524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia 330372bff8dd464574d36737d47e495cad14346653cShaopeng Jia // Regexp of all known extension prefixes used by different regions followed by 1 or more valid 3311524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia // digits, for use when parsing. 3321524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia private static final Pattern EXTN_PATTERN = 333f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia Pattern.compile("(?:" + EXTN_PATTERNS_FOR_PARSING + ")$", REGEX_FLAGS); 3341524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia 3351524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia // We append optionally the extension pattern to the end here, as a valid phone number may 3361524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia // have an extension prefix appended, followed by 1 or more digits. 3371524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia private static final Pattern VALID_PHONE_NUMBER_PATTERN = 338f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia Pattern.compile(VALID_PHONE_NUMBER + "(?:" + EXTN_PATTERNS_FOR_PARSING + ")?", REGEX_FLAGS); 3391524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia 340b210e301245cb5dc90aa3142f378632bd41cb172Shaopeng Jia static final Pattern NON_DIGITS_PATTERN = Pattern.compile("(\\D+)"); 341372bff8dd464574d36737d47e495cad14346653cShaopeng Jia 342372bff8dd464574d36737d47e495cad14346653cShaopeng Jia // The FIRST_GROUP_PATTERN was originally set to $1 but there are some countries for which the 343372bff8dd464574d36737d47e495cad14346653cShaopeng Jia // first group is not used in the national pattern (e.g. Argentina) so the $1 group does not match 344372bff8dd464574d36737d47e495cad14346653cShaopeng Jia // correctly. Therefore, we use \d, so that the first group actually used in the pattern will be 345372bff8dd464574d36737d47e495cad14346653cShaopeng Jia // matched. 346372bff8dd464574d36737d47e495cad14346653cShaopeng Jia private static final Pattern FIRST_GROUP_PATTERN = Pattern.compile("(\\$\\d)"); 347be1af2f8b62d5435eca48f3dd5c82e3d2c9bfa17Shaopeng Jia private static final Pattern NP_PATTERN = Pattern.compile("\\$NP"); 348be1af2f8b62d5435eca48f3dd5c82e3d2c9bfa17Shaopeng Jia private static final Pattern FG_PATTERN = Pattern.compile("\\$FG"); 3494b7846722d1a5acb0577b07e98324f744f5e7942Shaopeng Jia private static final Pattern CC_PATTERN = Pattern.compile("\\$CC"); 350be1af2f8b62d5435eca48f3dd5c82e3d2c9bfa17Shaopeng Jia 351203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia // A pattern that is used to determine if the national prefix formatting rule has the first group 352203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia // only, i.e., does not start with the national prefix. Note that the pattern explicitly allows 353203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia // for unbalanced parentheses. 354203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia private static final Pattern FIRST_GROUP_ONLY_PREFIX_PATTERN = Pattern.compile("\\(?\\$1\\)?"); 355203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia 3561524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia private static PhoneNumberUtil instance = null; 3571524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia 3581524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia // A mapping from a region code to the PhoneMetadata for that region. 359a1d3a5ed3af9cee85acdad939042a851a629f18cShaopeng Jia private final Map<String, PhoneMetadata> regionToMetadataMap = 360a1d3a5ed3af9cee85acdad939042a851a629f18cShaopeng Jia Collections.synchronizedMap(new HashMap<String, PhoneMetadata>()); 361be1af2f8b62d5435eca48f3dd5c82e3d2c9bfa17Shaopeng Jia 362528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia // A mapping from a country calling code for a non-geographical entity to the PhoneMetadata for 363528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia // that country calling code. Examples of the country calling codes include 800 (International 364528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia // Toll Free Service) and 808 (International Shared Cost Service). 365528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia private final Map<Integer, PhoneMetadata> countryCodeToNonGeographicalMetadataMap = 366528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia Collections.synchronizedMap(new HashMap<Integer, PhoneMetadata>()); 367528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia 368203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia // The set of county calling codes that map to the non-geo entity region ("001"). This set 369203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia // currently contains < 12 elements so the default capacity of 16 (load factor=0.75) is fine. 370203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia private final Set<Integer> countryCodesForNonGeographicalRegion = new HashSet<Integer>(); 371203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia 372372bff8dd464574d36737d47e495cad14346653cShaopeng Jia // A cache for frequently used region-specific regular expressions. 373f59ccfca9dd02c4e3cf3e06b5cf184a8d0e67626Shaopeng Jia // As most people use phone numbers primarily from one to two countries, and there are roughly 60 374f59ccfca9dd02c4e3cf3e06b5cf184a8d0e67626Shaopeng Jia // regular expressions needed, the initial capacity of 100 offers a rough load factor of 0.75. 3754b7846722d1a5acb0577b07e98324f744f5e7942Shaopeng Jia private RegexCache regexCache = new RegexCache(100); 3761524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia 377528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia public static final String REGION_CODE_FOR_NON_GEO_ENTITY = "001"; 378528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia 3791524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia /** 3801524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * INTERNATIONAL and NATIONAL formats are consistent with the definition in ITU-T Recommendation 381d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia * E123. For example, the number of the Google Switzerland office will be written as 3821524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * "+41 44 668 1800" in INTERNATIONAL format, and as "044 668 1800" in NATIONAL format. 383b0e21c22b1ca6b9aeb1426924cdf42a221c3d416Shaopeng Jia * E164 format is as per INTERNATIONAL format but with no formatting applied, e.g. 384b0e21c22b1ca6b9aeb1426924cdf42a221c3d416Shaopeng Jia * "+41446681800". RFC3966 is as per INTERNATIONAL format, but with all spaces and other 385b0e21c22b1ca6b9aeb1426924cdf42a221c3d416Shaopeng Jia * separating symbols replaced with a hyphen, and with any phone number extension appended with 386b0e21c22b1ca6b9aeb1426924cdf42a221c3d416Shaopeng Jia * ";ext=". It also will have a prefix of "tel:" added, e.g. "tel:+41-44-668-1800". 3871524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * 3881524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * Note: If you are considering storing the number in a neutral format, you are highly advised to 389372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * use the PhoneNumber class. 3901524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia */ 3911524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia public enum PhoneNumberFormat { 3921524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia E164, 3931524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia INTERNATIONAL, 394372bff8dd464574d36737d47e495cad14346653cShaopeng Jia NATIONAL, 395372bff8dd464574d36737d47e495cad14346653cShaopeng Jia RFC3966 3961524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } 3971524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia 3981524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia /** 3991524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * Type of phone numbers. 4001524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia */ 4011524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia public enum PhoneNumberType { 4021524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia FIXED_LINE, 4031524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia MOBILE, 404372bff8dd464574d36737d47e495cad14346653cShaopeng Jia // In some regions (e.g. the USA), it is impossible to distinguish between fixed-line and 4051524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia // mobile numbers by looking at the phone number itself. 4061524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia FIXED_LINE_OR_MOBILE, 4071524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia // Freephone lines 4081524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia TOLL_FREE, 4091524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia PREMIUM_RATE, 4101524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia // The cost of this call is shared between the caller and the recipient, and is hence typically 4111524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia // less than PREMIUM_RATE calls. See // http://en.wikipedia.org/wiki/Shared_Cost_Service for 4121524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia // more information. 4131524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia SHARED_COST, 4141524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia // Voice over IP numbers. This includes TSoIP (Telephony Service over IP). 4151524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia VOIP, 4161524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia // A personal number is associated with a particular person, and may be routed to either a 4171524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia // MOBILE or FIXED_LINE number. Some more information can be found here: 4181524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia // http://en.wikipedia.org/wiki/Personal_Numbers 4191524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia PERSONAL_NUMBER, 420b2697412130f6d087dde01fb1a978f7e5840a5faShaopeng Jia PAGER, 42174aa862e30b4d1b2722e90b1a8684274441a7541Shaopeng Jia // Used for "Universal Access Numbers" or "Company Numbers". They may be further routed to 42274aa862e30b4d1b2722e90b1a8684274441a7541Shaopeng Jia // specific offices, but allow one number to be used for a company. 42374aa862e30b4d1b2722e90b1a8684274441a7541Shaopeng Jia UAN, 424528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia // Used for "Voice Mail Access Numbers". 425528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia VOICEMAIL, 4261524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia // A phone number is of type UNKNOWN when it does not fit any of the known patterns for a 427372bff8dd464574d36737d47e495cad14346653cShaopeng Jia // specific region. 4281524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia UNKNOWN 4291524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } 4301524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia 4311524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia /** 4321524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * Types of phone number matches. See detailed description beside the isNumberMatch() method. 4331524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia */ 4341524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia public enum MatchType { 43574aa862e30b4d1b2722e90b1a8684274441a7541Shaopeng Jia NOT_A_NUMBER, 4361524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia NO_MATCH, 4371524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia SHORT_NSN_MATCH, 4381524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia NSN_MATCH, 4391524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia EXACT_MATCH, 4401524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } 4411524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia 4421524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia /** 4431524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * Possible outcomes when testing if a PhoneNumber is possible. 4441524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia */ 4451524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia public enum ValidationResult { 4461524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia IS_POSSIBLE, 4471524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia INVALID_COUNTRY_CODE, 4481524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia TOO_SHORT, 4491524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia TOO_LONG, 4501524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } 4511524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia 4521524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia /** 45352699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia * Leniency when {@linkplain PhoneNumberUtil#findNumbers finding} potential phone numbers in text 454f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia * segments. The levels here are ordered in increasing strictness. 45552699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia */ 45652699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia public enum Leniency { 45752699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia /** 45896a7214cdabf08f53f5b1a560304601c9f65e0b9Shaopeng Jia * Phone numbers accepted are {@linkplain PhoneNumberUtil#isPossibleNumber(PhoneNumber) 45996a7214cdabf08f53f5b1a560304601c9f65e0b9Shaopeng Jia * possible}, but not necessarily {@linkplain PhoneNumberUtil#isValidNumber(PhoneNumber) valid}. 46052699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia */ 46152699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia POSSIBLE { 46252699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia @Override 463f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia boolean verify(PhoneNumber number, String candidate, PhoneNumberUtil util) { 46452699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia return util.isPossibleNumber(number); 46552699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia } 46652699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia }, 46752699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia /** 46896a7214cdabf08f53f5b1a560304601c9f65e0b9Shaopeng Jia * Phone numbers accepted are {@linkplain PhoneNumberUtil#isPossibleNumber(PhoneNumber) 46996a7214cdabf08f53f5b1a560304601c9f65e0b9Shaopeng Jia * possible} and {@linkplain PhoneNumberUtil#isValidNumber(PhoneNumber) valid}. Numbers written 470a48b2d221ba46df7446d1a87244efa985e8e292fShaopeng Jia * in national format must have their national-prefix present if it is usually written for a 471a48b2d221ba46df7446d1a87244efa985e8e292fShaopeng Jia * number of this type. 47252699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia */ 47352699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia VALID { 47452699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia @Override 475f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia boolean verify(PhoneNumber number, String candidate, PhoneNumberUtil util) { 476a48b2d221ba46df7446d1a87244efa985e8e292fShaopeng Jia if (!util.isValidNumber(number) || 477b210e301245cb5dc90aa3142f378632bd41cb172Shaopeng Jia !PhoneNumberMatcher.containsOnlyValidXChars(number, candidate, util)) { 478f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia return false; 479f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia } 480b210e301245cb5dc90aa3142f378632bd41cb172Shaopeng Jia return PhoneNumberMatcher.isNationalPrefixPresentIfRequired(number, util); 481f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia } 482f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia }, 483f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia /** 484f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia * Phone numbers accepted are {@linkplain PhoneNumberUtil#isValidNumber(PhoneNumber) valid} and 485f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia * are grouped in a possible way for this locale. For example, a US number written as 486f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia * "65 02 53 00 00" and "650253 0000" are not accepted at this leniency level, whereas 487f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia * "650 253 0000", "650 2530000" or "6502530000" are. 488f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia * Numbers with more than one '/' symbol are also dropped at this level. 489f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia * <p> 490f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia * Warning: This level might result in lower coverage especially for regions outside of country 491f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia * code "+1". If you are not sure about which level to use, email the discussion group 492f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia * libphonenumber-discuss@googlegroups.com. 493f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia */ 494f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia STRICT_GROUPING { 495f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia @Override 496f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia boolean verify(PhoneNumber number, String candidate, PhoneNumberUtil util) { 497f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia if (!util.isValidNumber(number) || 498b210e301245cb5dc90aa3142f378632bd41cb172Shaopeng Jia !PhoneNumberMatcher.containsOnlyValidXChars(number, candidate, util) || 499b210e301245cb5dc90aa3142f378632bd41cb172Shaopeng Jia PhoneNumberMatcher.containsMoreThanOneSlash(candidate) || 500b210e301245cb5dc90aa3142f378632bd41cb172Shaopeng Jia !PhoneNumberMatcher.isNationalPrefixPresentIfRequired(number, util)) { 501f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia return false; 502f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia } 503b210e301245cb5dc90aa3142f378632bd41cb172Shaopeng Jia return PhoneNumberMatcher.checkNumberGroupingIsValid( 504b210e301245cb5dc90aa3142f378632bd41cb172Shaopeng Jia number, candidate, util, new PhoneNumberMatcher.NumberGroupingChecker() { 505b210e301245cb5dc90aa3142f378632bd41cb172Shaopeng Jia public boolean checkGroups(PhoneNumberUtil util, PhoneNumber number, 506b210e301245cb5dc90aa3142f378632bd41cb172Shaopeng Jia StringBuilder normalizedCandidate, 507b210e301245cb5dc90aa3142f378632bd41cb172Shaopeng Jia String[] expectedNumberGroups) { 508b210e301245cb5dc90aa3142f378632bd41cb172Shaopeng Jia return PhoneNumberMatcher.allNumberGroupsRemainGrouped( 509b210e301245cb5dc90aa3142f378632bd41cb172Shaopeng Jia util, number, normalizedCandidate, expectedNumberGroups); 510b210e301245cb5dc90aa3142f378632bd41cb172Shaopeng Jia } 511b210e301245cb5dc90aa3142f378632bd41cb172Shaopeng Jia }); 512f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia } 513f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia }, 514f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia /** 515f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia * Phone numbers accepted are {@linkplain PhoneNumberUtil#isValidNumber(PhoneNumber) valid} and 516f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia * are grouped in the same way that we would have formatted it, or as a single block. For 517f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia * example, a US number written as "650 2530000" is not accepted at this leniency level, whereas 518f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia * "650 253 0000" or "6502530000" are. 519f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia * Numbers with more than one '/' symbol are also dropped at this level. 520f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia * <p> 521f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia * Warning: This level might result in lower coverage especially for regions outside of country 522f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia * code "+1". If you are not sure about which level to use, email the discussion group 523f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia * libphonenumber-discuss@googlegroups.com. 524f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia */ 525f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia EXACT_GROUPING { 526f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia @Override 527f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia boolean verify(PhoneNumber number, String candidate, PhoneNumberUtil util) { 528f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia if (!util.isValidNumber(number) || 529b210e301245cb5dc90aa3142f378632bd41cb172Shaopeng Jia !PhoneNumberMatcher.containsOnlyValidXChars(number, candidate, util) || 530b210e301245cb5dc90aa3142f378632bd41cb172Shaopeng Jia PhoneNumberMatcher.containsMoreThanOneSlash(candidate) || 531b210e301245cb5dc90aa3142f378632bd41cb172Shaopeng Jia !PhoneNumberMatcher.isNationalPrefixPresentIfRequired(number, util)) { 532f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia return false; 533f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia } 534b210e301245cb5dc90aa3142f378632bd41cb172Shaopeng Jia return PhoneNumberMatcher.checkNumberGroupingIsValid( 535b210e301245cb5dc90aa3142f378632bd41cb172Shaopeng Jia number, candidate, util, new PhoneNumberMatcher.NumberGroupingChecker() { 536b210e301245cb5dc90aa3142f378632bd41cb172Shaopeng Jia public boolean checkGroups(PhoneNumberUtil util, PhoneNumber number, 537b210e301245cb5dc90aa3142f378632bd41cb172Shaopeng Jia StringBuilder normalizedCandidate, 538b210e301245cb5dc90aa3142f378632bd41cb172Shaopeng Jia String[] expectedNumberGroups) { 539b210e301245cb5dc90aa3142f378632bd41cb172Shaopeng Jia return PhoneNumberMatcher.allNumberGroupsAreExactlyPresent( 540b210e301245cb5dc90aa3142f378632bd41cb172Shaopeng Jia util, number, normalizedCandidate, expectedNumberGroups); 541b210e301245cb5dc90aa3142f378632bd41cb172Shaopeng Jia } 542b210e301245cb5dc90aa3142f378632bd41cb172Shaopeng Jia }); 54352699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia } 54452699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia }; 54552699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia 54652699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia /** Returns true if {@code number} is a verified number according to this leniency. */ 547f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia abstract boolean verify(PhoneNumber number, String candidate, PhoneNumberUtil util); 54852699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia } 54952699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia 55052699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia /** 5511524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * This class implements a singleton, so the only constructor is private. 5521524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia */ 5531524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia private PhoneNumberUtil() { 5541524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } 5551524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia 556fa42140081949568565af7dc8c22f0600ad90a8aShaopeng Jia private void init(String filePrefix) { 557fa42140081949568565af7dc8c22f0600ad90a8aShaopeng Jia currentFilePrefix = filePrefix; 558203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia for (Map.Entry<Integer, List<String>> entry : countryCallingCodeToRegionCodeMap.entrySet()) { 559203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia List<String> regionCodes = entry.getValue(); 560203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia // We can assume that if the county calling code maps to the non-geo entity region code then 561203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia // that's the only region code it maps to. 562203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia if (regionCodes.size() == 1 && REGION_CODE_FOR_NON_GEO_ENTITY.equals(regionCodes.get(0))) { 563203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia // This is the subset of all country codes that map to the non-geo entity region code. 564203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia countryCodesForNonGeographicalRegion.add(entry.getKey()); 565203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia } else { 566203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia // The supported regions set does not include the "001" non-geo entity region code. 567203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia supportedRegions.addAll(regionCodes); 568203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia } 569203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia } 570203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia // If the non-geo entity still got added to the set of supported regions it must be because 571203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia // there are entries that list the non-geo entity alongside normal regions (which is wrong). 572203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia // If we discover this, remove the non-geo entity from the set of supported regions and log. 573203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia if (supportedRegions.remove(REGION_CODE_FOR_NON_GEO_ENTITY)) { 574203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia LOGGER.log(Level.WARNING, "invalid metadata " + 575203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia "(country calling code was mapped to the non-geo entity as well as specific region(s))"); 576fa42140081949568565af7dc8c22f0600ad90a8aShaopeng Jia } 577372bff8dd464574d36737d47e495cad14346653cShaopeng Jia nanpaRegions.addAll(countryCallingCodeToRegionCodeMap.get(NANPA_COUNTRY_CODE)); 578fa42140081949568565af7dc8c22f0600ad90a8aShaopeng Jia } 579fa42140081949568565af7dc8c22f0600ad90a8aShaopeng Jia 580203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia // @VisibleForTesting 581203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia void loadMetadataFromFile(String filePrefix, String regionCode, int countryCallingCode) { 582528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia boolean isNonGeoRegion = REGION_CODE_FOR_NON_GEO_ENTITY.equals(regionCode); 583203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia String fileName = filePrefix + "_" + 584203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia (isNonGeoRegion ? String.valueOf(countryCallingCode) : regionCode); 585203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia InputStream source = PhoneNumberUtil.class.getResourceAsStream(fileName); 586203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia if (source == null) { 587203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia LOGGER.log(Level.SEVERE, "missing metadata: " + fileName); 588203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia throw new RuntimeException("missing metadata: " + fileName); 589203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia } 590507cdd3f40be5346cfd0681239b5dc81abc57d9bShaopeng Jia ObjectInputStream in = null; 5911524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia try { 592fa42140081949568565af7dc8c22f0600ad90a8aShaopeng Jia in = new ObjectInputStream(source); 593bef3e6ee44a7666b4748f5f471d32b9a9371f2d8Shaopeng Jia PhoneMetadataCollection metadataCollection = new PhoneMetadataCollection(); 594bef3e6ee44a7666b4748f5f471d32b9a9371f2d8Shaopeng Jia metadataCollection.readExternal(in); 595203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia List<PhoneMetadata> metadataList = metadataCollection.getMetadataList(); 596203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia if (metadataList.isEmpty()) { 597203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia LOGGER.log(Level.SEVERE, "empty metadata: " + fileName); 598203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia throw new RuntimeException("empty metadata: " + fileName); 599203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia } 600203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia if (metadataList.size() > 1) { 601203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia LOGGER.log(Level.WARNING, "invalid metadata (too many entries): " + fileName); 602203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia } 603203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia PhoneMetadata metadata = metadataList.get(0); 604203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia if (isNonGeoRegion) { 605203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia countryCodeToNonGeographicalMetadataMap.put(countryCallingCode, metadata); 606203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia } else { 607203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia regionToMetadataMap.put(regionCode, metadata); 6081524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } 6091524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } catch (IOException e) { 610203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia LOGGER.log(Level.SEVERE, "cannot load/parse metadata: " + fileName, e); 611203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia throw new RuntimeException("cannot load/parse metadata: " + fileName, e); 612507cdd3f40be5346cfd0681239b5dc81abc57d9bShaopeng Jia } finally { 613507cdd3f40be5346cfd0681239b5dc81abc57d9bShaopeng Jia close(in); 614507cdd3f40be5346cfd0681239b5dc81abc57d9bShaopeng Jia } 615507cdd3f40be5346cfd0681239b5dc81abc57d9bShaopeng Jia } 616507cdd3f40be5346cfd0681239b5dc81abc57d9bShaopeng Jia 617ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia private static void close(InputStream in) { 618507cdd3f40be5346cfd0681239b5dc81abc57d9bShaopeng Jia if (in != null) { 619507cdd3f40be5346cfd0681239b5dc81abc57d9bShaopeng Jia try { 620507cdd3f40be5346cfd0681239b5dc81abc57d9bShaopeng Jia in.close(); 621507cdd3f40be5346cfd0681239b5dc81abc57d9bShaopeng Jia } catch (IOException e) { 622203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia LOGGER.log(Level.WARNING, "error closing input stream (ignored)", e); 623507cdd3f40be5346cfd0681239b5dc81abc57d9bShaopeng Jia } 6241524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } 6251524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } 6261524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia 6271524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia /** 6281524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * Attempts to extract a possible number from the string passed in. This currently strips all 629372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * leading characters that cannot be used to start a phone number. Characters that can be used to 630372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * start a phone number are defined in the VALID_START_CHAR_PATTERN. If none of these characters 631372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * are found in the number passed in, an empty string is returned. This function also attempts to 632372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * strip off any alternative extensions or endings if two or more are present, such as in the case 633372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * of: (530) 583-6985 x302/x2303. The second extension here makes this actually two phone numbers, 634372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * (530) 583-6985 x302 and (530) 583-6985 x2303. We remove the second extension so that the first 635372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * number is parsed correctly. 6361524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * 6371524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * @param number the string that might contain a phone number 6381524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * @return the number, stripped of any non-phone-number prefix (such as "Tel:") or an empty 6391524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * string if no character used to start phone numbers (such as + or any digit) is 6401524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * found in the number 6411524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia */ 6421524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia static String extractPossibleNumber(String number) { 6431524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia Matcher m = VALID_START_CHAR_PATTERN.matcher(number); 6441524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia if (m.find()) { 6451524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia number = number.substring(m.start()); 6464b7846722d1a5acb0577b07e98324f744f5e7942Shaopeng Jia // Remove trailing non-alpha non-numerical characters. 6474b7846722d1a5acb0577b07e98324f744f5e7942Shaopeng Jia Matcher trailingCharsMatcher = UNWANTED_END_CHAR_PATTERN.matcher(number); 6484b7846722d1a5acb0577b07e98324f744f5e7942Shaopeng Jia if (trailingCharsMatcher.find()) { 6494b7846722d1a5acb0577b07e98324f744f5e7942Shaopeng Jia number = number.substring(0, trailingCharsMatcher.start()); 650372bff8dd464574d36737d47e495cad14346653cShaopeng Jia LOGGER.log(Level.FINER, "Stripped trailing characters: " + number); 6514b7846722d1a5acb0577b07e98324f744f5e7942Shaopeng Jia } 6521524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia // Check for extra numbers at the end. 6531524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia Matcher secondNumber = SECOND_NUMBER_START_PATTERN.matcher(number); 6541524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia if (secondNumber.find()) { 6551524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia number = number.substring(0, secondNumber.start()); 6561524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } 6571524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia return number; 6581524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } else { 6591524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia return ""; 6601524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } 6611524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } 6621524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia 6631524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia /** 6641524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * Checks to see if the string of characters could possibly be a phone number at all. At the 665bf5d9756fe9b13f5b2e0696c62949cea77396687Shaopeng Jia * moment, checks to see that the string begins with at least 2 digits, ignoring any punctuation 6661524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * commonly found in phone numbers. 6671524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * This method does not require the number to be normalized in advance - but does assume that 6681524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * leading non-number symbols have been removed, such as by the method extractPossibleNumber. 6691524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * 6701524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * @param number string to be checked for viability as a phone number 6711524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * @return true if the number could be a phone number of some sort, otherwise false 6721524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia */ 673ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia // @VisibleForTesting 6741524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia static boolean isViablePhoneNumber(String number) { 6751524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia if (number.length() < MIN_LENGTH_FOR_NSN) { 6761524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia return false; 6771524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } 6781524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia Matcher m = VALID_PHONE_NUMBER_PATTERN.matcher(number); 6791524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia return m.matches(); 6801524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } 6811524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia 6821524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia /** 6831524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * Normalizes a string of characters representing a phone number. This performs the following 6841524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * conversions: 685d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia * Punctuation is stripped. 686d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia * For ALPHA/VANITY numbers: 6871524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * Letters are converted to their numeric representation on a telephone keypad. The keypad 6881524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * used here is the one defined in ITU Recommendation E.161. This is only done if there are 689d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia * 3 or more letters in the number, to lessen the risk that such letters are typos. 690d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia * For other numbers: 691d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia * Wide-ascii digits are converted to normal ASCII (European) digits. 6921524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * Arabic-Indic numerals are converted to European numerals. 693d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia * Spurious alpha characters are stripped. 6941524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * 6951524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * @param number a string of characters representing a phone number 6961524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * @return the normalized string version of the phone number 6971524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia */ 6981524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia static String normalize(String number) { 6997900ea273b8c33b3c6f70d7dd559127938d0fc3dShaopeng Jia Matcher m = VALID_ALPHA_PHONE_PATTERN.matcher(number); 7007900ea273b8c33b3c6f70d7dd559127938d0fc3dShaopeng Jia if (m.matches()) { 701d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia return normalizeHelper(number, ALPHA_PHONE_MAPPINGS, true); 7021524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } else { 703d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia return normalizeDigitsOnly(number); 7041524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } 7051524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } 7061524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia 7071524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia /** 7081524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * Normalizes a string of characters representing a phone number. This is a wrapper for 709372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * normalize(String number) but does in-place normalization of the StringBuilder provided. 7101524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * 711372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * @param number a StringBuilder of characters representing a phone number that will be 712372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * normalized in place 7131524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia */ 714372bff8dd464574d36737d47e495cad14346653cShaopeng Jia static void normalize(StringBuilder number) { 7151524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia String normalizedNumber = normalize(number.toString()); 7161524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia number.replace(0, number.length(), normalizedNumber); 7171524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } 7181524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia 7191524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia /** 7201524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * Normalizes a string of characters representing a phone number. This converts wide-ascii and 7217900ea273b8c33b3c6f70d7dd559127938d0fc3dShaopeng Jia * arabic-indic numerals to European numerals, and strips punctuation and alpha characters. 7221524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * 7231524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * @param number a string of characters representing a phone number 7241524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * @return the normalized string version of the phone number 7251524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia */ 7261524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia public static String normalizeDigitsOnly(String number) { 727f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia return normalizeDigits(number, false /* strip non-digits */).toString(); 728f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia } 729f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia 730b210e301245cb5dc90aa3142f378632bd41cb172Shaopeng Jia static StringBuilder normalizeDigits(String number, boolean keepNonDigits) { 731f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia StringBuilder normalizedDigits = new StringBuilder(number.length()); 732f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia for (char c : number.toCharArray()) { 733f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia int digit = Character.digit(c, 10); 734f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia if (digit != -1) { 735f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia normalizedDigits.append(digit); 736f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia } else if (keepNonDigits) { 737f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia normalizedDigits.append(c); 738d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia } 739d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia } 740f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia return normalizedDigits; 7411524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } 7421524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia 7431524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia /** 7441524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * Converts all alpha characters in a number to their respective digits on a keypad, but retains 745d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia * existing formatting. 7461524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia */ 7471524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia public static String convertAlphaCharactersInNumber(String number) { 748d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia return normalizeHelper(number, ALPHA_PHONE_MAPPINGS, false); 7491524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } 7501524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia 7511524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia /** 752b210e301245cb5dc90aa3142f378632bd41cb172Shaopeng Jia * Gets the length of the geographical area code from the {@code nationalNumber_} field of the 753372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * PhoneNumber object passed in, so that clients could use it to split a national significant 754372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * number into geographical area code and subscriber number. It works in such a way that the 755372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * resultant subscriber number should be diallable, at least on some devices. An example of how 756372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * this could be used: 7575c24149d269da6e7d7b6b2797df096fdea64a019Shaopeng Jia * 758372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * <pre> 759df19cbfb8a1e8720bae76bb763ab29622e057c42Shaopeng Jia * PhoneNumberUtil phoneUtil = PhoneNumberUtil.getInstance(); 760b2697412130f6d087dde01fb1a978f7e5840a5faShaopeng Jia * PhoneNumber number = phoneUtil.parse("16502530000", "US"); 761372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * String nationalSignificantNumber = phoneUtil.getNationalSignificantNumber(number); 7625c24149d269da6e7d7b6b2797df096fdea64a019Shaopeng Jia * String areaCode; 7635c24149d269da6e7d7b6b2797df096fdea64a019Shaopeng Jia * String subscriberNumber; 7645c24149d269da6e7d7b6b2797df096fdea64a019Shaopeng Jia * 7655c24149d269da6e7d7b6b2797df096fdea64a019Shaopeng Jia * int areaCodeLength = phoneUtil.getLengthOfGeographicalAreaCode(number); 7665c24149d269da6e7d7b6b2797df096fdea64a019Shaopeng Jia * if (areaCodeLength > 0) { 7675c24149d269da6e7d7b6b2797df096fdea64a019Shaopeng Jia * areaCode = nationalSignificantNumber.substring(0, areaCodeLength); 7685c24149d269da6e7d7b6b2797df096fdea64a019Shaopeng Jia * subscriberNumber = nationalSignificantNumber.substring(areaCodeLength); 7695c24149d269da6e7d7b6b2797df096fdea64a019Shaopeng Jia * } else { 7705c24149d269da6e7d7b6b2797df096fdea64a019Shaopeng Jia * areaCode = ""; 7715c24149d269da6e7d7b6b2797df096fdea64a019Shaopeng Jia * subscriberNumber = nationalSignificantNumber; 7725c24149d269da6e7d7b6b2797df096fdea64a019Shaopeng Jia * } 773372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * </pre> 7745c24149d269da6e7d7b6b2797df096fdea64a019Shaopeng Jia * 7755c24149d269da6e7d7b6b2797df096fdea64a019Shaopeng Jia * N.B.: area code is a very ambiguous concept, so the I18N team generally recommends against 776d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia * using it for most purposes, but recommends using the more general {@code national_number} 777d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia * instead. Read the following carefully before deciding to use this method: 778d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia * <ul> 779d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia * <li> geographical area codes change over time, and this method honors those changes; 780d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia * therefore, it doesn't guarantee the stability of the result it produces. 781d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia * <li> subscriber numbers may not be diallable from all devices (notably mobile devices, which 782d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia * typically requires the full national_number to be dialled in most regions). 783528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia * <li> most non-geographical numbers have no area codes, including numbers from non-geographical 784528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia * entities 785d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia * <li> some geographical numbers have no area codes. 786d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia * </ul> 7875c24149d269da6e7d7b6b2797df096fdea64a019Shaopeng Jia * @param number the PhoneNumber object for which clients want to know the length of the area 78852699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia * code. 7895c24149d269da6e7d7b6b2797df096fdea64a019Shaopeng Jia * @return the length of area code of the PhoneNumber object passed in. 7905c24149d269da6e7d7b6b2797df096fdea64a019Shaopeng Jia */ 7915c24149d269da6e7d7b6b2797df096fdea64a019Shaopeng Jia public int getLengthOfGeographicalAreaCode(PhoneNumber number) { 792203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia PhoneMetadata metadata = getMetadataForRegion(getRegionCodeForNumber(number)); 793203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia if (metadata == null) { 7945c24149d269da6e7d7b6b2797df096fdea64a019Shaopeng Jia return 0; 7955c24149d269da6e7d7b6b2797df096fdea64a019Shaopeng Jia } 796b210e301245cb5dc90aa3142f378632bd41cb172Shaopeng Jia // If a country doesn't use a national prefix, and this number doesn't have an Italian leading 797b210e301245cb5dc90aa3142f378632bd41cb172Shaopeng Jia // zero, we assume it is a closed dialling plan with no area codes. 798b210e301245cb5dc90aa3142f378632bd41cb172Shaopeng Jia if (!metadata.hasNationalPrefix() && !number.isItalianLeadingZero()) { 7995c24149d269da6e7d7b6b2797df096fdea64a019Shaopeng Jia return 0; 8005c24149d269da6e7d7b6b2797df096fdea64a019Shaopeng Jia } 8015c24149d269da6e7d7b6b2797df096fdea64a019Shaopeng Jia 802203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia if (!isNumberGeographical(number)) { 8035c24149d269da6e7d7b6b2797df096fdea64a019Shaopeng Jia return 0; 8045c24149d269da6e7d7b6b2797df096fdea64a019Shaopeng Jia } 8055c24149d269da6e7d7b6b2797df096fdea64a019Shaopeng Jia 80674aa862e30b4d1b2722e90b1a8684274441a7541Shaopeng Jia return getLengthOfNationalDestinationCode(number); 80774aa862e30b4d1b2722e90b1a8684274441a7541Shaopeng Jia } 80874aa862e30b4d1b2722e90b1a8684274441a7541Shaopeng Jia 80974aa862e30b4d1b2722e90b1a8684274441a7541Shaopeng Jia /** 81074aa862e30b4d1b2722e90b1a8684274441a7541Shaopeng Jia * Gets the length of the national destination code (NDC) from the PhoneNumber object passed in, 81174aa862e30b4d1b2722e90b1a8684274441a7541Shaopeng Jia * so that clients could use it to split a national significant number into NDC and subscriber 81274aa862e30b4d1b2722e90b1a8684274441a7541Shaopeng Jia * number. The NDC of a phone number is normally the first group of digit(s) right after the 813372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * country calling code when the number is formatted in the international format, if there is a 814372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * subscriber number part that follows. An example of how this could be used: 81574aa862e30b4d1b2722e90b1a8684274441a7541Shaopeng Jia * 816372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * <pre> 81774aa862e30b4d1b2722e90b1a8684274441a7541Shaopeng Jia * PhoneNumberUtil phoneUtil = PhoneNumberUtil.getInstance(); 81874aa862e30b4d1b2722e90b1a8684274441a7541Shaopeng Jia * PhoneNumber number = phoneUtil.parse("18002530000", "US"); 819372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * String nationalSignificantNumber = phoneUtil.getNationalSignificantNumber(number); 82074aa862e30b4d1b2722e90b1a8684274441a7541Shaopeng Jia * String nationalDestinationCode; 82174aa862e30b4d1b2722e90b1a8684274441a7541Shaopeng Jia * String subscriberNumber; 82274aa862e30b4d1b2722e90b1a8684274441a7541Shaopeng Jia * 82374aa862e30b4d1b2722e90b1a8684274441a7541Shaopeng Jia * int nationalDestinationCodeLength = phoneUtil.getLengthOfNationalDestinationCode(number); 82474aa862e30b4d1b2722e90b1a8684274441a7541Shaopeng Jia * if (nationalDestinationCodeLength > 0) { 82574aa862e30b4d1b2722e90b1a8684274441a7541Shaopeng Jia * nationalDestinationCode = nationalSignificantNumber.substring(0, 82674aa862e30b4d1b2722e90b1a8684274441a7541Shaopeng Jia * nationalDestinationCodeLength); 82774aa862e30b4d1b2722e90b1a8684274441a7541Shaopeng Jia * subscriberNumber = nationalSignificantNumber.substring(nationalDestinationCodeLength); 82874aa862e30b4d1b2722e90b1a8684274441a7541Shaopeng Jia * } else { 82974aa862e30b4d1b2722e90b1a8684274441a7541Shaopeng Jia * nationalDestinationCode = ""; 83074aa862e30b4d1b2722e90b1a8684274441a7541Shaopeng Jia * subscriberNumber = nationalSignificantNumber; 83174aa862e30b4d1b2722e90b1a8684274441a7541Shaopeng Jia * } 832372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * </pre> 83374aa862e30b4d1b2722e90b1a8684274441a7541Shaopeng Jia * 83474aa862e30b4d1b2722e90b1a8684274441a7541Shaopeng Jia * Refer to the unittests to see the difference between this function and 835d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia * {@link #getLengthOfGeographicalAreaCode}. 83674aa862e30b4d1b2722e90b1a8684274441a7541Shaopeng Jia * 83774aa862e30b4d1b2722e90b1a8684274441a7541Shaopeng Jia * @param number the PhoneNumber object for which clients want to know the length of the NDC. 83874aa862e30b4d1b2722e90b1a8684274441a7541Shaopeng Jia * @return the length of NDC of the PhoneNumber object passed in. 83974aa862e30b4d1b2722e90b1a8684274441a7541Shaopeng Jia */ 84074aa862e30b4d1b2722e90b1a8684274441a7541Shaopeng Jia public int getLengthOfNationalDestinationCode(PhoneNumber number) { 8415c24149d269da6e7d7b6b2797df096fdea64a019Shaopeng Jia PhoneNumber copiedProto; 8425c24149d269da6e7d7b6b2797df096fdea64a019Shaopeng Jia if (number.hasExtension()) { 8435c24149d269da6e7d7b6b2797df096fdea64a019Shaopeng Jia // We don't want to alter the proto given to us, but we don't want to include the extension 8445c24149d269da6e7d7b6b2797df096fdea64a019Shaopeng Jia // when we format it, so we copy it and clear the extension here. 84576f6569af0619d12afd19991d8ff69a9bea4c142Shaopeng Jia copiedProto = new PhoneNumber(); 84676f6569af0619d12afd19991d8ff69a9bea4c142Shaopeng Jia copiedProto.mergeFrom(number); 84776f6569af0619d12afd19991d8ff69a9bea4c142Shaopeng Jia copiedProto.clearExtension(); 8485c24149d269da6e7d7b6b2797df096fdea64a019Shaopeng Jia } else { 8495c24149d269da6e7d7b6b2797df096fdea64a019Shaopeng Jia copiedProto = number; 8505c24149d269da6e7d7b6b2797df096fdea64a019Shaopeng Jia } 8515c24149d269da6e7d7b6b2797df096fdea64a019Shaopeng Jia 8525c24149d269da6e7d7b6b2797df096fdea64a019Shaopeng Jia String nationalSignificantNumber = format(copiedProto, 8535c24149d269da6e7d7b6b2797df096fdea64a019Shaopeng Jia PhoneNumberUtil.PhoneNumberFormat.INTERNATIONAL); 854f59ccfca9dd02c4e3cf3e06b5cf184a8d0e67626Shaopeng Jia String[] numberGroups = NON_DIGITS_PATTERN.split(nationalSignificantNumber); 8555c24149d269da6e7d7b6b2797df096fdea64a019Shaopeng Jia // The pattern will start with "+COUNTRY_CODE " so the first group will always be the empty 856372bff8dd464574d36737d47e495cad14346653cShaopeng Jia // string (before the + symbol) and the second group will be the country calling code. The third 857372bff8dd464574d36737d47e495cad14346653cShaopeng Jia // group will be area code if it is not the last group. 8585c24149d269da6e7d7b6b2797df096fdea64a019Shaopeng Jia if (numberGroups.length <= 3) { 8595c24149d269da6e7d7b6b2797df096fdea64a019Shaopeng Jia return 0; 8605c24149d269da6e7d7b6b2797df096fdea64a019Shaopeng Jia } 86174aa862e30b4d1b2722e90b1a8684274441a7541Shaopeng Jia 862a48b2d221ba46df7446d1a87244efa985e8e292fShaopeng Jia if (getRegionCodeForCountryCode(number.getCountryCode()).equals("AR") && 86374aa862e30b4d1b2722e90b1a8684274441a7541Shaopeng Jia getNumberType(number) == PhoneNumberType.MOBILE) { 86474aa862e30b4d1b2722e90b1a8684274441a7541Shaopeng Jia // Argentinian mobile numbers, when formatted in the international format, are in the form of 86574aa862e30b4d1b2722e90b1a8684274441a7541Shaopeng Jia // +54 9 NDC XXXX.... As a result, we take the length of the third group (NDC) and add 1 for 86674aa862e30b4d1b2722e90b1a8684274441a7541Shaopeng Jia // the digit 9, which also forms part of the national significant number. 86774aa862e30b4d1b2722e90b1a8684274441a7541Shaopeng Jia // 86874aa862e30b4d1b2722e90b1a8684274441a7541Shaopeng Jia // TODO: Investigate the possibility of better modeling the metadata to make it 86974aa862e30b4d1b2722e90b1a8684274441a7541Shaopeng Jia // easier to obtain the NDC. 87074aa862e30b4d1b2722e90b1a8684274441a7541Shaopeng Jia return numberGroups[3].length() + 1; 87174aa862e30b4d1b2722e90b1a8684274441a7541Shaopeng Jia } 8725c24149d269da6e7d7b6b2797df096fdea64a019Shaopeng Jia return numberGroups[2].length(); 873df19cbfb8a1e8720bae76bb763ab29622e057c42Shaopeng Jia } 8745c24149d269da6e7d7b6b2797df096fdea64a019Shaopeng Jia 8755c24149d269da6e7d7b6b2797df096fdea64a019Shaopeng Jia /** 8761524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * Normalizes a string of characters representing a phone number by replacing all characters found 8771524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * in the accompanying map with the values therein, and stripping all other characters if 8781524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * removeNonMatches is true. 8791524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * 8801524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * @param number a string of characters representing a phone number 8811524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * @param normalizationReplacements a mapping of characters to what they should be replaced by in 8821524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * the normalized version of the phone number 8831524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * @param removeNonMatches indicates whether characters that are not able to be replaced 8841524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * should be stripped from the number. If this is false, they 8851524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * will be left unchanged in the number. 8865c24149d269da6e7d7b6b2797df096fdea64a019Shaopeng Jia * @return the normalized string version of the phone number 8871524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia */ 888f59ccfca9dd02c4e3cf3e06b5cf184a8d0e67626Shaopeng Jia private static String normalizeHelper(String number, 889f59ccfca9dd02c4e3cf3e06b5cf184a8d0e67626Shaopeng Jia Map<Character, Character> normalizationReplacements, 890f59ccfca9dd02c4e3cf3e06b5cf184a8d0e67626Shaopeng Jia boolean removeNonMatches) { 891372bff8dd464574d36737d47e495cad14346653cShaopeng Jia StringBuilder normalizedNumber = new StringBuilder(number.length()); 892203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia for (int i = 0; i < number.length(); i++) { 893203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia char character = number.charAt(i); 8941524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia Character newDigit = normalizationReplacements.get(Character.toUpperCase(character)); 8951524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia if (newDigit != null) { 8961524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia normalizedNumber.append(newDigit); 8971524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } else if (!removeNonMatches) { 8981524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia normalizedNumber.append(character); 8991524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } 9001524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia // If neither of the above are true, we remove this character. 9011524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } 9021524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia return normalizedNumber.toString(); 9031524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } 9041524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia 905cc0ae7326023c5da91dd9a84035c3dc3f6cc372fShaopeng Jia // @VisibleForTesting 906fa42140081949568565af7dc8c22f0600ad90a8aShaopeng Jia static synchronized PhoneNumberUtil getInstance( 907fa42140081949568565af7dc8c22f0600ad90a8aShaopeng Jia String baseFileLocation, 908372bff8dd464574d36737d47e495cad14346653cShaopeng Jia Map<Integer, List<String>> countryCallingCodeToRegionCodeMap) { 9091524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia if (instance == null) { 9101524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia instance = new PhoneNumberUtil(); 911372bff8dd464574d36737d47e495cad14346653cShaopeng Jia instance.countryCallingCodeToRegionCodeMap = countryCallingCodeToRegionCodeMap; 912fa42140081949568565af7dc8c22f0600ad90a8aShaopeng Jia instance.init(baseFileLocation); 9131524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } 9141524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia return instance; 9151524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } 9161524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia 9171524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia /** 9181524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * Used for testing purposes only to reset the PhoneNumberUtil singleton to null. 9191524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia */ 920528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia // @VisibleForTesting 9211524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia static synchronized void resetInstance() { 9221524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia instance = null; 9231524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } 9241524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia 9251524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia /** 926ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia * Convenience method to get a list of what regions the library has metadata for. 9271524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia */ 928372bff8dd464574d36737d47e495cad14346653cShaopeng Jia public Set<String> getSupportedRegions() { 929203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia return Collections.unmodifiableSet(supportedRegions); 9301524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } 9311524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia 9321524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia /** 933cc0ae7326023c5da91dd9a84035c3dc3f6cc372fShaopeng Jia * Convenience method to get a list of what global network calling codes the library has metadata 934cc0ae7326023c5da91dd9a84035c3dc3f6cc372fShaopeng Jia * for. 935cc0ae7326023c5da91dd9a84035c3dc3f6cc372fShaopeng Jia */ 936cc0ae7326023c5da91dd9a84035c3dc3f6cc372fShaopeng Jia public Set<Integer> getSupportedGlobalNetworkCallingCodes() { 937203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia return Collections.unmodifiableSet(countryCodesForNonGeographicalRegion); 938cc0ae7326023c5da91dd9a84035c3dc3f6cc372fShaopeng Jia } 939cc0ae7326023c5da91dd9a84035c3dc3f6cc372fShaopeng Jia 940cc0ae7326023c5da91dd9a84035c3dc3f6cc372fShaopeng Jia /** 941372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * Gets a {@link PhoneNumberUtil} instance to carry out international phone number formatting, 942372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * parsing, or validation. The instance is loaded with phone number metadata for a number of most 943372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * commonly used regions. 9441524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * 945372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * <p>The {@link PhoneNumberUtil} is implemented as a singleton. Therefore, calling getInstance 946372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * multiple times will only result in one instance being created. 9471524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * 9481524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * @return a PhoneNumberUtil instance 9491524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia */ 9501524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia public static synchronized PhoneNumberUtil getInstance() { 9511524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia if (instance == null) { 952b2697412130f6d087dde01fb1a978f7e5840a5faShaopeng Jia return getInstance(META_DATA_FILE_PREFIX, 953b2697412130f6d087dde01fb1a978f7e5840a5faShaopeng Jia CountryCodeToRegionCodeMap.getCountryCodeToRegionCodeMap()); 9541524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } 9551524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia return instance; 9561524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } 9571524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia 9581524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia /** 959203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia * Helper function to check if the national prefix formatting rule has the first group only, i.e., 960203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia * does not start with the national prefix. 961203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia */ 962203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia static boolean formattingRuleHasFirstGroupOnly(String nationalPrefixFormattingRule) { 963203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia return FIRST_GROUP_ONLY_PREFIX_PATTERN.matcher(nationalPrefixFormattingRule).matches(); 964203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia } 965203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia 966203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia /** 967203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia * Tests whether a phone number has a geographical association. It checks if the number is 968203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia * associated to a certain region in the country where it belongs to. Note that this doesn't 969203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia * verify if the number is actually in use. 970203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia */ 971203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia boolean isNumberGeographical(PhoneNumber phoneNumber) { 972203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia PhoneNumberType numberType = getNumberType(phoneNumber); 973203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia // TODO: Include mobile phone numbers from countries like Indonesia, which has some 974203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia // mobile numbers that are geographical. 975203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia return numberType == PhoneNumberType.FIXED_LINE || 976203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia numberType == PhoneNumberType.FIXED_LINE_OR_MOBILE; 977203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia } 978203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia 979203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia /** 980be1af2f8b62d5435eca48f3dd5c82e3d2c9bfa17Shaopeng Jia * Helper function to check region code is not unknown or null. 9811524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia */ 982be1af2f8b62d5435eca48f3dd5c82e3d2c9bfa17Shaopeng Jia private boolean isValidRegionCode(String regionCode) { 983d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia return regionCode != null && supportedRegions.contains(regionCode); 984372bff8dd464574d36737d47e495cad14346653cShaopeng Jia } 985372bff8dd464574d36737d47e495cad14346653cShaopeng Jia 986372bff8dd464574d36737d47e495cad14346653cShaopeng Jia /** 987528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia * Helper function to check the country calling code is valid. 988372bff8dd464574d36737d47e495cad14346653cShaopeng Jia */ 989528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia private boolean hasValidCountryCallingCode(int countryCallingCode) { 990528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia return countryCallingCodeToRegionCodeMap.containsKey(countryCallingCode); 9911524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } 9921524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia 9931524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia /** 9941524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * Formats a phone number in the specified format using default rules. Note that this does not 9951524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * promise to produce a phone number that the user can dial from where they are - although we do 9961524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * format in either 'national' or 'international' format depending on what the client asks for, we 9971524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * do not currently support a more abbreviated format, such as for users in the same "area" who 9981524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * could potentially dial the number without area code. Note that if the phone number has a 999372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * country calling code of 0 or an otherwise invalid country calling code, we cannot work out 1000372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * which formatting rules to apply so we return the national significant number with no formatting 1001372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * applied. 10021524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * 10031524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * @param number the phone number to be formatted 10041524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * @param numberFormat the format the phone number should be formatted into 10055c24149d269da6e7d7b6b2797df096fdea64a019Shaopeng Jia * @return the formatted phone number 10061524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia */ 10071524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia public String format(PhoneNumber number, PhoneNumberFormat numberFormat) { 1008082e1e80b0bcb2911de5d26981b592f2c2b9d3f6Shaopeng Jia if (number.getNationalNumber() == 0 && number.hasRawInput()) { 1009203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia // Unparseable numbers that kept their raw input just use that. 1010203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia // This is the only case where a number can be formatted as E164 without a 1011203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia // leading '+' symbol (but the original number wasn't parseable anyway). 1012203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia // TODO: Consider removing the 'if' above so that unparseable 1013203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia // strings without raw input format to the empty string instead of "+00" 1014082e1e80b0bcb2911de5d26981b592f2c2b9d3f6Shaopeng Jia String rawInput = number.getRawInput(); 1015082e1e80b0bcb2911de5d26981b592f2c2b9d3f6Shaopeng Jia if (rawInput.length() > 0) { 1016082e1e80b0bcb2911de5d26981b592f2c2b9d3f6Shaopeng Jia return rawInput; 1017082e1e80b0bcb2911de5d26981b592f2c2b9d3f6Shaopeng Jia } 1018082e1e80b0bcb2911de5d26981b592f2c2b9d3f6Shaopeng Jia } 1019372bff8dd464574d36737d47e495cad14346653cShaopeng Jia StringBuilder formattedNumber = new StringBuilder(20); 102076f6569af0619d12afd19991d8ff69a9bea4c142Shaopeng Jia format(number, numberFormat, formattedNumber); 1021be1af2f8b62d5435eca48f3dd5c82e3d2c9bfa17Shaopeng Jia return formattedNumber.toString(); 1022be1af2f8b62d5435eca48f3dd5c82e3d2c9bfa17Shaopeng Jia } 1023be1af2f8b62d5435eca48f3dd5c82e3d2c9bfa17Shaopeng Jia 1024d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia /** 102596a7214cdabf08f53f5b1a560304601c9f65e0b9Shaopeng Jia * Same as {@link #format(PhoneNumber, PhoneNumberFormat)}, but accepts a mutable StringBuilder as 102696a7214cdabf08f53f5b1a560304601c9f65e0b9Shaopeng Jia * a parameter to decrease object creation when invoked many times. 1027d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia */ 102876f6569af0619d12afd19991d8ff69a9bea4c142Shaopeng Jia public void format(PhoneNumber number, PhoneNumberFormat numberFormat, 1029372bff8dd464574d36737d47e495cad14346653cShaopeng Jia StringBuilder formattedNumber) { 1030372bff8dd464574d36737d47e495cad14346653cShaopeng Jia // Clear the StringBuilder first. 1031be1af2f8b62d5435eca48f3dd5c82e3d2c9bfa17Shaopeng Jia formattedNumber.setLength(0); 1032d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia int countryCallingCode = number.getCountryCode(); 10335c24149d269da6e7d7b6b2797df096fdea64a019Shaopeng Jia String nationalSignificantNumber = getNationalSignificantNumber(number); 10341524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia if (numberFormat == PhoneNumberFormat.E164) { 1035203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia // Early exit for E164 case (even if the country calling code is invalid) since no formatting 1036203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia // of the national number needs to be applied. Extensions are not formatted. 1037be1af2f8b62d5435eca48f3dd5c82e3d2c9bfa17Shaopeng Jia formattedNumber.append(nationalSignificantNumber); 1038cc0ae7326023c5da91dd9a84035c3dc3f6cc372fShaopeng Jia prefixNumberWithCountryCallingCode(countryCallingCode, PhoneNumberFormat.E164, 1039cc0ae7326023c5da91dd9a84035c3dc3f6cc372fShaopeng Jia formattedNumber); 1040be1af2f8b62d5435eca48f3dd5c82e3d2c9bfa17Shaopeng Jia return; 10411524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } 1042cc0ae7326023c5da91dd9a84035c3dc3f6cc372fShaopeng Jia if (!hasValidCountryCallingCode(countryCallingCode)) { 1043be1af2f8b62d5435eca48f3dd5c82e3d2c9bfa17Shaopeng Jia formattedNumber.append(nationalSignificantNumber); 1044be1af2f8b62d5435eca48f3dd5c82e3d2c9bfa17Shaopeng Jia return; 10451524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } 1046203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia // Note getRegionCodeForCountryCode() is used because formatting information for regions which 1047203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia // share a country calling code is contained by only one region for performance reasons. For 1048203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia // example, for NANPA regions it will be contained in the metadata for US. 1049203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia String regionCode = getRegionCodeForCountryCode(countryCallingCode); 1050203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia // Metadata cannot be null because the country calling code is valid (which means that the 1051203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia // region code cannot be ZZ and must be one of our supported region codes). 1052528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia PhoneMetadata metadata = 1053528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia getMetadataForRegionOrCallingCode(countryCallingCode, regionCode); 1054cc0ae7326023c5da91dd9a84035c3dc3f6cc372fShaopeng Jia formattedNumber.append(formatNsn(nationalSignificantNumber, metadata, numberFormat)); 1055cc0ae7326023c5da91dd9a84035c3dc3f6cc372fShaopeng Jia maybeAppendFormattedExtension(number, metadata, numberFormat, formattedNumber); 1056cc0ae7326023c5da91dd9a84035c3dc3f6cc372fShaopeng Jia prefixNumberWithCountryCallingCode(countryCallingCode, numberFormat, formattedNumber); 10571524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } 10581524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia 10591524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia /** 10601524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * Formats a phone number in the specified format using client-defined formatting rules. Note that 1061372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * if the phone number has a country calling code of zero or an otherwise invalid country calling 1062372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * code, we cannot work out things like whether there should be a national prefix applied, or how 1063372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * to format extensions, so we return the national significant number with no formatting applied. 10641524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * 10651524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * @param number the phone number to be formatted 10661524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * @param numberFormat the format the phone number should be formatted into 10671524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * @param userDefinedFormats formatting rules specified by clients 10685c24149d269da6e7d7b6b2797df096fdea64a019Shaopeng Jia * @return the formatted phone number 10691524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia */ 10701524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia public String formatByPattern(PhoneNumber number, 10711524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia PhoneNumberFormat numberFormat, 10721524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia List<NumberFormat> userDefinedFormats) { 1073372bff8dd464574d36737d47e495cad14346653cShaopeng Jia int countryCallingCode = number.getCountryCode(); 10744b7846722d1a5acb0577b07e98324f744f5e7942Shaopeng Jia String nationalSignificantNumber = getNationalSignificantNumber(number); 1075203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia if (!hasValidCountryCallingCode(countryCallingCode)) { 1076203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia return nationalSignificantNumber; 1077203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia } 1078372bff8dd464574d36737d47e495cad14346653cShaopeng Jia // Note getRegionCodeForCountryCode() is used because formatting information for regions which 1079372bff8dd464574d36737d47e495cad14346653cShaopeng Jia // share a country calling code is contained by only one region for performance reasons. For 1080372bff8dd464574d36737d47e495cad14346653cShaopeng Jia // example, for NANPA regions it will be contained in the metadata for US. 1081372bff8dd464574d36737d47e495cad14346653cShaopeng Jia String regionCode = getRegionCodeForCountryCode(countryCallingCode); 1082203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia // Metadata cannot be null because the country calling code is valid 1083528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia PhoneMetadata metadata = 1084528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia getMetadataForRegionOrCallingCode(countryCallingCode, regionCode); 1085cc0ae7326023c5da91dd9a84035c3dc3f6cc372fShaopeng Jia 1086cc0ae7326023c5da91dd9a84035c3dc3f6cc372fShaopeng Jia StringBuilder formattedNumber = new StringBuilder(20); 1087cc0ae7326023c5da91dd9a84035c3dc3f6cc372fShaopeng Jia 1088cc0ae7326023c5da91dd9a84035c3dc3f6cc372fShaopeng Jia NumberFormat formattingPattern = 1089cc0ae7326023c5da91dd9a84035c3dc3f6cc372fShaopeng Jia chooseFormattingPatternForNumber(userDefinedFormats, nationalSignificantNumber); 1090cc0ae7326023c5da91dd9a84035c3dc3f6cc372fShaopeng Jia if (formattingPattern == null) { 1091cc0ae7326023c5da91dd9a84035c3dc3f6cc372fShaopeng Jia // If no pattern above is matched, we format the number as a whole. 1092cc0ae7326023c5da91dd9a84035c3dc3f6cc372fShaopeng Jia formattedNumber.append(nationalSignificantNumber); 1093cc0ae7326023c5da91dd9a84035c3dc3f6cc372fShaopeng Jia } else { 1094cc0ae7326023c5da91dd9a84035c3dc3f6cc372fShaopeng Jia NumberFormat numFormatCopy = new NumberFormat(); 1095cc0ae7326023c5da91dd9a84035c3dc3f6cc372fShaopeng Jia // Before we do a replacement of the national prefix pattern $NP with the national prefix, we 1096cc0ae7326023c5da91dd9a84035c3dc3f6cc372fShaopeng Jia // need to copy the rule so that subsequent replacements for different numbers have the 1097cc0ae7326023c5da91dd9a84035c3dc3f6cc372fShaopeng Jia // appropriate national prefix. 1098cc0ae7326023c5da91dd9a84035c3dc3f6cc372fShaopeng Jia numFormatCopy.mergeFrom(formattingPattern); 1099cc0ae7326023c5da91dd9a84035c3dc3f6cc372fShaopeng Jia String nationalPrefixFormattingRule = formattingPattern.getNationalPrefixFormattingRule(); 11001524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia if (nationalPrefixFormattingRule.length() > 0) { 1101528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia String nationalPrefix = metadata.getNationalPrefix(); 1102f59ccfca9dd02c4e3cf3e06b5cf184a8d0e67626Shaopeng Jia if (nationalPrefix.length() > 0) { 1103df19cbfb8a1e8720bae76bb763ab29622e057c42Shaopeng Jia // Replace $NP with national prefix and $FG with the first group ($1). 1104df19cbfb8a1e8720bae76bb763ab29622e057c42Shaopeng Jia nationalPrefixFormattingRule = 1105df19cbfb8a1e8720bae76bb763ab29622e057c42Shaopeng Jia NP_PATTERN.matcher(nationalPrefixFormattingRule).replaceFirst(nationalPrefix); 1106df19cbfb8a1e8720bae76bb763ab29622e057c42Shaopeng Jia nationalPrefixFormattingRule = 1107df19cbfb8a1e8720bae76bb763ab29622e057c42Shaopeng Jia FG_PATTERN.matcher(nationalPrefixFormattingRule).replaceFirst("\\$1"); 1108df19cbfb8a1e8720bae76bb763ab29622e057c42Shaopeng Jia numFormatCopy.setNationalPrefixFormattingRule(nationalPrefixFormattingRule); 1109df19cbfb8a1e8720bae76bb763ab29622e057c42Shaopeng Jia } else { 1110df19cbfb8a1e8720bae76bb763ab29622e057c42Shaopeng Jia // We don't want to have a rule for how to format the national prefix if there isn't one. 1111df19cbfb8a1e8720bae76bb763ab29622e057c42Shaopeng Jia numFormatCopy.clearNationalPrefixFormattingRule(); 1112df19cbfb8a1e8720bae76bb763ab29622e057c42Shaopeng Jia } 11131524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } 1114cc0ae7326023c5da91dd9a84035c3dc3f6cc372fShaopeng Jia formattedNumber.append( 1115cc0ae7326023c5da91dd9a84035c3dc3f6cc372fShaopeng Jia formatNsnUsingPattern(nationalSignificantNumber, numFormatCopy, numberFormat)); 11161524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } 1117cc0ae7326023c5da91dd9a84035c3dc3f6cc372fShaopeng Jia maybeAppendFormattedExtension(number, metadata, numberFormat, formattedNumber); 1118cc0ae7326023c5da91dd9a84035c3dc3f6cc372fShaopeng Jia prefixNumberWithCountryCallingCode(countryCallingCode, numberFormat, formattedNumber); 1119be1af2f8b62d5435eca48f3dd5c82e3d2c9bfa17Shaopeng Jia return formattedNumber.toString(); 11201524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } 11211524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia 112252699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia /** 112352699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia * Formats a phone number in national format for dialing using the carrier as specified in the 1124372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * {@code carrierCode}. The {@code carrierCode} will always be used regardless of whether the 1125372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * phone number already has a preferred domestic carrier code stored. If {@code carrierCode} 1126372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * contains an empty string, returns the number in national format without any carrier code. 112752699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia * 112852699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia * @param number the phone number to be formatted 112952699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia * @param carrierCode the carrier selection code to be used 113052699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia * @return the formatted phone number in national format for dialing using the carrier as 1131372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * specified in the {@code carrierCode} 113252699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia */ 11334b7846722d1a5acb0577b07e98324f744f5e7942Shaopeng Jia public String formatNationalNumberWithCarrierCode(PhoneNumber number, String carrierCode) { 1134372bff8dd464574d36737d47e495cad14346653cShaopeng Jia int countryCallingCode = number.getCountryCode(); 11354b7846722d1a5acb0577b07e98324f744f5e7942Shaopeng Jia String nationalSignificantNumber = getNationalSignificantNumber(number); 1136203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia if (!hasValidCountryCallingCode(countryCallingCode)) { 1137203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia return nationalSignificantNumber; 1138203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia } 1139203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia 1140372bff8dd464574d36737d47e495cad14346653cShaopeng Jia // Note getRegionCodeForCountryCode() is used because formatting information for regions which 1141372bff8dd464574d36737d47e495cad14346653cShaopeng Jia // share a country calling code is contained by only one region for performance reasons. For 1142372bff8dd464574d36737d47e495cad14346653cShaopeng Jia // example, for NANPA regions it will be contained in the metadata for US. 1143372bff8dd464574d36737d47e495cad14346653cShaopeng Jia String regionCode = getRegionCodeForCountryCode(countryCallingCode); 1144203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia // Metadata cannot be null because the country calling code is valid. 1145203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia PhoneMetadata metadata = getMetadataForRegionOrCallingCode(countryCallingCode, regionCode); 11464b7846722d1a5acb0577b07e98324f744f5e7942Shaopeng Jia 1147372bff8dd464574d36737d47e495cad14346653cShaopeng Jia StringBuilder formattedNumber = new StringBuilder(20); 1148cc0ae7326023c5da91dd9a84035c3dc3f6cc372fShaopeng Jia formattedNumber.append(formatNsn(nationalSignificantNumber, metadata, 1149cc0ae7326023c5da91dd9a84035c3dc3f6cc372fShaopeng Jia PhoneNumberFormat.NATIONAL, carrierCode)); 1150cc0ae7326023c5da91dd9a84035c3dc3f6cc372fShaopeng Jia maybeAppendFormattedExtension(number, metadata, PhoneNumberFormat.NATIONAL, formattedNumber); 1151cc0ae7326023c5da91dd9a84035c3dc3f6cc372fShaopeng Jia prefixNumberWithCountryCallingCode(countryCallingCode, PhoneNumberFormat.NATIONAL, 1152cc0ae7326023c5da91dd9a84035c3dc3f6cc372fShaopeng Jia formattedNumber); 11534b7846722d1a5acb0577b07e98324f744f5e7942Shaopeng Jia return formattedNumber.toString(); 11544b7846722d1a5acb0577b07e98324f744f5e7942Shaopeng Jia } 11554b7846722d1a5acb0577b07e98324f744f5e7942Shaopeng Jia 1156528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia private PhoneMetadata getMetadataForRegionOrCallingCode( 1157528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia int countryCallingCode, String regionCode) { 1158528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia return REGION_CODE_FOR_NON_GEO_ENTITY.equals(regionCode) 1159528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia ? getMetadataForNonGeographicalRegion(countryCallingCode) 1160528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia : getMetadataForRegion(regionCode); 1161528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia } 1162528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia 11631524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia /** 116452699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia * Formats a phone number in national format for dialing using the carrier as specified in the 1165372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * preferredDomesticCarrierCode field of the PhoneNumber object passed in. If that is missing, 1166372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * use the {@code fallbackCarrierCode} passed in instead. If there is no 1167372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * {@code preferredDomesticCarrierCode}, and the {@code fallbackCarrierCode} contains an empty 1168372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * string, return the number in national format without any carrier code. 116952699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia * 1170372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * <p>Use {@link #formatNationalNumberWithCarrierCode} instead if the carrier code passed in 1171372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * should take precedence over the number's {@code preferredDomesticCarrierCode} when formatting. 117252699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia * 117352699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia * @param number the phone number to be formatted 117452699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia * @param fallbackCarrierCode the carrier selection code to be used, if none is found in the 1175372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * phone number itself 117652699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia * @return the formatted phone number in national format for dialing using the number's 1177372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * {@code preferredDomesticCarrierCode}, or the {@code fallbackCarrierCode} passed in if 1178372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * none is found 117952699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia */ 118052699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia public String formatNationalNumberWithPreferredCarrierCode(PhoneNumber number, 118152699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia String fallbackCarrierCode) { 118252699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia return formatNationalNumberWithCarrierCode(number, number.hasPreferredDomesticCarrierCode() 118352699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia ? number.getPreferredDomesticCarrierCode() 118452699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia : fallbackCarrierCode); 118552699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia } 118652699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia 118752699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia /** 1188ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia * Returns a number formatted in such a way that it can be dialed from a mobile phone in a 1189ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia * specific region. If the number cannot be reached from the region (e.g. some countries block 1190ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia * toll-free numbers from being called outside of the country), the method returns an empty 1191ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia * string. 1192ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia * 1193ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia * @param number the phone number to be formatted 1194ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia * @param regionCallingFrom the region where the call is being placed 1195ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia * @param withFormatting whether the number should be returned with formatting symbols, such as 1196ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia * spaces and dashes. 1197ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia * @return the formatted phone number 1198ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia */ 1199ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia public String formatNumberForMobileDialing(PhoneNumber number, String regionCallingFrom, 1200ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia boolean withFormatting) { 1201528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia int countryCallingCode = number.getCountryCode(); 1202528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia if (!hasValidCountryCallingCode(countryCallingCode)) { 1203ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia return number.hasRawInput() ? number.getRawInput() : ""; 1204ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia } 1205ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia 1206ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia String formattedNumber; 1207ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia // Clear the extension, as that part cannot normally be dialed together with the main number. 1208ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia PhoneNumber numberNoExt = new PhoneNumber().mergeFrom(number).clearExtension(); 1209ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia PhoneNumberType numberType = getNumberType(numberNoExt); 1210528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia String regionCode = getRegionCodeForCountryCode(countryCallingCode); 121196a7214cdabf08f53f5b1a560304601c9f65e0b9Shaopeng Jia if (regionCode.equals("CO") && regionCallingFrom.equals("CO")) { 121296a7214cdabf08f53f5b1a560304601c9f65e0b9Shaopeng Jia if (numberType == PhoneNumberType.FIXED_LINE) { 121396a7214cdabf08f53f5b1a560304601c9f65e0b9Shaopeng Jia formattedNumber = 121496a7214cdabf08f53f5b1a560304601c9f65e0b9Shaopeng Jia formatNationalNumberWithCarrierCode(numberNoExt, COLOMBIA_MOBILE_TO_FIXED_LINE_PREFIX); 121596a7214cdabf08f53f5b1a560304601c9f65e0b9Shaopeng Jia } else { 121696a7214cdabf08f53f5b1a560304601c9f65e0b9Shaopeng Jia // E164 doesn't work at all when dialing within Colombia. 121796a7214cdabf08f53f5b1a560304601c9f65e0b9Shaopeng Jia formattedNumber = format(numberNoExt, PhoneNumberFormat.NATIONAL); 121896a7214cdabf08f53f5b1a560304601c9f65e0b9Shaopeng Jia } 121996a7214cdabf08f53f5b1a560304601c9f65e0b9Shaopeng Jia } else if (regionCode.equals("PE") && regionCallingFrom.equals("PE")) { 122096a7214cdabf08f53f5b1a560304601c9f65e0b9Shaopeng Jia // In Peru, numbers cannot be dialled using E164 format from a mobile phone for Movistar. 122196a7214cdabf08f53f5b1a560304601c9f65e0b9Shaopeng Jia // Instead they must be dialled in national format. 122296a7214cdabf08f53f5b1a560304601c9f65e0b9Shaopeng Jia formattedNumber = format(numberNoExt, PhoneNumberFormat.NATIONAL); 122377aadd284847681bd66af639636c2fa43e418c2bShaopeng Jia } else if (regionCode.equals("AE") && regionCallingFrom.equals("AE") && 122477aadd284847681bd66af639636c2fa43e418c2bShaopeng Jia numberType == PhoneNumberType.UAN) { 122577aadd284847681bd66af639636c2fa43e418c2bShaopeng Jia // In the United Arab Emirates, numbers with the prefix 600 (UAN numbers) cannot be dialled 122677aadd284847681bd66af639636c2fa43e418c2bShaopeng Jia // using E164 format. Instead they must be dialled in national format. 122777aadd284847681bd66af639636c2fa43e418c2bShaopeng Jia formattedNumber = format(numberNoExt, PhoneNumberFormat.NATIONAL); 122896a7214cdabf08f53f5b1a560304601c9f65e0b9Shaopeng Jia } else if (regionCode.equals("BR") && regionCallingFrom.equals("BR") && 1229ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia ((numberType == PhoneNumberType.FIXED_LINE) || (numberType == PhoneNumberType.MOBILE) || 1230ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia (numberType == PhoneNumberType.FIXED_LINE_OR_MOBILE))) { 1231ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia formattedNumber = numberNoExt.hasPreferredDomesticCarrierCode() 1232ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia ? formatNationalNumberWithPreferredCarrierCode(numberNoExt, "") 1233ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia // Brazilian fixed line and mobile numbers need to be dialed with a carrier code when 1234ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia // called within Brazil. Without that, most of the carriers won't connect the call. 1235ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia // Because of that, we return an empty string here. 1236ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia : ""; 1237ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia } else if (canBeInternationallyDialled(numberNoExt)) { 1238ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia return withFormatting ? format(numberNoExt, PhoneNumberFormat.INTERNATIONAL) 1239ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia : format(numberNoExt, PhoneNumberFormat.E164); 1240ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia } else { 1241ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia formattedNumber = (regionCallingFrom.equals(regionCode)) 1242ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia ? format(numberNoExt, PhoneNumberFormat.NATIONAL) : ""; 1243ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia } 124496a7214cdabf08f53f5b1a560304601c9f65e0b9Shaopeng Jia return withFormatting ? formattedNumber 124596a7214cdabf08f53f5b1a560304601c9f65e0b9Shaopeng Jia : normalizeHelper(formattedNumber, DIALLABLE_CHAR_MAPPINGS, 124696a7214cdabf08f53f5b1a560304601c9f65e0b9Shaopeng Jia true /* remove non matches */); 1247ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia } 1248ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia 1249ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia /** 1250372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * Formats a phone number for out-of-country dialing purposes. If no regionCallingFrom is 1251372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * supplied, we format the number in its INTERNATIONAL format. If the country calling code is the 1252d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia * same as that of the region where the number is from, then NATIONAL formatting will be applied. 12531524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * 1254372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * <p>If the number itself has a country calling code of zero or an otherwise invalid country 1255372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * calling code, then we return the number with no formatting applied. 12561524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * 1257372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * <p>Note this function takes care of the case for calling inside of NANPA and between Russia and 1258372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * Kazakhstan (who share the same country calling code). In those cases, no international prefix 1259372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * is used. For regions which have multiple international prefixes, the number in its 1260372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * INTERNATIONAL format will be returned instead. 12611524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * 12621524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * @param number the phone number to be formatted 1263d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia * @param regionCallingFrom the region where the call is being placed 12645c24149d269da6e7d7b6b2797df096fdea64a019Shaopeng Jia * @return the formatted phone number 12651524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia */ 1266d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia public String formatOutOfCountryCallingNumber(PhoneNumber number, 1267d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia String regionCallingFrom) { 1268372bff8dd464574d36737d47e495cad14346653cShaopeng Jia if (!isValidRegionCode(regionCallingFrom)) { 1269cc0ae7326023c5da91dd9a84035c3dc3f6cc372fShaopeng Jia LOGGER.log(Level.WARNING, 1270cc0ae7326023c5da91dd9a84035c3dc3f6cc372fShaopeng Jia "Trying to format number from invalid region " 1271cc0ae7326023c5da91dd9a84035c3dc3f6cc372fShaopeng Jia + regionCallingFrom 1272cc0ae7326023c5da91dd9a84035c3dc3f6cc372fShaopeng Jia + ". International formatting applied."); 12731524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia return format(number, PhoneNumberFormat.INTERNATIONAL); 12741524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } 1275372bff8dd464574d36737d47e495cad14346653cShaopeng Jia int countryCallingCode = number.getCountryCode(); 12765c24149d269da6e7d7b6b2797df096fdea64a019Shaopeng Jia String nationalSignificantNumber = getNationalSignificantNumber(number); 1277528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia if (!hasValidCountryCallingCode(countryCallingCode)) { 12781524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia return nationalSignificantNumber; 12791524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } 1280372bff8dd464574d36737d47e495cad14346653cShaopeng Jia if (countryCallingCode == NANPA_COUNTRY_CODE) { 1281372bff8dd464574d36737d47e495cad14346653cShaopeng Jia if (isNANPACountry(regionCallingFrom)) { 1282372bff8dd464574d36737d47e495cad14346653cShaopeng Jia // For NANPA regions, return the national format for these regions but prefix it with the 1283372bff8dd464574d36737d47e495cad14346653cShaopeng Jia // country calling code. 1284372bff8dd464574d36737d47e495cad14346653cShaopeng Jia return countryCallingCode + " " + format(number, PhoneNumberFormat.NATIONAL); 12854b7846722d1a5acb0577b07e98324f744f5e7942Shaopeng Jia } 1286cc0ae7326023c5da91dd9a84035c3dc3f6cc372fShaopeng Jia } else if (countryCallingCode == getCountryCodeForValidRegion(regionCallingFrom)) { 128777aadd284847681bd66af639636c2fa43e418c2bShaopeng Jia // If regions share a country calling code, the country calling code need not be dialled. 128877aadd284847681bd66af639636c2fa43e418c2bShaopeng Jia // This also applies when dialling within a region, so this if clause covers both these cases. 128977aadd284847681bd66af639636c2fa43e418c2bShaopeng Jia // Technically this is the case for dialling from La Reunion to other overseas departments of 129077aadd284847681bd66af639636c2fa43e418c2bShaopeng Jia // France (French Guiana, Martinique, Guadeloupe), but not vice versa - so we don't cover this 129177aadd284847681bd66af639636c2fa43e418c2bShaopeng Jia // edge case for now and for those cases return the version including country calling code. 129277aadd284847681bd66af639636c2fa43e418c2bShaopeng Jia // Details here: http://www.petitfute.com/voyage/225-info-pratiques-reunion 12931524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia return format(number, PhoneNumberFormat.NATIONAL); 12941524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } 1295203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia // Metadata cannot be null because we checked 'isValidRegionCode()' above. 1296528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia PhoneMetadata metadataForRegionCallingFrom = getMetadataForRegion(regionCallingFrom); 1297528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia String internationalPrefix = metadataForRegionCallingFrom.getInternationalPrefix(); 1298be1af2f8b62d5435eca48f3dd5c82e3d2c9bfa17Shaopeng Jia 1299372bff8dd464574d36737d47e495cad14346653cShaopeng Jia // For regions that have multiple international prefixes, the international format of the 13001524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia // number is returned, unless there is a preferred international prefix. 13011524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia String internationalPrefixForFormatting = ""; 13021524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia if (UNIQUE_INTERNATIONAL_PREFIX.matcher(internationalPrefix).matches()) { 13031524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia internationalPrefixForFormatting = internationalPrefix; 1304528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia } else if (metadataForRegionCallingFrom.hasPreferredInternationalPrefix()) { 1305528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia internationalPrefixForFormatting = 1306528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia metadataForRegionCallingFrom.getPreferredInternationalPrefix(); 13071524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } 1308be1af2f8b62d5435eca48f3dd5c82e3d2c9bfa17Shaopeng Jia 1309528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia String regionCode = getRegionCodeForCountryCode(countryCallingCode); 1310203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia // Metadata cannot be null because the country calling code is valid. 1311528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia PhoneMetadata metadataForRegion = 1312528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia getMetadataForRegionOrCallingCode(countryCallingCode, regionCode); 1313528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia String formattedNationalNumber = 1314cc0ae7326023c5da91dd9a84035c3dc3f6cc372fShaopeng Jia formatNsn(nationalSignificantNumber, metadataForRegion, PhoneNumberFormat.INTERNATIONAL); 1315372bff8dd464574d36737d47e495cad14346653cShaopeng Jia StringBuilder formattedNumber = new StringBuilder(formattedNationalNumber); 1316cc0ae7326023c5da91dd9a84035c3dc3f6cc372fShaopeng Jia maybeAppendFormattedExtension(number, metadataForRegion, PhoneNumberFormat.INTERNATIONAL, 1317cc0ae7326023c5da91dd9a84035c3dc3f6cc372fShaopeng Jia formattedNumber); 1318be1af2f8b62d5435eca48f3dd5c82e3d2c9bfa17Shaopeng Jia if (internationalPrefixForFormatting.length() > 0) { 1319372bff8dd464574d36737d47e495cad14346653cShaopeng Jia formattedNumber.insert(0, " ").insert(0, countryCallingCode).insert(0, " ") 1320be1af2f8b62d5435eca48f3dd5c82e3d2c9bfa17Shaopeng Jia .insert(0, internationalPrefixForFormatting); 1321be1af2f8b62d5435eca48f3dd5c82e3d2c9bfa17Shaopeng Jia } else { 1322cc0ae7326023c5da91dd9a84035c3dc3f6cc372fShaopeng Jia prefixNumberWithCountryCallingCode(countryCallingCode, 1323cc0ae7326023c5da91dd9a84035c3dc3f6cc372fShaopeng Jia PhoneNumberFormat.INTERNATIONAL, 1324cc0ae7326023c5da91dd9a84035c3dc3f6cc372fShaopeng Jia formattedNumber); 1325be1af2f8b62d5435eca48f3dd5c82e3d2c9bfa17Shaopeng Jia } 1326be1af2f8b62d5435eca48f3dd5c82e3d2c9bfa17Shaopeng Jia return formattedNumber.toString(); 13271524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } 13281524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia 132954923fc72f0faeb11fe58a545c0314f6051b14aaShaopeng Jia /** 133054923fc72f0faeb11fe58a545c0314f6051b14aaShaopeng Jia * Formats a phone number using the original phone number format that the number is parsed from. 133154923fc72f0faeb11fe58a545c0314f6051b14aaShaopeng Jia * The original format is embedded in the country_code_source field of the PhoneNumber object 133254923fc72f0faeb11fe58a545c0314f6051b14aaShaopeng Jia * passed in. If such information is missing, the number will be formatted into the NATIONAL 1333528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia * format by default. When the number contains a leading zero and this is unexpected for this 1334528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia * country, or we don't have a formatting pattern for the number, the method returns the raw input 1335528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia * when it is available. 133654923fc72f0faeb11fe58a545c0314f6051b14aaShaopeng Jia * 1337528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia * Note this method guarantees no digit will be inserted, removed or modified as a result of 1338528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia * formatting. 1339cc0ae7326023c5da91dd9a84035c3dc3f6cc372fShaopeng Jia * 1340372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * @param number the phone number that needs to be formatted in its original number format 1341372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * @param regionCallingFrom the region whose IDD needs to be prefixed if the original number 13424b7846722d1a5acb0577b07e98324f744f5e7942Shaopeng Jia * has one 13434b7846722d1a5acb0577b07e98324f744f5e7942Shaopeng Jia * @return the formatted phone number in its original number format 134454923fc72f0faeb11fe58a545c0314f6051b14aaShaopeng Jia */ 1345372bff8dd464574d36737d47e495cad14346653cShaopeng Jia public String formatInOriginalFormat(PhoneNumber number, String regionCallingFrom) { 13465cd062f9cba053c771bcea181fec210279ec030bShaopeng Jia if (number.hasRawInput() && 1347528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia (hasUnexpectedItalianLeadingZero(number) || !hasFormattingPatternForNumber(number))) { 13485cd062f9cba053c771bcea181fec210279ec030bShaopeng Jia // We check if we have the formatting pattern because without that, we might format the number 1349528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia // as a group without national prefix. 13501940212be2ff2ac5bf7d91eabbdb34e10d9b8e2eShaopeng Jia return number.getRawInput(); 13511940212be2ff2ac5bf7d91eabbdb34e10d9b8e2eShaopeng Jia } 13524b7846722d1a5acb0577b07e98324f744f5e7942Shaopeng Jia if (!number.hasCountryCodeSource()) { 135354923fc72f0faeb11fe58a545c0314f6051b14aaShaopeng Jia return format(number, PhoneNumberFormat.NATIONAL); 135454923fc72f0faeb11fe58a545c0314f6051b14aaShaopeng Jia } 1355d470984844c388d6766c3de6ac64e93e00480fc9Flavio Lerda String formattedNumber; 135654923fc72f0faeb11fe58a545c0314f6051b14aaShaopeng Jia switch (number.getCountryCodeSource()) { 135754923fc72f0faeb11fe58a545c0314f6051b14aaShaopeng Jia case FROM_NUMBER_WITH_PLUS_SIGN: 1358d470984844c388d6766c3de6ac64e93e00480fc9Flavio Lerda formattedNumber = format(number, PhoneNumberFormat.INTERNATIONAL); 1359d470984844c388d6766c3de6ac64e93e00480fc9Flavio Lerda break; 136054923fc72f0faeb11fe58a545c0314f6051b14aaShaopeng Jia case FROM_NUMBER_WITH_IDD: 1361d470984844c388d6766c3de6ac64e93e00480fc9Flavio Lerda formattedNumber = formatOutOfCountryCallingNumber(number, regionCallingFrom); 1362d470984844c388d6766c3de6ac64e93e00480fc9Flavio Lerda break; 136354923fc72f0faeb11fe58a545c0314f6051b14aaShaopeng Jia case FROM_NUMBER_WITHOUT_PLUS_SIGN: 1364d470984844c388d6766c3de6ac64e93e00480fc9Flavio Lerda formattedNumber = format(number, PhoneNumberFormat.INTERNATIONAL).substring(1); 1365d470984844c388d6766c3de6ac64e93e00480fc9Flavio Lerda break; 13664b7846722d1a5acb0577b07e98324f744f5e7942Shaopeng Jia case FROM_DEFAULT_COUNTRY: 1367528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia // Fall-through to default case. 136854923fc72f0faeb11fe58a545c0314f6051b14aaShaopeng Jia default: 1369528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia String regionCode = getRegionCodeForCountryCode(number.getCountryCode()); 1370528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia // We strip non-digits from the NDD here, and from the raw input later, so that we can 1371528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia // compare them easily. 1372528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia String nationalPrefix = getNddPrefixForRegion(regionCode, true /* strip non-digits */); 1373528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia String nationalFormat = format(number, PhoneNumberFormat.NATIONAL); 1374528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia if (nationalPrefix == null || nationalPrefix.length() == 0) { 1375528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia // If the region doesn't have a national prefix at all, we can safely return the national 1376528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia // format without worrying about a national prefix being added. 1377528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia formattedNumber = nationalFormat; 1378528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia break; 1379528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia } 1380528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia // Otherwise, we check if the original number was entered with a national prefix. 1381528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia if (rawInputContainsNationalPrefix( 1382528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia number.getRawInput(), nationalPrefix, regionCode)) { 1383528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia // If so, we can safely return the national format. 1384528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia formattedNumber = nationalFormat; 1385528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia break; 1386528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia } 1387203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia // Metadata cannot be null here because getNddPrefixForRegion() (above) returns null if 1388203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia // there is no metadata for the region. 1389528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia PhoneMetadata metadata = getMetadataForRegion(regionCode); 1390528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia String nationalNumber = getNationalSignificantNumber(number); 1391528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia NumberFormat formatRule = 1392528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia chooseFormattingPatternForNumber(metadata.numberFormats(), nationalNumber); 1393203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia // The format rule could still be null here if the national number was 0 and there was no 1394203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia // raw input (this should not be possible for numbers generated by the phonenumber library 1395203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia // as they would also not have a country calling code and we would have exited earlier). 1396203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia if (formatRule == null) { 1397203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia formattedNumber = nationalFormat; 1398203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia break; 1399203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia } 1400528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia // When the format we apply to this number doesn't contain national prefix, we can just 1401528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia // return the national format. 1402528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia // TODO: Refactor the code below with the code in isNationalPrefixPresentIfRequired. 1403528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia String candidateNationalPrefixRule = formatRule.getNationalPrefixFormattingRule(); 1404528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia // We assume that the first-group symbol will never be _before_ the national prefix. 1405528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia int indexOfFirstGroup = candidateNationalPrefixRule.indexOf("$1"); 1406528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia if (indexOfFirstGroup <= 0) { 1407528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia formattedNumber = nationalFormat; 1408528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia break; 1409528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia } 1410528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia candidateNationalPrefixRule = 1411528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia candidateNationalPrefixRule.substring(0, indexOfFirstGroup); 1412528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia candidateNationalPrefixRule = normalizeDigitsOnly(candidateNationalPrefixRule); 1413528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia if (candidateNationalPrefixRule.length() == 0) { 1414528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia // National prefix not used when formatting this number. 1415528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia formattedNumber = nationalFormat; 1416528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia break; 1417528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia } 1418528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia // Otherwise, we need to remove the national prefix from our output. 1419528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia NumberFormat numFormatCopy = new NumberFormat(); 1420528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia numFormatCopy.mergeFrom(formatRule); 1421528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia numFormatCopy.clearNationalPrefixFormattingRule(); 1422528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia List<NumberFormat> numberFormats = new ArrayList<NumberFormat>(1); 1423528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia numberFormats.add(numFormatCopy); 1424528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia formattedNumber = formatByPattern(number, PhoneNumberFormat.NATIONAL, numberFormats); 1425d470984844c388d6766c3de6ac64e93e00480fc9Flavio Lerda break; 142654923fc72f0faeb11fe58a545c0314f6051b14aaShaopeng Jia } 1427d470984844c388d6766c3de6ac64e93e00480fc9Flavio Lerda String rawInput = number.getRawInput(); 1428d470984844c388d6766c3de6ac64e93e00480fc9Flavio Lerda // If no digit is inserted/removed/modified as a result of our formatting, we return the 1429d470984844c388d6766c3de6ac64e93e00480fc9Flavio Lerda // formatted phone number; otherwise we return the raw input the user entered. 1430203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia if (formattedNumber != null && rawInput.length() > 0) { 1431203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia String normalizedFormattedNumber = 1432203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia normalizeHelper(formattedNumber, DIALLABLE_CHAR_MAPPINGS, true /* remove non matches */); 1433203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia String normalizedRawInput = 1434203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia normalizeHelper(rawInput, DIALLABLE_CHAR_MAPPINGS, true /* remove non matches */); 1435203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia if (!normalizedFormattedNumber.equals(normalizedRawInput)) { 1436203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia formattedNumber = rawInput; 1437203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia } 1438203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia } 1439203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia return formattedNumber; 144054923fc72f0faeb11fe58a545c0314f6051b14aaShaopeng Jia } 144154923fc72f0faeb11fe58a545c0314f6051b14aaShaopeng Jia 1442528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia // Check if rawInput, which is assumed to be in the national format, has a national prefix. The 1443528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia // national prefix is assumed to be in digits-only form. 1444528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia private boolean rawInputContainsNationalPrefix(String rawInput, String nationalPrefix, 1445528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia String regionCode) { 1446528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia String normalizedNationalNumber = normalizeDigitsOnly(rawInput); 1447528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia if (normalizedNationalNumber.startsWith(nationalPrefix)) { 1448528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia try { 1449528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia // Some Japanese numbers (e.g. 00777123) might be mistaken to contain the national prefix 1450528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia // when written without it (e.g. 0777123) if we just do prefix matching. To tackle that, we 1451528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia // check the validity of the number if the assumed national prefix is removed (777123 won't 1452528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia // be valid in Japan). 1453528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia return isValidNumber( 1454528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia parse(normalizedNationalNumber.substring(nationalPrefix.length()), regionCode)); 1455528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia } catch (NumberParseException e) { 1456528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia return false; 1457528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia } 1458528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia } 1459528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia return false; 1460528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia } 1461528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia 1462528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia /** 1463528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia * Returns true if a number is from a region whose national significant number couldn't contain a 1464528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia * leading zero, but has the italian_leading_zero field set to true. 1465528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia */ 1466528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia private boolean hasUnexpectedItalianLeadingZero(PhoneNumber number) { 1467528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia return number.isItalianLeadingZero() && !isLeadingZeroPossible(number.getCountryCode()); 1468528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia } 1469528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia 14705cd062f9cba053c771bcea181fec210279ec030bShaopeng Jia private boolean hasFormattingPatternForNumber(PhoneNumber number) { 1471528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia int countryCallingCode = number.getCountryCode(); 1472528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia String phoneNumberRegion = getRegionCodeForCountryCode(countryCallingCode); 1473528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia PhoneMetadata metadata = 1474528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia getMetadataForRegionOrCallingCode(countryCallingCode, phoneNumberRegion); 14755cd062f9cba053c771bcea181fec210279ec030bShaopeng Jia if (metadata == null) { 14765cd062f9cba053c771bcea181fec210279ec030bShaopeng Jia return false; 14775cd062f9cba053c771bcea181fec210279ec030bShaopeng Jia } 14785cd062f9cba053c771bcea181fec210279ec030bShaopeng Jia String nationalNumber = getNationalSignificantNumber(number); 14795cd062f9cba053c771bcea181fec210279ec030bShaopeng Jia NumberFormat formatRule = 14805cd062f9cba053c771bcea181fec210279ec030bShaopeng Jia chooseFormattingPatternForNumber(metadata.numberFormats(), nationalNumber); 14815cd062f9cba053c771bcea181fec210279ec030bShaopeng Jia return formatRule != null; 14825cd062f9cba053c771bcea181fec210279ec030bShaopeng Jia } 14835cd062f9cba053c771bcea181fec210279ec030bShaopeng Jia 14845c24149d269da6e7d7b6b2797df096fdea64a019Shaopeng Jia /** 1485372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * Formats a phone number for out-of-country dialing purposes. 1486372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * 1487372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * Note that in this version, if the number was entered originally using alpha characters and 1488372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * this version of the number is stored in raw_input, this representation of the number will be 1489372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * used rather than the digit representation. Grouping information, as specified by characters 1490372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * such as "-" and " ", will be retained. 1491372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * 1492372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * <p><b>Caveats:</b></p> 1493372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * <ul> 1494372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * <li> This will not produce good results if the country calling code is both present in the raw 1495372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * input _and_ is the start of the national number. This is not a problem in the regions 1496372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * which typically use alpha numbers. 1497372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * <li> This will also not produce good results if the raw input has any grouping information 1498372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * within the first three digits of the national number, and if the function needs to strip 1499372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * preceding digits/words in the raw input before these digits. Normally people group the 1500372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * first three digits together so this is not a huge problem - and will be fixed if it 1501372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * proves to be so. 1502372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * </ul> 1503372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * 1504372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * @param number the phone number that needs to be formatted 1505372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * @param regionCallingFrom the region where the call is being placed 1506372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * @return the formatted phone number 1507372bff8dd464574d36737d47e495cad14346653cShaopeng Jia */ 1508d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia public String formatOutOfCountryKeepingAlphaChars(PhoneNumber number, 1509d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia String regionCallingFrom) { 1510372bff8dd464574d36737d47e495cad14346653cShaopeng Jia String rawInput = number.getRawInput(); 1511372bff8dd464574d36737d47e495cad14346653cShaopeng Jia // If there is no raw input, then we can't keep alpha characters because there aren't any. 1512372bff8dd464574d36737d47e495cad14346653cShaopeng Jia // In this case, we return formatOutOfCountryCallingNumber. 1513372bff8dd464574d36737d47e495cad14346653cShaopeng Jia if (rawInput.length() == 0) { 1514372bff8dd464574d36737d47e495cad14346653cShaopeng Jia return formatOutOfCountryCallingNumber(number, regionCallingFrom); 1515372bff8dd464574d36737d47e495cad14346653cShaopeng Jia } 1516372bff8dd464574d36737d47e495cad14346653cShaopeng Jia int countryCode = number.getCountryCode(); 1517528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia if (!hasValidCountryCallingCode(countryCode)) { 1518372bff8dd464574d36737d47e495cad14346653cShaopeng Jia return rawInput; 1519372bff8dd464574d36737d47e495cad14346653cShaopeng Jia } 1520372bff8dd464574d36737d47e495cad14346653cShaopeng Jia // Strip any prefix such as country calling code, IDD, that was present. We do this by comparing 1521372bff8dd464574d36737d47e495cad14346653cShaopeng Jia // the number in raw_input with the parsed number. 1522372bff8dd464574d36737d47e495cad14346653cShaopeng Jia // To do this, first we normalize punctuation. We retain number grouping symbols such as " " 1523372bff8dd464574d36737d47e495cad14346653cShaopeng Jia // only. 1524372bff8dd464574d36737d47e495cad14346653cShaopeng Jia rawInput = normalizeHelper(rawInput, ALL_PLUS_NUMBER_GROUPING_SYMBOLS, true); 1525372bff8dd464574d36737d47e495cad14346653cShaopeng Jia // Now we trim everything before the first three digits in the parsed number. We choose three 1526372bff8dd464574d36737d47e495cad14346653cShaopeng Jia // because all valid alpha numbers have 3 digits at the start - if it does not, then we don't 1527372bff8dd464574d36737d47e495cad14346653cShaopeng Jia // trim anything at all. Similarly, if the national number was less than three digits, we don't 1528372bff8dd464574d36737d47e495cad14346653cShaopeng Jia // trim anything at all. 1529372bff8dd464574d36737d47e495cad14346653cShaopeng Jia String nationalNumber = getNationalSignificantNumber(number); 1530372bff8dd464574d36737d47e495cad14346653cShaopeng Jia if (nationalNumber.length() > 3) { 1531372bff8dd464574d36737d47e495cad14346653cShaopeng Jia int firstNationalNumberDigit = rawInput.indexOf(nationalNumber.substring(0, 3)); 1532372bff8dd464574d36737d47e495cad14346653cShaopeng Jia if (firstNationalNumberDigit != -1) { 1533372bff8dd464574d36737d47e495cad14346653cShaopeng Jia rawInput = rawInput.substring(firstNationalNumberDigit); 1534372bff8dd464574d36737d47e495cad14346653cShaopeng Jia } 1535372bff8dd464574d36737d47e495cad14346653cShaopeng Jia } 1536528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia PhoneMetadata metadataForRegionCallingFrom = getMetadataForRegion(regionCallingFrom); 1537372bff8dd464574d36737d47e495cad14346653cShaopeng Jia if (countryCode == NANPA_COUNTRY_CODE) { 1538372bff8dd464574d36737d47e495cad14346653cShaopeng Jia if (isNANPACountry(regionCallingFrom)) { 1539372bff8dd464574d36737d47e495cad14346653cShaopeng Jia return countryCode + " " + rawInput; 1540372bff8dd464574d36737d47e495cad14346653cShaopeng Jia } 1541203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia } else if (metadataForRegionCallingFrom != null && 1542cc0ae7326023c5da91dd9a84035c3dc3f6cc372fShaopeng Jia countryCode == getCountryCodeForValidRegion(regionCallingFrom)) { 1543cc0ae7326023c5da91dd9a84035c3dc3f6cc372fShaopeng Jia NumberFormat formattingPattern = 1544cc0ae7326023c5da91dd9a84035c3dc3f6cc372fShaopeng Jia chooseFormattingPatternForNumber(metadataForRegionCallingFrom.numberFormats(), 1545cc0ae7326023c5da91dd9a84035c3dc3f6cc372fShaopeng Jia nationalNumber); 1546cc0ae7326023c5da91dd9a84035c3dc3f6cc372fShaopeng Jia if (formattingPattern == null) { 1547cc0ae7326023c5da91dd9a84035c3dc3f6cc372fShaopeng Jia // If no pattern above is matched, we format the original input. 1548cc0ae7326023c5da91dd9a84035c3dc3f6cc372fShaopeng Jia return rawInput; 1549372bff8dd464574d36737d47e495cad14346653cShaopeng Jia } 1550cc0ae7326023c5da91dd9a84035c3dc3f6cc372fShaopeng Jia NumberFormat newFormat = new NumberFormat(); 1551cc0ae7326023c5da91dd9a84035c3dc3f6cc372fShaopeng Jia newFormat.mergeFrom(formattingPattern); 1552cc0ae7326023c5da91dd9a84035c3dc3f6cc372fShaopeng Jia // The first group is the first group of digits that the user wrote together. 1553cc0ae7326023c5da91dd9a84035c3dc3f6cc372fShaopeng Jia newFormat.setPattern("(\\d+)(.*)"); 1554cc0ae7326023c5da91dd9a84035c3dc3f6cc372fShaopeng Jia // Here we just concatenate them back together after the national prefix has been fixed. 1555cc0ae7326023c5da91dd9a84035c3dc3f6cc372fShaopeng Jia newFormat.setFormat("$1$2"); 1556cc0ae7326023c5da91dd9a84035c3dc3f6cc372fShaopeng Jia // Now we format using this pattern instead of the default pattern, but with the national 1557cc0ae7326023c5da91dd9a84035c3dc3f6cc372fShaopeng Jia // prefix prefixed if necessary. 1558372bff8dd464574d36737d47e495cad14346653cShaopeng Jia // This will not work in the cases where the pattern (and not the leading digits) decide 1559372bff8dd464574d36737d47e495cad14346653cShaopeng Jia // whether a national prefix needs to be used, since we have overridden the pattern to match 1560372bff8dd464574d36737d47e495cad14346653cShaopeng Jia // anything, but that is not the case in the metadata to date. 1561cc0ae7326023c5da91dd9a84035c3dc3f6cc372fShaopeng Jia return formatNsnUsingPattern(rawInput, newFormat, PhoneNumberFormat.NATIONAL); 1562372bff8dd464574d36737d47e495cad14346653cShaopeng Jia } 1563528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia String internationalPrefixForFormatting = ""; 1564528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia // If an unsupported region-calling-from is entered, or a country with multiple international 1565528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia // prefixes, the international format of the number is returned, unless there is a preferred 1566528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia // international prefix. 1567528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia if (metadataForRegionCallingFrom != null) { 1568528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia String internationalPrefix = metadataForRegionCallingFrom.getInternationalPrefix(); 1569528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia internationalPrefixForFormatting = 1570528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia UNIQUE_INTERNATIONAL_PREFIX.matcher(internationalPrefix).matches() 1571528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia ? internationalPrefix 1572528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia : metadataForRegionCallingFrom.getPreferredInternationalPrefix(); 1573528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia } 1574372bff8dd464574d36737d47e495cad14346653cShaopeng Jia StringBuilder formattedNumber = new StringBuilder(rawInput); 1575528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia String regionCode = getRegionCodeForCountryCode(countryCode); 1576203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia // Metadata cannot be null because the country calling code is valid. 1577528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia PhoneMetadata metadataForRegion = getMetadataForRegionOrCallingCode(countryCode, regionCode); 1578cc0ae7326023c5da91dd9a84035c3dc3f6cc372fShaopeng Jia maybeAppendFormattedExtension(number, metadataForRegion, 1579cc0ae7326023c5da91dd9a84035c3dc3f6cc372fShaopeng Jia PhoneNumberFormat.INTERNATIONAL, formattedNumber); 1580372bff8dd464574d36737d47e495cad14346653cShaopeng Jia if (internationalPrefixForFormatting.length() > 0) { 1581372bff8dd464574d36737d47e495cad14346653cShaopeng Jia formattedNumber.insert(0, " ").insert(0, countryCode).insert(0, " ") 1582372bff8dd464574d36737d47e495cad14346653cShaopeng Jia .insert(0, internationalPrefixForFormatting); 1583372bff8dd464574d36737d47e495cad14346653cShaopeng Jia } else { 1584528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia // Invalid region entered as country-calling-from (so no metadata was found for it) or the 1585528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia // region chosen has multiple international dialling prefixes. 1586b0e21c22b1ca6b9aeb1426924cdf42a221c3d416Shaopeng Jia LOGGER.log(Level.WARNING, 1587b0e21c22b1ca6b9aeb1426924cdf42a221c3d416Shaopeng Jia "Trying to format number from invalid region " 1588b0e21c22b1ca6b9aeb1426924cdf42a221c3d416Shaopeng Jia + regionCallingFrom 1589b0e21c22b1ca6b9aeb1426924cdf42a221c3d416Shaopeng Jia + ". International formatting applied."); 1590cc0ae7326023c5da91dd9a84035c3dc3f6cc372fShaopeng Jia prefixNumberWithCountryCallingCode(countryCode, 1591b0e21c22b1ca6b9aeb1426924cdf42a221c3d416Shaopeng Jia PhoneNumberFormat.INTERNATIONAL, 1592b0e21c22b1ca6b9aeb1426924cdf42a221c3d416Shaopeng Jia formattedNumber); 1593372bff8dd464574d36737d47e495cad14346653cShaopeng Jia } 1594372bff8dd464574d36737d47e495cad14346653cShaopeng Jia return formattedNumber.toString(); 1595372bff8dd464574d36737d47e495cad14346653cShaopeng Jia } 1596372bff8dd464574d36737d47e495cad14346653cShaopeng Jia 1597372bff8dd464574d36737d47e495cad14346653cShaopeng Jia /** 15985c24149d269da6e7d7b6b2797df096fdea64a019Shaopeng Jia * Gets the national significant number of the a phone number. Note a national significant number 15995c24149d269da6e7d7b6b2797df096fdea64a019Shaopeng Jia * doesn't contain a national prefix or any formatting. 16005c24149d269da6e7d7b6b2797df096fdea64a019Shaopeng Jia * 1601d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia * @param number the phone number for which the national significant number is needed 16025c24149d269da6e7d7b6b2797df096fdea64a019Shaopeng Jia * @return the national significant number of the PhoneNumber object passed in 16035c24149d269da6e7d7b6b2797df096fdea64a019Shaopeng Jia */ 1604372bff8dd464574d36737d47e495cad14346653cShaopeng Jia public String getNationalSignificantNumber(PhoneNumber number) { 1605ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia // If a leading zero has been set, we prefix this now. Note this is not a national prefix. 1606ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia StringBuilder nationalNumber = new StringBuilder(number.isItalianLeadingZero() ? "0" : ""); 16071524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia nationalNumber.append(number.getNationalNumber()); 16081524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia return nationalNumber.toString(); 16091524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } 16101524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia 16111524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia /** 16121524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * A helper function that is used by format and formatByPattern. 16131524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia */ 1614cc0ae7326023c5da91dd9a84035c3dc3f6cc372fShaopeng Jia private void prefixNumberWithCountryCallingCode(int countryCallingCode, 1615cc0ae7326023c5da91dd9a84035c3dc3f6cc372fShaopeng Jia PhoneNumberFormat numberFormat, 1616cc0ae7326023c5da91dd9a84035c3dc3f6cc372fShaopeng Jia StringBuilder formattedNumber) { 16171524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia switch (numberFormat) { 16181524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia case E164: 1619372bff8dd464574d36737d47e495cad14346653cShaopeng Jia formattedNumber.insert(0, countryCallingCode).insert(0, PLUS_SIGN); 1620be1af2f8b62d5435eca48f3dd5c82e3d2c9bfa17Shaopeng Jia return; 16211524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia case INTERNATIONAL: 1622372bff8dd464574d36737d47e495cad14346653cShaopeng Jia formattedNumber.insert(0, " ").insert(0, countryCallingCode).insert(0, PLUS_SIGN); 1623372bff8dd464574d36737d47e495cad14346653cShaopeng Jia return; 1624372bff8dd464574d36737d47e495cad14346653cShaopeng Jia case RFC3966: 1625b0e21c22b1ca6b9aeb1426924cdf42a221c3d416Shaopeng Jia formattedNumber.insert(0, "-").insert(0, countryCallingCode).insert(0, PLUS_SIGN) 1626b210e301245cb5dc90aa3142f378632bd41cb172Shaopeng Jia .insert(0, RFC3966_PREFIX); 1627be1af2f8b62d5435eca48f3dd5c82e3d2c9bfa17Shaopeng Jia return; 16281524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia case NATIONAL: 16291524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia default: 1630be1af2f8b62d5435eca48f3dd5c82e3d2c9bfa17Shaopeng Jia return; 16311524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } 16321524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } 16331524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia 1634cc0ae7326023c5da91dd9a84035c3dc3f6cc372fShaopeng Jia // Simple wrapper of formatNsn for the common case of no carrier code. 1635cc0ae7326023c5da91dd9a84035c3dc3f6cc372fShaopeng Jia private String formatNsn(String number, PhoneMetadata metadata, PhoneNumberFormat numberFormat) { 1636cc0ae7326023c5da91dd9a84035c3dc3f6cc372fShaopeng Jia return formatNsn(number, metadata, numberFormat, null); 1637df19cbfb8a1e8720bae76bb763ab29622e057c42Shaopeng Jia } 16384b7846722d1a5acb0577b07e98324f744f5e7942Shaopeng Jia 1639372bff8dd464574d36737d47e495cad14346653cShaopeng Jia // Note in some regions, the national number can be written in two completely different ways 16401524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia // depending on whether it forms part of the NATIONAL format or INTERNATIONAL format. The 16414b7846722d1a5acb0577b07e98324f744f5e7942Shaopeng Jia // numberFormat parameter here is used to specify which format to use for those cases. If a 16424b7846722d1a5acb0577b07e98324f744f5e7942Shaopeng Jia // carrierCode is specified, this will be inserted into the formatted string to replace $CC. 1643cc0ae7326023c5da91dd9a84035c3dc3f6cc372fShaopeng Jia private String formatNsn(String number, 1644cc0ae7326023c5da91dd9a84035c3dc3f6cc372fShaopeng Jia PhoneMetadata metadata, 1645cc0ae7326023c5da91dd9a84035c3dc3f6cc372fShaopeng Jia PhoneNumberFormat numberFormat, 1646cc0ae7326023c5da91dd9a84035c3dc3f6cc372fShaopeng Jia String carrierCode) { 1647372bff8dd464574d36737d47e495cad14346653cShaopeng Jia List<NumberFormat> intlNumberFormats = metadata.intlNumberFormats(); 16481524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia // When the intlNumberFormats exists, we use that to format national number for the 16491524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia // INTERNATIONAL format instead of using the numberDesc.numberFormats. 16501524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia List<NumberFormat> availableFormats = 16511524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia (intlNumberFormats.size() == 0 || numberFormat == PhoneNumberFormat.NATIONAL) 1652372bff8dd464574d36737d47e495cad14346653cShaopeng Jia ? metadata.numberFormats() 1653372bff8dd464574d36737d47e495cad14346653cShaopeng Jia : metadata.intlNumberFormats(); 1654cc0ae7326023c5da91dd9a84035c3dc3f6cc372fShaopeng Jia NumberFormat formattingPattern = chooseFormattingPatternForNumber(availableFormats, number); 1655cc0ae7326023c5da91dd9a84035c3dc3f6cc372fShaopeng Jia return (formattingPattern == null) 1656cc0ae7326023c5da91dd9a84035c3dc3f6cc372fShaopeng Jia ? number 1657cc0ae7326023c5da91dd9a84035c3dc3f6cc372fShaopeng Jia : formatNsnUsingPattern(number, formattingPattern, numberFormat, carrierCode); 16581524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } 16591524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia 1660b210e301245cb5dc90aa3142f378632bd41cb172Shaopeng Jia NumberFormat chooseFormattingPatternForNumber(List<NumberFormat> availableFormats, 1661b210e301245cb5dc90aa3142f378632bd41cb172Shaopeng Jia String nationalNumber) { 1662a48b2d221ba46df7446d1a87244efa985e8e292fShaopeng Jia for (NumberFormat numFormat : availableFormats) { 1663a48b2d221ba46df7446d1a87244efa985e8e292fShaopeng Jia int size = numFormat.leadingDigitsPatternSize(); 1664a48b2d221ba46df7446d1a87244efa985e8e292fShaopeng Jia if (size == 0 || regexCache.getPatternForRegex( 1665a48b2d221ba46df7446d1a87244efa985e8e292fShaopeng Jia // We always use the last leading_digits_pattern, as it is the most detailed. 1666a48b2d221ba46df7446d1a87244efa985e8e292fShaopeng Jia numFormat.getLeadingDigitsPattern(size - 1)).matcher(nationalNumber).lookingAt()) { 1667a48b2d221ba46df7446d1a87244efa985e8e292fShaopeng Jia Matcher m = regexCache.getPatternForRegex(numFormat.getPattern()).matcher(nationalNumber); 1668a48b2d221ba46df7446d1a87244efa985e8e292fShaopeng Jia if (m.matches()) { 1669a48b2d221ba46df7446d1a87244efa985e8e292fShaopeng Jia return numFormat; 1670a48b2d221ba46df7446d1a87244efa985e8e292fShaopeng Jia } 1671a48b2d221ba46df7446d1a87244efa985e8e292fShaopeng Jia } 1672a48b2d221ba46df7446d1a87244efa985e8e292fShaopeng Jia } 1673a48b2d221ba46df7446d1a87244efa985e8e292fShaopeng Jia return null; 1674a48b2d221ba46df7446d1a87244efa985e8e292fShaopeng Jia } 1675a48b2d221ba46df7446d1a87244efa985e8e292fShaopeng Jia 1676cc0ae7326023c5da91dd9a84035c3dc3f6cc372fShaopeng Jia // Simple wrapper of formatNsnUsingPattern for the common case of no carrier code. 1677b210e301245cb5dc90aa3142f378632bd41cb172Shaopeng Jia String formatNsnUsingPattern(String nationalNumber, 1678b210e301245cb5dc90aa3142f378632bd41cb172Shaopeng Jia NumberFormat formattingPattern, 1679b210e301245cb5dc90aa3142f378632bd41cb172Shaopeng Jia PhoneNumberFormat numberFormat) { 1680cc0ae7326023c5da91dd9a84035c3dc3f6cc372fShaopeng Jia return formatNsnUsingPattern(nationalNumber, formattingPattern, numberFormat, null); 16814b7846722d1a5acb0577b07e98324f744f5e7942Shaopeng Jia } 16824b7846722d1a5acb0577b07e98324f744f5e7942Shaopeng Jia 1683203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia // Note that carrierCode is optional - if null or an empty string, no carrier code replacement 168452699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia // will take place. 1685cc0ae7326023c5da91dd9a84035c3dc3f6cc372fShaopeng Jia private String formatNsnUsingPattern(String nationalNumber, 1686cc0ae7326023c5da91dd9a84035c3dc3f6cc372fShaopeng Jia NumberFormat formattingPattern, 1687cc0ae7326023c5da91dd9a84035c3dc3f6cc372fShaopeng Jia PhoneNumberFormat numberFormat, 1688cc0ae7326023c5da91dd9a84035c3dc3f6cc372fShaopeng Jia String carrierCode) { 1689cc0ae7326023c5da91dd9a84035c3dc3f6cc372fShaopeng Jia String numberFormatRule = formattingPattern.getFormat(); 1690cc0ae7326023c5da91dd9a84035c3dc3f6cc372fShaopeng Jia Matcher m = 1691cc0ae7326023c5da91dd9a84035c3dc3f6cc372fShaopeng Jia regexCache.getPatternForRegex(formattingPattern.getPattern()).matcher(nationalNumber); 1692cc0ae7326023c5da91dd9a84035c3dc3f6cc372fShaopeng Jia String formattedNationalNumber = ""; 1693a48b2d221ba46df7446d1a87244efa985e8e292fShaopeng Jia if (numberFormat == PhoneNumberFormat.NATIONAL && 1694a48b2d221ba46df7446d1a87244efa985e8e292fShaopeng Jia carrierCode != null && carrierCode.length() > 0 && 1695cc0ae7326023c5da91dd9a84035c3dc3f6cc372fShaopeng Jia formattingPattern.getDomesticCarrierCodeFormattingRule().length() > 0) { 1696a48b2d221ba46df7446d1a87244efa985e8e292fShaopeng Jia // Replace the $CC in the formatting rule with the desired carrier code. 1697cc0ae7326023c5da91dd9a84035c3dc3f6cc372fShaopeng Jia String carrierCodeFormattingRule = formattingPattern.getDomesticCarrierCodeFormattingRule(); 1698a48b2d221ba46df7446d1a87244efa985e8e292fShaopeng Jia carrierCodeFormattingRule = 1699a48b2d221ba46df7446d1a87244efa985e8e292fShaopeng Jia CC_PATTERN.matcher(carrierCodeFormattingRule).replaceFirst(carrierCode); 1700a48b2d221ba46df7446d1a87244efa985e8e292fShaopeng Jia // Now replace the $FG in the formatting rule with the first group and the carrier code 1701a48b2d221ba46df7446d1a87244efa985e8e292fShaopeng Jia // combined in the appropriate way. 1702a48b2d221ba46df7446d1a87244efa985e8e292fShaopeng Jia numberFormatRule = FIRST_GROUP_PATTERN.matcher(numberFormatRule) 1703a48b2d221ba46df7446d1a87244efa985e8e292fShaopeng Jia .replaceFirst(carrierCodeFormattingRule); 1704cc0ae7326023c5da91dd9a84035c3dc3f6cc372fShaopeng Jia formattedNationalNumber = m.replaceAll(numberFormatRule); 1705a48b2d221ba46df7446d1a87244efa985e8e292fShaopeng Jia } else { 1706a48b2d221ba46df7446d1a87244efa985e8e292fShaopeng Jia // Use the national prefix formatting rule instead. 1707cc0ae7326023c5da91dd9a84035c3dc3f6cc372fShaopeng Jia String nationalPrefixFormattingRule = formattingPattern.getNationalPrefixFormattingRule(); 1708a48b2d221ba46df7446d1a87244efa985e8e292fShaopeng Jia if (numberFormat == PhoneNumberFormat.NATIONAL && 1709a48b2d221ba46df7446d1a87244efa985e8e292fShaopeng Jia nationalPrefixFormattingRule != null && 1710a48b2d221ba46df7446d1a87244efa985e8e292fShaopeng Jia nationalPrefixFormattingRule.length() > 0) { 1711a48b2d221ba46df7446d1a87244efa985e8e292fShaopeng Jia Matcher firstGroupMatcher = FIRST_GROUP_PATTERN.matcher(numberFormatRule); 1712cc0ae7326023c5da91dd9a84035c3dc3f6cc372fShaopeng Jia formattedNationalNumber = 1713cc0ae7326023c5da91dd9a84035c3dc3f6cc372fShaopeng Jia m.replaceAll(firstGroupMatcher.replaceFirst(nationalPrefixFormattingRule)); 1714a48b2d221ba46df7446d1a87244efa985e8e292fShaopeng Jia } else { 1715cc0ae7326023c5da91dd9a84035c3dc3f6cc372fShaopeng Jia formattedNationalNumber = m.replaceAll(numberFormatRule); 17161524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } 17171524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } 1718cc0ae7326023c5da91dd9a84035c3dc3f6cc372fShaopeng Jia if (numberFormat == PhoneNumberFormat.RFC3966) { 1719cc0ae7326023c5da91dd9a84035c3dc3f6cc372fShaopeng Jia // Strip any leading punctuation. 1720cc0ae7326023c5da91dd9a84035c3dc3f6cc372fShaopeng Jia Matcher matcher = SEPARATOR_PATTERN.matcher(formattedNationalNumber); 1721cc0ae7326023c5da91dd9a84035c3dc3f6cc372fShaopeng Jia if (matcher.lookingAt()) { 1722cc0ae7326023c5da91dd9a84035c3dc3f6cc372fShaopeng Jia formattedNationalNumber = matcher.replaceFirst(""); 1723cc0ae7326023c5da91dd9a84035c3dc3f6cc372fShaopeng Jia } 1724cc0ae7326023c5da91dd9a84035c3dc3f6cc372fShaopeng Jia // Replace the rest with a dash between each number group. 1725cc0ae7326023c5da91dd9a84035c3dc3f6cc372fShaopeng Jia formattedNationalNumber = matcher.reset(formattedNationalNumber).replaceAll("-"); 1726cc0ae7326023c5da91dd9a84035c3dc3f6cc372fShaopeng Jia } 1727cc0ae7326023c5da91dd9a84035c3dc3f6cc372fShaopeng Jia return formattedNationalNumber; 17281524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } 17291524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia 17301524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia /** 1731372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * Gets a valid number for the specified region. 17321524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * 1733d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia * @param regionCode the region for which an example number is needed 1734372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * @return a valid fixed-line number for the specified region. Returns null when the metadata 1735528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia * does not contain such information, or the region 001 is passed in. For 001 (representing 1736528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia * non-geographical numbers), call {@link #getExampleNumberForNonGeoEntity} instead. 17371524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia */ 17381524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia public PhoneNumber getExampleNumber(String regionCode) { 17391524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia return getExampleNumberForType(regionCode, PhoneNumberType.FIXED_LINE); 17401524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } 17411524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia 17421524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia /** 1743372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * Gets a valid number for the specified region and number type. 17441524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * 1745d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia * @param regionCode the region for which an example number is needed 17461524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * @param type the type of number that is needed 1747372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * @return a valid number for the specified region and type. Returns null when the metadata 1748528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia * does not contain such information or if an invalid region or region 001 was entered. 1749528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia * For 001 (representing non-geographical numbers), call 1750528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia * {@link #getExampleNumberForNonGeoEntity} instead. 17511524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia */ 17521524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia public PhoneNumber getExampleNumberForType(String regionCode, PhoneNumberType type) { 1753372bff8dd464574d36737d47e495cad14346653cShaopeng Jia // Check the region code is valid. 1754372bff8dd464574d36737d47e495cad14346653cShaopeng Jia if (!isValidRegionCode(regionCode)) { 1755cc0ae7326023c5da91dd9a84035c3dc3f6cc372fShaopeng Jia LOGGER.log(Level.WARNING, "Invalid or unknown region code provided: " + regionCode); 1756372bff8dd464574d36737d47e495cad14346653cShaopeng Jia return null; 1757372bff8dd464574d36737d47e495cad14346653cShaopeng Jia } 17581524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia PhoneNumberDesc desc = getNumberDescByType(getMetadataForRegion(regionCode), type); 17591524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia try { 17601524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia if (desc.hasExampleNumber()) { 17611524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia return parse(desc.getExampleNumber(), regionCode); 17621524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } 17631524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } catch (NumberParseException e) { 17641524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia LOGGER.log(Level.SEVERE, e.toString()); 17651524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } 17661524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia return null; 17671524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } 17681524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia 17691524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia /** 1770528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia * Gets a valid number for the specified country calling code for a non-geographical entity. 1771528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia * 1772528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia * @param countryCallingCode the country calling code for a non-geographical entity 1773528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia * @return a valid number for the non-geographical entity. Returns null when the metadata 1774528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia * does not contain such information, or the country calling code passed in does not belong 1775528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia * to a non-geographical entity. 1776528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia */ 1777528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia public PhoneNumber getExampleNumberForNonGeoEntity(int countryCallingCode) { 1778528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia PhoneMetadata metadata = getMetadataForNonGeographicalRegion(countryCallingCode); 1779528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia if (metadata != null) { 1780528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia PhoneNumberDesc desc = metadata.getGeneralDesc(); 1781528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia try { 1782528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia if (desc.hasExampleNumber()) { 1783528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia return parse("+" + countryCallingCode + desc.getExampleNumber(), "ZZ"); 1784528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia } 1785528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia } catch (NumberParseException e) { 1786528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia LOGGER.log(Level.SEVERE, e.toString()); 1787528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia } 1788cc0ae7326023c5da91dd9a84035c3dc3f6cc372fShaopeng Jia } else { 1789cc0ae7326023c5da91dd9a84035c3dc3f6cc372fShaopeng Jia LOGGER.log(Level.WARNING, 1790cc0ae7326023c5da91dd9a84035c3dc3f6cc372fShaopeng Jia "Invalid or unknown country calling code provided: " + countryCallingCode); 1791528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia } 1792528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia return null; 1793528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia } 1794528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia 1795528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia /** 1796be1af2f8b62d5435eca48f3dd5c82e3d2c9bfa17Shaopeng Jia * Appends the formatted extension of a phone number to formattedNumber, if the phone number had 1797be1af2f8b62d5435eca48f3dd5c82e3d2c9bfa17Shaopeng Jia * an extension specified. 17981524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia */ 1799cc0ae7326023c5da91dd9a84035c3dc3f6cc372fShaopeng Jia private void maybeAppendFormattedExtension(PhoneNumber number, PhoneMetadata metadata, 1800cc0ae7326023c5da91dd9a84035c3dc3f6cc372fShaopeng Jia PhoneNumberFormat numberFormat, 1801cc0ae7326023c5da91dd9a84035c3dc3f6cc372fShaopeng Jia StringBuilder formattedNumber) { 1802372bff8dd464574d36737d47e495cad14346653cShaopeng Jia if (number.hasExtension() && number.getExtension().length() > 0) { 1803372bff8dd464574d36737d47e495cad14346653cShaopeng Jia if (numberFormat == PhoneNumberFormat.RFC3966) { 1804372bff8dd464574d36737d47e495cad14346653cShaopeng Jia formattedNumber.append(RFC3966_EXTN_PREFIX).append(number.getExtension()); 1805be1af2f8b62d5435eca48f3dd5c82e3d2c9bfa17Shaopeng Jia } else { 1806cc0ae7326023c5da91dd9a84035c3dc3f6cc372fShaopeng Jia if (metadata.hasPreferredExtnPrefix()) { 1807cc0ae7326023c5da91dd9a84035c3dc3f6cc372fShaopeng Jia formattedNumber.append(metadata.getPreferredExtnPrefix()).append(number.getExtension()); 1808cc0ae7326023c5da91dd9a84035c3dc3f6cc372fShaopeng Jia } else { 1809cc0ae7326023c5da91dd9a84035c3dc3f6cc372fShaopeng Jia formattedNumber.append(DEFAULT_EXTN_PREFIX).append(number.getExtension()); 1810cc0ae7326023c5da91dd9a84035c3dc3f6cc372fShaopeng Jia } 1811be1af2f8b62d5435eca48f3dd5c82e3d2c9bfa17Shaopeng Jia } 1812372bff8dd464574d36737d47e495cad14346653cShaopeng Jia } 1813372bff8dd464574d36737d47e495cad14346653cShaopeng Jia } 1814372bff8dd464574d36737d47e495cad14346653cShaopeng Jia 18151524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia PhoneNumberDesc getNumberDescByType(PhoneMetadata metadata, PhoneNumberType type) { 18161524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia switch (type) { 18171524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia case PREMIUM_RATE: 18181524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia return metadata.getPremiumRate(); 18191524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia case TOLL_FREE: 18201524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia return metadata.getTollFree(); 18211524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia case MOBILE: 18221524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia return metadata.getMobile(); 18231524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia case FIXED_LINE: 18241524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia case FIXED_LINE_OR_MOBILE: 18251524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia return metadata.getFixedLine(); 18261524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia case SHARED_COST: 18271524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia return metadata.getSharedCost(); 18281524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia case VOIP: 18291524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia return metadata.getVoip(); 18301524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia case PERSONAL_NUMBER: 18311524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia return metadata.getPersonalNumber(); 1832b2697412130f6d087dde01fb1a978f7e5840a5faShaopeng Jia case PAGER: 1833b2697412130f6d087dde01fb1a978f7e5840a5faShaopeng Jia return metadata.getPager(); 183474aa862e30b4d1b2722e90b1a8684274441a7541Shaopeng Jia case UAN: 183574aa862e30b4d1b2722e90b1a8684274441a7541Shaopeng Jia return metadata.getUan(); 1836528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia case VOICEMAIL: 1837528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia return metadata.getVoicemail(); 18381524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia default: 18391524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia return metadata.getGeneralDesc(); 18401524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } 18411524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } 18421524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia 18431524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia /** 18441524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * Gets the type of a phone number. 18451524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * 18461524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * @param number the phone number that we want to know the type 18471524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * @return the type of the phone number 18481524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia */ 18491524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia public PhoneNumberType getNumberType(PhoneNumber number) { 18501524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia String regionCode = getRegionCodeForNumber(number); 1851203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia PhoneMetadata metadata = getMetadataForRegionOrCallingCode(number.getCountryCode(), regionCode); 1852203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia if (metadata == null) { 18531524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia return PhoneNumberType.UNKNOWN; 18541524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } 1855be1af2f8b62d5435eca48f3dd5c82e3d2c9bfa17Shaopeng Jia String nationalSignificantNumber = getNationalSignificantNumber(number); 1856528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia return getNumberTypeHelper(nationalSignificantNumber, metadata); 18571524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } 18581524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia 18591524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia private PhoneNumberType getNumberTypeHelper(String nationalNumber, PhoneMetadata metadata) { 18601524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia PhoneNumberDesc generalNumberDesc = metadata.getGeneralDesc(); 18611524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia if (!generalNumberDesc.hasNationalNumberPattern() || 18621524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia !isNumberMatchingDesc(nationalNumber, generalNumberDesc)) { 18631524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia return PhoneNumberType.UNKNOWN; 18641524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } 18651524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia 18661524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia if (isNumberMatchingDesc(nationalNumber, metadata.getPremiumRate())) { 18671524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia return PhoneNumberType.PREMIUM_RATE; 18681524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } 18691524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia if (isNumberMatchingDesc(nationalNumber, metadata.getTollFree())) { 18701524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia return PhoneNumberType.TOLL_FREE; 18711524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } 18721524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia if (isNumberMatchingDesc(nationalNumber, metadata.getSharedCost())) { 18731524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia return PhoneNumberType.SHARED_COST; 18741524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } 18751524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia if (isNumberMatchingDesc(nationalNumber, metadata.getVoip())) { 18761524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia return PhoneNumberType.VOIP; 18771524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } 18781524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia if (isNumberMatchingDesc(nationalNumber, metadata.getPersonalNumber())) { 18791524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia return PhoneNumberType.PERSONAL_NUMBER; 18801524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } 1881b2697412130f6d087dde01fb1a978f7e5840a5faShaopeng Jia if (isNumberMatchingDesc(nationalNumber, metadata.getPager())) { 1882b2697412130f6d087dde01fb1a978f7e5840a5faShaopeng Jia return PhoneNumberType.PAGER; 1883b2697412130f6d087dde01fb1a978f7e5840a5faShaopeng Jia } 188474aa862e30b4d1b2722e90b1a8684274441a7541Shaopeng Jia if (isNumberMatchingDesc(nationalNumber, metadata.getUan())) { 188574aa862e30b4d1b2722e90b1a8684274441a7541Shaopeng Jia return PhoneNumberType.UAN; 188674aa862e30b4d1b2722e90b1a8684274441a7541Shaopeng Jia } 1887528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia if (isNumberMatchingDesc(nationalNumber, metadata.getVoicemail())) { 1888528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia return PhoneNumberType.VOICEMAIL; 1889528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia } 18901524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia 18911524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia boolean isFixedLine = isNumberMatchingDesc(nationalNumber, metadata.getFixedLine()); 18921524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia if (isFixedLine) { 1893d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia if (metadata.isSameMobileAndFixedLinePattern()) { 18941524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia return PhoneNumberType.FIXED_LINE_OR_MOBILE; 18951524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } else if (isNumberMatchingDesc(nationalNumber, metadata.getMobile())) { 18961524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia return PhoneNumberType.FIXED_LINE_OR_MOBILE; 18971524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } 18981524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia return PhoneNumberType.FIXED_LINE; 18991524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } 19001524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia // Otherwise, test to see if the number is mobile. Only do this if certain that the patterns for 19011524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia // mobile and fixed line aren't the same. 1902d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia if (!metadata.isSameMobileAndFixedLinePattern() && 19031524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia isNumberMatchingDesc(nationalNumber, metadata.getMobile())) { 19041524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia return PhoneNumberType.MOBILE; 19051524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } 19061524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia return PhoneNumberType.UNKNOWN; 19071524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } 19081524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia 1909203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia /** 1910203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia * Returns the metadata for the given region code or {@code null} if the region code is invalid 1911203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia * or unknown. 1912203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia */ 19131524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia PhoneMetadata getMetadataForRegion(String regionCode) { 1914fa42140081949568565af7dc8c22f0600ad90a8aShaopeng Jia if (!isValidRegionCode(regionCode)) { 19151524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia return null; 19161524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } 1917a1d3a5ed3af9cee85acdad939042a851a629f18cShaopeng Jia synchronized (regionToMetadataMap) { 1918a1d3a5ed3af9cee85acdad939042a851a629f18cShaopeng Jia if (!regionToMetadataMap.containsKey(regionCode)) { 1919528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia // The regionCode here will be valid and won't be '001', so we don't need to worry about 1920528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia // what to pass in for the country calling code. 1921528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia loadMetadataFromFile(currentFilePrefix, regionCode, 0); 1922a1d3a5ed3af9cee85acdad939042a851a629f18cShaopeng Jia } 1923fa42140081949568565af7dc8c22f0600ad90a8aShaopeng Jia } 1924372bff8dd464574d36737d47e495cad14346653cShaopeng Jia return regionToMetadataMap.get(regionCode); 19251524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } 19261524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia 1927528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia PhoneMetadata getMetadataForNonGeographicalRegion(int countryCallingCode) { 1928528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia synchronized (countryCodeToNonGeographicalMetadataMap) { 1929528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia if (!countryCallingCodeToRegionCodeMap.containsKey(countryCallingCode)) { 1930528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia return null; 1931528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia } 1932528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia if (!countryCodeToNonGeographicalMetadataMap.containsKey(countryCallingCode)) { 1933528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia loadMetadataFromFile(currentFilePrefix, REGION_CODE_FOR_NON_GEO_ENTITY, countryCallingCode); 1934528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia } 1935528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia } 1936528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia return countryCodeToNonGeographicalMetadataMap.get(countryCallingCode); 1937528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia } 1938528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia 19391524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia private boolean isNumberMatchingDesc(String nationalNumber, PhoneNumberDesc numberDesc) { 1940be1af2f8b62d5435eca48f3dd5c82e3d2c9bfa17Shaopeng Jia Matcher possibleNumberPatternMatcher = 1941be1af2f8b62d5435eca48f3dd5c82e3d2c9bfa17Shaopeng Jia regexCache.getPatternForRegex(numberDesc.getPossibleNumberPattern()) 1942be1af2f8b62d5435eca48f3dd5c82e3d2c9bfa17Shaopeng Jia .matcher(nationalNumber); 1943be1af2f8b62d5435eca48f3dd5c82e3d2c9bfa17Shaopeng Jia Matcher nationalNumberPatternMatcher = 1944be1af2f8b62d5435eca48f3dd5c82e3d2c9bfa17Shaopeng Jia regexCache.getPatternForRegex(numberDesc.getNationalNumberPattern()) 1945be1af2f8b62d5435eca48f3dd5c82e3d2c9bfa17Shaopeng Jia .matcher(nationalNumber); 1946be1af2f8b62d5435eca48f3dd5c82e3d2c9bfa17Shaopeng Jia return possibleNumberPatternMatcher.matches() && nationalNumberPatternMatcher.matches(); 19471524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } 19481524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia 19491524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia /** 19501524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * Tests whether a phone number matches a valid pattern. Note this doesn't verify the number 19511524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * is actually in use, which is impossible to tell by just looking at a number itself. 19521524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * 19531524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * @param number the phone number that we want to validate 19541524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * @return a boolean that indicates whether the number is of a valid pattern 19551524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia */ 19561524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia public boolean isValidNumber(PhoneNumber number) { 19571524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia String regionCode = getRegionCodeForNumber(number); 1958528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia return isValidNumberForRegion(number, regionCode); 19591524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } 19601524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia 19611524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia /** 19621524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * Tests whether a phone number is valid for a certain region. Note this doesn't verify the number 19631524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * is actually in use, which is impossible to tell by just looking at a number itself. If the 1964372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * country calling code is not the same as the country calling code for the region, this 1965372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * immediately exits with false. After this, the specific number pattern rules for the region are 1966372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * examined. This is useful for determining for example whether a particular number is valid for 1967372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * Canada, rather than just a valid NANPA number. 1968203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia * Warning: In most cases, you want to use {@link #isValidNumber} instead. For example, this 1969203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia * method will mark numbers from British Crown dependencies such as the Isle of Man as invalid for 1970203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia * the region "GB" (United Kingdom), since it has its own region code, "IM", which may be 1971203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia * undesirable. 19721524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * 19731524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * @param number the phone number that we want to validate 1974d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia * @param regionCode the region that we want to validate the phone number for 19751524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * @return a boolean that indicates whether the number is of a valid pattern 19761524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia */ 19771524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia public boolean isValidNumberForRegion(PhoneNumber number, String regionCode) { 1978528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia int countryCode = number.getCountryCode(); 1979cc0ae7326023c5da91dd9a84035c3dc3f6cc372fShaopeng Jia PhoneMetadata metadata = getMetadataForRegionOrCallingCode(countryCode, regionCode); 1980cc0ae7326023c5da91dd9a84035c3dc3f6cc372fShaopeng Jia if ((metadata == null) || 1981528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia (!REGION_CODE_FOR_NON_GEO_ENTITY.equals(regionCode) && 1982cc0ae7326023c5da91dd9a84035c3dc3f6cc372fShaopeng Jia countryCode != getCountryCodeForValidRegion(regionCode))) { 1983cc0ae7326023c5da91dd9a84035c3dc3f6cc372fShaopeng Jia // Either the region code was invalid, or the country calling code for this number does not 1984cc0ae7326023c5da91dd9a84035c3dc3f6cc372fShaopeng Jia // match that of the region code. 19851524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia return false; 19861524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } 19871524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia PhoneNumberDesc generalNumDesc = metadata.getGeneralDesc(); 19885c24149d269da6e7d7b6b2797df096fdea64a019Shaopeng Jia String nationalSignificantNumber = getNationalSignificantNumber(number); 19891524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia 1990372bff8dd464574d36737d47e495cad14346653cShaopeng Jia // For regions where we don't have metadata for PhoneNumberDesc, we treat any number passed in 1991372bff8dd464574d36737d47e495cad14346653cShaopeng Jia // as a valid number if its national significant number is between the minimum and maximum 19921524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia // lengths defined by ITU for a national significant number. 19931524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia if (!generalNumDesc.hasNationalNumberPattern()) { 19941524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia int numberLength = nationalSignificantNumber.length(); 19951524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia return numberLength > MIN_LENGTH_FOR_NSN && numberLength <= MAX_LENGTH_FOR_NSN; 19961524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } 199709104d6c45e3cfae9264367232dd17890e0e8675Shaopeng Jia return getNumberTypeHelper(nationalSignificantNumber, metadata) != PhoneNumberType.UNKNOWN; 19981524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } 19991524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia 20001524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia /** 2001372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * Returns the region where a phone number is from. This could be used for geocoding at the region 2002372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * level. 20031524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * 20041524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * @param number the phone number whose origin we want to know 2005372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * @return the region where the phone number is from, or null if no region matches this calling 2006372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * code 20071524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia */ 20081524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia public String getRegionCodeForNumber(PhoneNumber number) { 20091524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia int countryCode = number.getCountryCode(); 2010372bff8dd464574d36737d47e495cad14346653cShaopeng Jia List<String> regions = countryCallingCodeToRegionCodeMap.get(countryCode); 20114b7846722d1a5acb0577b07e98324f744f5e7942Shaopeng Jia if (regions == null) { 2012528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia String numberString = getNationalSignificantNumber(number); 2013528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia LOGGER.log(Level.WARNING, 2014528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia "Missing/invalid country_code (" + countryCode + ") for number " + numberString); 20154b7846722d1a5acb0577b07e98324f744f5e7942Shaopeng Jia return null; 20164b7846722d1a5acb0577b07e98324f744f5e7942Shaopeng Jia } 20174b7846722d1a5acb0577b07e98324f744f5e7942Shaopeng Jia if (regions.size() == 1) { 20184b7846722d1a5acb0577b07e98324f744f5e7942Shaopeng Jia return regions.get(0); 20194b7846722d1a5acb0577b07e98324f744f5e7942Shaopeng Jia } else { 20204b7846722d1a5acb0577b07e98324f744f5e7942Shaopeng Jia return getRegionCodeForNumberFromRegionList(number, regions); 20211524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } 20221524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } 20231524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia 20241524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia private String getRegionCodeForNumberFromRegionList(PhoneNumber number, 20254b7846722d1a5acb0577b07e98324f744f5e7942Shaopeng Jia List<String> regionCodes) { 2026372bff8dd464574d36737d47e495cad14346653cShaopeng Jia String nationalNumber = getNationalSignificantNumber(number); 20271524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia for (String regionCode : regionCodes) { 20284b7846722d1a5acb0577b07e98324f744f5e7942Shaopeng Jia // If leadingDigits is present, use this. Otherwise, do full validation. 2029203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia // Metadata cannot be null because the region codes come from the country calling code map. 20304b7846722d1a5acb0577b07e98324f744f5e7942Shaopeng Jia PhoneMetadata metadata = getMetadataForRegion(regionCode); 20314b7846722d1a5acb0577b07e98324f744f5e7942Shaopeng Jia if (metadata.hasLeadingDigits()) { 20324b7846722d1a5acb0577b07e98324f744f5e7942Shaopeng Jia if (regexCache.getPatternForRegex(metadata.getLeadingDigits()) 20334b7846722d1a5acb0577b07e98324f744f5e7942Shaopeng Jia .matcher(nationalNumber).lookingAt()) { 20344b7846722d1a5acb0577b07e98324f744f5e7942Shaopeng Jia return regionCode; 20354b7846722d1a5acb0577b07e98324f744f5e7942Shaopeng Jia } 20364b7846722d1a5acb0577b07e98324f744f5e7942Shaopeng Jia } else if (getNumberTypeHelper(nationalNumber, metadata) != PhoneNumberType.UNKNOWN) { 20371524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia return regionCode; 20381524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } 20391524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } 20401524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia return null; 20411524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } 20421524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia 20431524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia /** 2044372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * Returns the region code that matches the specific country calling code. In the case of no 2045372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * region code being found, ZZ will be returned. In the case of multiple regions, the one 2046372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * designated in the metadata as the "main" region for this calling code will be returned. 20471524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia */ 2048372bff8dd464574d36737d47e495cad14346653cShaopeng Jia public String getRegionCodeForCountryCode(int countryCallingCode) { 2049372bff8dd464574d36737d47e495cad14346653cShaopeng Jia List<String> regionCodes = countryCallingCodeToRegionCodeMap.get(countryCallingCode); 205074aa862e30b4d1b2722e90b1a8684274441a7541Shaopeng Jia return regionCodes == null ? UNKNOWN_REGION : regionCodes.get(0); 20511524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } 20521524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia 20531524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia /** 2054203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia * Returns a list with the region codes that match the specific country calling code. For 2055203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia * non-geographical country calling codes, the region code 001 is returned. Also, in the case 2056203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia * of no region code being found, an empty list is returned. 2057203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia */ 2058203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia public List<String> getRegionCodesForCountryCode(int countryCallingCode) { 2059203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia List<String> regionCodes = countryCallingCodeToRegionCodeMap.get(countryCallingCode); 2060203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia return Collections.unmodifiableList(regionCodes == null ? new ArrayList<String>(0) 2061203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia : regionCodes); 2062203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia } 2063203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia 2064203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia /** 20651524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * Returns the country calling code for a specific region. For example, this would be 1 for the 20661524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * United States, and 64 for New Zealand. 20671524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * 2068d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia * @param regionCode the region that we want to get the country calling code for 2069372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * @return the country calling code for the region denoted by regionCode 20701524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia */ 20711524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia public int getCountryCodeForRegion(String regionCode) { 2072be1af2f8b62d5435eca48f3dd5c82e3d2c9bfa17Shaopeng Jia if (!isValidRegionCode(regionCode)) { 2073cc0ae7326023c5da91dd9a84035c3dc3f6cc372fShaopeng Jia LOGGER.log(Level.WARNING, 2074528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia "Invalid or missing region code (" 2075528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia + ((regionCode == null) ? "null" : regionCode) 2076528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia + ") provided."); 20771524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia return 0; 20781524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } 2079cc0ae7326023c5da91dd9a84035c3dc3f6cc372fShaopeng Jia return getCountryCodeForValidRegion(regionCode); 2080cc0ae7326023c5da91dd9a84035c3dc3f6cc372fShaopeng Jia } 2081cc0ae7326023c5da91dd9a84035c3dc3f6cc372fShaopeng Jia 2082cc0ae7326023c5da91dd9a84035c3dc3f6cc372fShaopeng Jia /** 2083cc0ae7326023c5da91dd9a84035c3dc3f6cc372fShaopeng Jia * Returns the country calling code for a specific region. For example, this would be 1 for the 2084cc0ae7326023c5da91dd9a84035c3dc3f6cc372fShaopeng Jia * United States, and 64 for New Zealand. Assumes the region is already valid. 2085cc0ae7326023c5da91dd9a84035c3dc3f6cc372fShaopeng Jia * 2086cc0ae7326023c5da91dd9a84035c3dc3f6cc372fShaopeng Jia * @param regionCode the region that we want to get the country calling code for 2087cc0ae7326023c5da91dd9a84035c3dc3f6cc372fShaopeng Jia * @return the country calling code for the region denoted by regionCode 2088203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia * @throws IllegalArgumentException if the region is invalid 2089cc0ae7326023c5da91dd9a84035c3dc3f6cc372fShaopeng Jia */ 2090cc0ae7326023c5da91dd9a84035c3dc3f6cc372fShaopeng Jia private int getCountryCodeForValidRegion(String regionCode) { 2091be1af2f8b62d5435eca48f3dd5c82e3d2c9bfa17Shaopeng Jia PhoneMetadata metadata = getMetadataForRegion(regionCode); 2092203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia if (metadata == null) { 2093203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia throw new IllegalArgumentException("Invalid region code: " + regionCode); 2094203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia } 20951524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia return metadata.getCountryCode(); 20961524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } 20971524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia 20981524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia /** 2099f59ccfca9dd02c4e3cf3e06b5cf184a8d0e67626Shaopeng Jia * Returns the national dialling prefix for a specific region. For example, this would be 1 for 2100f59ccfca9dd02c4e3cf3e06b5cf184a8d0e67626Shaopeng Jia * the United States, and 0 for New Zealand. Set stripNonDigits to true to strip symbols like "~" 2101f59ccfca9dd02c4e3cf3e06b5cf184a8d0e67626Shaopeng Jia * (which indicates a wait for a dialling tone) from the prefix returned. If no national prefix is 2102f59ccfca9dd02c4e3cf3e06b5cf184a8d0e67626Shaopeng Jia * present, we return null. 2103f59ccfca9dd02c4e3cf3e06b5cf184a8d0e67626Shaopeng Jia * 2104372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * <p>Warning: Do not use this method for do-your-own formatting - for some regions, the 2105372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * national dialling prefix is used only for certain types of numbers. Use the library's 2106372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * formatting functions to prefix the national prefix when required. 2107f59ccfca9dd02c4e3cf3e06b5cf184a8d0e67626Shaopeng Jia * 2108d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia * @param regionCode the region that we want to get the dialling prefix for 2109f59ccfca9dd02c4e3cf3e06b5cf184a8d0e67626Shaopeng Jia * @param stripNonDigits true to strip non-digits from the national dialling prefix 2110372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * @return the dialling prefix for the region denoted by regionCode 2111f59ccfca9dd02c4e3cf3e06b5cf184a8d0e67626Shaopeng Jia */ 2112f59ccfca9dd02c4e3cf3e06b5cf184a8d0e67626Shaopeng Jia public String getNddPrefixForRegion(String regionCode, boolean stripNonDigits) { 2113203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia PhoneMetadata metadata = getMetadataForRegion(regionCode); 2114203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia if (metadata == null) { 2115cc0ae7326023c5da91dd9a84035c3dc3f6cc372fShaopeng Jia LOGGER.log(Level.WARNING, 2116528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia "Invalid or missing region code (" 2117528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia + ((regionCode == null) ? "null" : regionCode) 2118528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia + ") provided."); 2119f59ccfca9dd02c4e3cf3e06b5cf184a8d0e67626Shaopeng Jia return null; 2120f59ccfca9dd02c4e3cf3e06b5cf184a8d0e67626Shaopeng Jia } 2121f59ccfca9dd02c4e3cf3e06b5cf184a8d0e67626Shaopeng Jia String nationalPrefix = metadata.getNationalPrefix(); 2122f59ccfca9dd02c4e3cf3e06b5cf184a8d0e67626Shaopeng Jia // If no national prefix was found, we return null. 2123f59ccfca9dd02c4e3cf3e06b5cf184a8d0e67626Shaopeng Jia if (nationalPrefix.length() == 0) { 2124f59ccfca9dd02c4e3cf3e06b5cf184a8d0e67626Shaopeng Jia return null; 2125f59ccfca9dd02c4e3cf3e06b5cf184a8d0e67626Shaopeng Jia } 2126f59ccfca9dd02c4e3cf3e06b5cf184a8d0e67626Shaopeng Jia if (stripNonDigits) { 2127f59ccfca9dd02c4e3cf3e06b5cf184a8d0e67626Shaopeng Jia // Note: if any other non-numeric symbols are ever used in national prefixes, these would have 2128f59ccfca9dd02c4e3cf3e06b5cf184a8d0e67626Shaopeng Jia // to be removed here as well. 2129f59ccfca9dd02c4e3cf3e06b5cf184a8d0e67626Shaopeng Jia nationalPrefix = nationalPrefix.replace("~", ""); 2130f59ccfca9dd02c4e3cf3e06b5cf184a8d0e67626Shaopeng Jia } 2131f59ccfca9dd02c4e3cf3e06b5cf184a8d0e67626Shaopeng Jia return nationalPrefix; 2132f59ccfca9dd02c4e3cf3e06b5cf184a8d0e67626Shaopeng Jia } 2133f59ccfca9dd02c4e3cf3e06b5cf184a8d0e67626Shaopeng Jia 2134f59ccfca9dd02c4e3cf3e06b5cf184a8d0e67626Shaopeng Jia /** 2135372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * Checks if this is a region under the North American Numbering Plan Administration (NANPA). 21361524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * 2137372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * @return true if regionCode is one of the regions under NANPA 21381524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia */ 21397900ea273b8c33b3c6f70d7dd559127938d0fc3dShaopeng Jia public boolean isNANPACountry(String regionCode) { 2140f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia return nanpaRegions.contains(regionCode); 2141372bff8dd464574d36737d47e495cad14346653cShaopeng Jia } 2142372bff8dd464574d36737d47e495cad14346653cShaopeng Jia 2143372bff8dd464574d36737d47e495cad14346653cShaopeng Jia /** 21449651f4d6f2740017c0c4ea9c1c340af6f644d609Shaopeng Jia * Checks whether the country calling code is from a region whose national significant number 21459651f4d6f2740017c0c4ea9c1c340af6f644d609Shaopeng Jia * could contain a leading zero. An example of such a region is Italy. Returns false if no 21469651f4d6f2740017c0c4ea9c1c340af6f644d609Shaopeng Jia * metadata for the country is found. 2147372bff8dd464574d36737d47e495cad14346653cShaopeng Jia */ 2148f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia boolean isLeadingZeroPossible(int countryCallingCode) { 2149203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia PhoneMetadata mainMetadataForCallingCode = 2150203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia getMetadataForRegionOrCallingCode(countryCallingCode, 2151203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia getRegionCodeForCountryCode(countryCallingCode)); 2152372bff8dd464574d36737d47e495cad14346653cShaopeng Jia if (mainMetadataForCallingCode == null) { 2153372bff8dd464574d36737d47e495cad14346653cShaopeng Jia return false; 2154372bff8dd464574d36737d47e495cad14346653cShaopeng Jia } 2155372bff8dd464574d36737d47e495cad14346653cShaopeng Jia return mainMetadataForCallingCode.isLeadingZeroPossible(); 21561524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } 21571524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia 21581524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia /** 2159372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * Checks if the number is a valid vanity (alpha) number such as 800 MICROSOFT. A valid vanity 2160372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * number will start with at least 3 digits and will have three or more alpha characters. This 2161372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * does not do region-specific checks - to work out if this number is actually valid for a region, 2162372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * it should be parsed and methods such as {@link #isPossibleNumberWithReason} and 2163372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * {@link #isValidNumber} should be used. 2164372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * 2165372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * @param number the number that needs to be checked 2166372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * @return true if the number is a valid vanity number 2167f59ccfca9dd02c4e3cf3e06b5cf184a8d0e67626Shaopeng Jia */ 2168372bff8dd464574d36737d47e495cad14346653cShaopeng Jia public boolean isAlphaNumber(String number) { 2169372bff8dd464574d36737d47e495cad14346653cShaopeng Jia if (!isViablePhoneNumber(number)) { 2170372bff8dd464574d36737d47e495cad14346653cShaopeng Jia // Number is too short, or doesn't match the basic phone number pattern. 2171372bff8dd464574d36737d47e495cad14346653cShaopeng Jia return false; 2172372bff8dd464574d36737d47e495cad14346653cShaopeng Jia } 2173372bff8dd464574d36737d47e495cad14346653cShaopeng Jia StringBuilder strippedNumber = new StringBuilder(number); 2174372bff8dd464574d36737d47e495cad14346653cShaopeng Jia maybeStripExtension(strippedNumber); 2175372bff8dd464574d36737d47e495cad14346653cShaopeng Jia return VALID_ALPHA_PHONE_PATTERN.matcher(strippedNumber).matches(); 2176f59ccfca9dd02c4e3cf3e06b5cf184a8d0e67626Shaopeng Jia } 2177f59ccfca9dd02c4e3cf3e06b5cf184a8d0e67626Shaopeng Jia 2178f59ccfca9dd02c4e3cf3e06b5cf184a8d0e67626Shaopeng Jia /** 2179372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * Convenience wrapper around {@link #isPossibleNumberWithReason}. Instead of returning the reason 2180372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * for failure, this method returns a boolean value. 21811524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * @param number the number that needs to be checked 21821524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * @return true if the number is possible 21831524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia */ 21841524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia public boolean isPossibleNumber(PhoneNumber number) { 21851524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia return isPossibleNumberWithReason(number) == ValidationResult.IS_POSSIBLE; 21861524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } 21871524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia 21881524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia /** 2189372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * Helper method to check a number against a particular pattern and determine whether it matches, 2190372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * or is too short or too long. Currently, if a number pattern suggests that numbers of length 7 2191372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * and 10 are possible, and a number in between these possible lengths is entered, such as of 2192372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * length 8, this will return TOO_LONG. 2193372bff8dd464574d36737d47e495cad14346653cShaopeng Jia */ 2194372bff8dd464574d36737d47e495cad14346653cShaopeng Jia private ValidationResult testNumberLengthAgainstPattern(Pattern numberPattern, String number) { 2195372bff8dd464574d36737d47e495cad14346653cShaopeng Jia Matcher numberMatcher = numberPattern.matcher(number); 2196372bff8dd464574d36737d47e495cad14346653cShaopeng Jia if (numberMatcher.matches()) { 2197372bff8dd464574d36737d47e495cad14346653cShaopeng Jia return ValidationResult.IS_POSSIBLE; 2198372bff8dd464574d36737d47e495cad14346653cShaopeng Jia } 2199372bff8dd464574d36737d47e495cad14346653cShaopeng Jia if (numberMatcher.lookingAt()) { 2200372bff8dd464574d36737d47e495cad14346653cShaopeng Jia return ValidationResult.TOO_LONG; 2201372bff8dd464574d36737d47e495cad14346653cShaopeng Jia } else { 2202372bff8dd464574d36737d47e495cad14346653cShaopeng Jia return ValidationResult.TOO_SHORT; 2203372bff8dd464574d36737d47e495cad14346653cShaopeng Jia } 2204372bff8dd464574d36737d47e495cad14346653cShaopeng Jia } 2205372bff8dd464574d36737d47e495cad14346653cShaopeng Jia 2206372bff8dd464574d36737d47e495cad14346653cShaopeng Jia /** 22071524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * Check whether a phone number is a possible number. It provides a more lenient check than 2208372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * {@link #isValidNumber} in the following sense: 2209372bff8dd464574d36737d47e495cad14346653cShaopeng Jia *<ol> 2210372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * <li> It only checks the length of phone numbers. In particular, it doesn't check starting 22111524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * digits of the number. 2212372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * <li> It doesn't attempt to figure out the type of the number, but uses general rules which 2213372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * applies to all types of phone numbers in a region. Therefore, it is much faster than 22141524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * isValidNumber. 2215372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * <li> For fixed line numbers, many regions have the concept of area code, which together with 22161524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * subscriber number constitute the national significant number. It is sometimes okay to dial 22171524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * the subscriber number only when dialing in the same area. This function will return 22181524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * true if the subscriber-number-only version is passed in. On the other hand, because 22191524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * isValidNumber validates using information on both starting digits (for fixed line 22201524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * numbers, that would most likely be area codes) and length (obviously includes the 22211524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * length of area codes for fixed line numbers), it will return false for the 22221524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * subscriber-number-only version. 2223203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia * </ol> 22241524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * @param number the number that needs to be checked 22251524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * @return a ValidationResult object which indicates whether the number is possible 22261524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia */ 22271524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia public ValidationResult isPossibleNumberWithReason(PhoneNumber number) { 2228372bff8dd464574d36737d47e495cad14346653cShaopeng Jia String nationalNumber = getNationalSignificantNumber(number); 22291524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia int countryCode = number.getCountryCode(); 22301524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia // Note: For Russian Fed and NANPA numbers, we just use the rules from the default region (US or 22311524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia // Russia) since the getRegionCodeForNumber will not work if the number is possible but not 22321524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia // valid. This would need to be revisited if the possible number pattern ever differed between 2233372bff8dd464574d36737d47e495cad14346653cShaopeng Jia // various regions within those plans. 2234528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia if (!hasValidCountryCallingCode(countryCode)) { 22351524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia return ValidationResult.INVALID_COUNTRY_CODE; 22361524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } 2237528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia String regionCode = getRegionCodeForCountryCode(countryCode); 2238203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia // Metadata cannot be null because the country calling code is valid. 2239528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia PhoneMetadata metadata = getMetadataForRegionOrCallingCode(countryCode, regionCode); 2240528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia PhoneNumberDesc generalNumDesc = metadata.getGeneralDesc(); 22414b7846722d1a5acb0577b07e98324f744f5e7942Shaopeng Jia // Handling case of numbers with no metadata. 22424b7846722d1a5acb0577b07e98324f744f5e7942Shaopeng Jia if (!generalNumDesc.hasNationalNumberPattern()) { 22434b7846722d1a5acb0577b07e98324f744f5e7942Shaopeng Jia LOGGER.log(Level.FINER, "Checking if number is possible with incomplete metadata."); 22444b7846722d1a5acb0577b07e98324f744f5e7942Shaopeng Jia int numberLength = nationalNumber.length(); 22454b7846722d1a5acb0577b07e98324f744f5e7942Shaopeng Jia if (numberLength < MIN_LENGTH_FOR_NSN) { 22464b7846722d1a5acb0577b07e98324f744f5e7942Shaopeng Jia return ValidationResult.TOO_SHORT; 22474b7846722d1a5acb0577b07e98324f744f5e7942Shaopeng Jia } else if (numberLength > MAX_LENGTH_FOR_NSN) { 22484b7846722d1a5acb0577b07e98324f744f5e7942Shaopeng Jia return ValidationResult.TOO_LONG; 22494b7846722d1a5acb0577b07e98324f744f5e7942Shaopeng Jia } else { 22504b7846722d1a5acb0577b07e98324f744f5e7942Shaopeng Jia return ValidationResult.IS_POSSIBLE; 22514b7846722d1a5acb0577b07e98324f744f5e7942Shaopeng Jia } 22524b7846722d1a5acb0577b07e98324f744f5e7942Shaopeng Jia } 2253372bff8dd464574d36737d47e495cad14346653cShaopeng Jia Pattern possibleNumberPattern = 2254372bff8dd464574d36737d47e495cad14346653cShaopeng Jia regexCache.getPatternForRegex(generalNumDesc.getPossibleNumberPattern()); 2255372bff8dd464574d36737d47e495cad14346653cShaopeng Jia return testNumberLengthAgainstPattern(possibleNumberPattern, nationalNumber); 22561524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } 22571524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia 22581524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia /** 22591524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * Check whether a phone number is a possible number given a number in the form of a string, and 2260372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * the region where the number could be dialed from. It provides a more lenient check than 226196a7214cdabf08f53f5b1a560304601c9f65e0b9Shaopeng Jia * {@link #isValidNumber}. See {@link #isPossibleNumber(PhoneNumber)} for details. 22621524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * 226396a7214cdabf08f53f5b1a560304601c9f65e0b9Shaopeng Jia * <p>This method first parses the number, then invokes {@link #isPossibleNumber(PhoneNumber)} 226496a7214cdabf08f53f5b1a560304601c9f65e0b9Shaopeng Jia * with the resultant PhoneNumber object. 22651524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * 22661524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * @param number the number that needs to be checked, in the form of a string 2267d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia * @param regionDialingFrom the region that we are expecting the number to be dialed from. 2268372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * Note this is different from the region where the number belongs. For example, the number 2269372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * +1 650 253 0000 is a number that belongs to US. When written in this form, it can be 2270372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * dialed from any region. When it is written as 00 1 650 253 0000, it can be dialed from any 2271372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * region which uses an international dialling prefix of 00. When it is written as 2272372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * 650 253 0000, it can only be dialed from within the US, and when written as 253 0000, it 2273372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * can only be dialed from within a smaller area in the US (Mountain View, CA, to be more 227474aa862e30b4d1b2722e90b1a8684274441a7541Shaopeng Jia * specific). 22751524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * @return true if the number is possible 22761524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia */ 2277372bff8dd464574d36737d47e495cad14346653cShaopeng Jia public boolean isPossibleNumber(String number, String regionDialingFrom) { 22781524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia try { 2279372bff8dd464574d36737d47e495cad14346653cShaopeng Jia return isPossibleNumber(parse(number, regionDialingFrom)); 22801524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } catch (NumberParseException e) { 22811524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia return false; 22821524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } 22831524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } 22841524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia 22851524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia /** 2286df19cbfb8a1e8720bae76bb763ab29622e057c42Shaopeng Jia * Attempts to extract a valid number from a phone number that is too long to be valid, and resets 2287df19cbfb8a1e8720bae76bb763ab29622e057c42Shaopeng Jia * the PhoneNumber object passed in to that valid version. If no valid number could be extracted, 2288df19cbfb8a1e8720bae76bb763ab29622e057c42Shaopeng Jia * the PhoneNumber object passed in will not be modified. 2289df19cbfb8a1e8720bae76bb763ab29622e057c42Shaopeng Jia * @param number a PhoneNumber object which contains a number that is too long to be valid. 2290df19cbfb8a1e8720bae76bb763ab29622e057c42Shaopeng Jia * @return true if a valid phone number can be successfully extracted. 2291df19cbfb8a1e8720bae76bb763ab29622e057c42Shaopeng Jia */ 2292df19cbfb8a1e8720bae76bb763ab29622e057c42Shaopeng Jia public boolean truncateTooLongNumber(PhoneNumber number) { 2293df19cbfb8a1e8720bae76bb763ab29622e057c42Shaopeng Jia if (isValidNumber(number)) { 2294df19cbfb8a1e8720bae76bb763ab29622e057c42Shaopeng Jia return true; 2295df19cbfb8a1e8720bae76bb763ab29622e057c42Shaopeng Jia } 2296df19cbfb8a1e8720bae76bb763ab29622e057c42Shaopeng Jia PhoneNumber numberCopy = new PhoneNumber(); 2297df19cbfb8a1e8720bae76bb763ab29622e057c42Shaopeng Jia numberCopy.mergeFrom(number); 2298df19cbfb8a1e8720bae76bb763ab29622e057c42Shaopeng Jia long nationalNumber = number.getNationalNumber(); 2299df19cbfb8a1e8720bae76bb763ab29622e057c42Shaopeng Jia do { 2300df19cbfb8a1e8720bae76bb763ab29622e057c42Shaopeng Jia nationalNumber /= 10; 2301df19cbfb8a1e8720bae76bb763ab29622e057c42Shaopeng Jia numberCopy.setNationalNumber(nationalNumber); 2302df19cbfb8a1e8720bae76bb763ab29622e057c42Shaopeng Jia if (isPossibleNumberWithReason(numberCopy) == ValidationResult.TOO_SHORT || 2303df19cbfb8a1e8720bae76bb763ab29622e057c42Shaopeng Jia nationalNumber == 0) { 2304df19cbfb8a1e8720bae76bb763ab29622e057c42Shaopeng Jia return false; 2305df19cbfb8a1e8720bae76bb763ab29622e057c42Shaopeng Jia } 2306df19cbfb8a1e8720bae76bb763ab29622e057c42Shaopeng Jia } while (!isValidNumber(numberCopy)); 2307df19cbfb8a1e8720bae76bb763ab29622e057c42Shaopeng Jia number.setNationalNumber(nationalNumber); 2308df19cbfb8a1e8720bae76bb763ab29622e057c42Shaopeng Jia return true; 2309df19cbfb8a1e8720bae76bb763ab29622e057c42Shaopeng Jia } 2310df19cbfb8a1e8720bae76bb763ab29622e057c42Shaopeng Jia 2311df19cbfb8a1e8720bae76bb763ab29622e057c42Shaopeng Jia /** 231293f6965c2c041ac707bf1b3bcf5a3f60e452f421Shaopeng Jia * Gets an {@link com.android.i18n.phonenumbers.AsYouTypeFormatter} for the specific region. 23131524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * 2314d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia * @param regionCode the region where the phone number is being entered 231593f6965c2c041ac707bf1b3bcf5a3f60e452f421Shaopeng Jia * @return an {@link com.android.i18n.phonenumbers.AsYouTypeFormatter} object, which can be used 2316372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * to format phone numbers in the specific region "as you type" 23171524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia */ 23181524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia public AsYouTypeFormatter getAsYouTypeFormatter(String regionCode) { 23191524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia return new AsYouTypeFormatter(regionCode); 23201524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } 23211524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia 2322372bff8dd464574d36737d47e495cad14346653cShaopeng Jia // Extracts country calling code from fullNumber, returns it and places the remaining number in 23231524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia // nationalNumber. It assumes that the leading plus sign or IDD has already been removed. Returns 2324372bff8dd464574d36737d47e495cad14346653cShaopeng Jia // 0 if fullNumber doesn't start with a valid country calling code, and leaves nationalNumber 2325372bff8dd464574d36737d47e495cad14346653cShaopeng Jia // unmodified. 2326372bff8dd464574d36737d47e495cad14346653cShaopeng Jia int extractCountryCode(StringBuilder fullNumber, StringBuilder nationalNumber) { 2327ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia if ((fullNumber.length() == 0) || (fullNumber.charAt(0) == '0')) { 2328ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia // Country codes do not begin with a '0'. 2329ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia return 0; 2330ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia } 23311524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia int potentialCountryCode; 2332df19cbfb8a1e8720bae76bb763ab29622e057c42Shaopeng Jia int numberLength = fullNumber.length(); 233374aa862e30b4d1b2722e90b1a8684274441a7541Shaopeng Jia for (int i = 1; i <= MAX_LENGTH_COUNTRY_CODE && i <= numberLength; i++) { 23341524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia potentialCountryCode = Integer.parseInt(fullNumber.substring(0, i)); 2335372bff8dd464574d36737d47e495cad14346653cShaopeng Jia if (countryCallingCodeToRegionCodeMap.containsKey(potentialCountryCode)) { 23361524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia nationalNumber.append(fullNumber.substring(i)); 23371524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia return potentialCountryCode; 23381524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } 23391524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } 23401524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia return 0; 23411524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } 23421524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia 23431524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia /** 2344372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * Tries to extract a country calling code from a number. This method will return zero if no 2345372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * country calling code is considered to be present. Country calling codes are extracted in the 2346372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * following ways: 2347372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * <ul> 2348372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * <li> by stripping the international dialing prefix of the region the person is dialing from, 23491524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * if this is present in the number, and looking at the next digits 2350372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * <li> by stripping the '+' sign if present and then looking at the next digits 2351372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * <li> by comparing the start of the number and the country calling code of the default region. 2352372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * If the number is not considered possible for the numbering plan of the default region 2353372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * initially, but starts with the country calling code of this region, validation will be 2354372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * reattempted after stripping this country calling code. If this number is considered a 2355372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * possible number, then the first digits will be considered the country calling code and 2356372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * removed as such. 2357372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * </ul> 2358372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * It will throw a NumberParseException if the number starts with a '+' but the country calling 2359372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * code supplied after this does not match that of any known region. 23601524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * 2361372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * @param number non-normalized telephone number that we wish to extract a country calling 23621524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * code from - may begin with '+' 23631524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * @param defaultRegionMetadata metadata about the region this number may be from 23641524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * @param nationalNumber a string buffer to store the national significant number in, in the case 2365372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * that a country calling code was extracted. The number is appended to any existing contents. 2366372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * If no country calling code was extracted, this will be left unchanged. 236752699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia * @param keepRawInput true if the country_code_source and preferred_carrier_code fields of 236852699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia * phoneNumber should be populated. 2369372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * @param phoneNumber the PhoneNumber object where the country_code and country_code_source need 2370372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * to be populated. Note the country_code is always populated, whereas country_code_source is 2371372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * only populated when keepCountryCodeSource is true. 2372372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * @return the country calling code extracted or 0 if none could be extracted 23731524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia */ 2374ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia // @VisibleForTesting 23751524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia int maybeExtractCountryCode(String number, PhoneMetadata defaultRegionMetadata, 2376372bff8dd464574d36737d47e495cad14346653cShaopeng Jia StringBuilder nationalNumber, boolean keepRawInput, 237776f6569af0619d12afd19991d8ff69a9bea4c142Shaopeng Jia PhoneNumber phoneNumber) 23781524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia throws NumberParseException { 23795c24149d269da6e7d7b6b2797df096fdea64a019Shaopeng Jia if (number.length() == 0) { 23805c24149d269da6e7d7b6b2797df096fdea64a019Shaopeng Jia return 0; 23815c24149d269da6e7d7b6b2797df096fdea64a019Shaopeng Jia } 2382372bff8dd464574d36737d47e495cad14346653cShaopeng Jia StringBuilder fullNumber = new StringBuilder(number); 23831524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia // Set the default prefix to be something that will never match. 23841524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia String possibleCountryIddPrefix = "NonMatch"; 23851524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia if (defaultRegionMetadata != null) { 23861524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia possibleCountryIddPrefix = defaultRegionMetadata.getInternationalPrefix(); 23871524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } 23885c24149d269da6e7d7b6b2797df096fdea64a019Shaopeng Jia 23895c24149d269da6e7d7b6b2797df096fdea64a019Shaopeng Jia CountryCodeSource countryCodeSource = 23905c24149d269da6e7d7b6b2797df096fdea64a019Shaopeng Jia maybeStripInternationalPrefixAndNormalize(fullNumber, possibleCountryIddPrefix); 239152699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia if (keepRawInput) { 23925c24149d269da6e7d7b6b2797df096fdea64a019Shaopeng Jia phoneNumber.setCountryCodeSource(countryCodeSource); 23935c24149d269da6e7d7b6b2797df096fdea64a019Shaopeng Jia } 23945c24149d269da6e7d7b6b2797df096fdea64a019Shaopeng Jia if (countryCodeSource != CountryCodeSource.FROM_DEFAULT_COUNTRY) { 2395bf5d9756fe9b13f5b2e0696c62949cea77396687Shaopeng Jia if (fullNumber.length() <= MIN_LENGTH_FOR_NSN) { 23961524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia throw new NumberParseException(NumberParseException.ErrorType.TOO_SHORT_AFTER_IDD, 23971524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia "Phone number had an IDD, but after this was not " 23981524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia + "long enough to be a viable phone number."); 23991524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } 24001524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia int potentialCountryCode = extractCountryCode(fullNumber, nationalNumber); 24011524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia if (potentialCountryCode != 0) { 24025c24149d269da6e7d7b6b2797df096fdea64a019Shaopeng Jia phoneNumber.setCountryCode(potentialCountryCode); 24031524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia return potentialCountryCode; 24041524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } 24051524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia 2406372bff8dd464574d36737d47e495cad14346653cShaopeng Jia // If this fails, they must be using a strange country calling code that we don't recognize, 2407372bff8dd464574d36737d47e495cad14346653cShaopeng Jia // or that doesn't exist. 24081524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia throw new NumberParseException(NumberParseException.ErrorType.INVALID_COUNTRY_CODE, 2409372bff8dd464574d36737d47e495cad14346653cShaopeng Jia "Country calling code supplied was not recognised."); 24101524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } else if (defaultRegionMetadata != null) { 2411372bff8dd464574d36737d47e495cad14346653cShaopeng Jia // Check to see if the number starts with the country calling code for the default region. If 2412372bff8dd464574d36737d47e495cad14346653cShaopeng Jia // so, we remove the country calling code, and do some checks on the validity of the number 2413372bff8dd464574d36737d47e495cad14346653cShaopeng Jia // before and after. 2414372bff8dd464574d36737d47e495cad14346653cShaopeng Jia int defaultCountryCode = defaultRegionMetadata.getCountryCode(); 2415372bff8dd464574d36737d47e495cad14346653cShaopeng Jia String defaultCountryCodeString = String.valueOf(defaultCountryCode); 2416372bff8dd464574d36737d47e495cad14346653cShaopeng Jia String normalizedNumber = fullNumber.toString(); 2417372bff8dd464574d36737d47e495cad14346653cShaopeng Jia if (normalizedNumber.startsWith(defaultCountryCodeString)) { 2418372bff8dd464574d36737d47e495cad14346653cShaopeng Jia StringBuilder potentialNationalNumber = 2419372bff8dd464574d36737d47e495cad14346653cShaopeng Jia new StringBuilder(normalizedNumber.substring(defaultCountryCodeString.length())); 2420372bff8dd464574d36737d47e495cad14346653cShaopeng Jia PhoneNumberDesc generalDesc = defaultRegionMetadata.getGeneralDesc(); 2421372bff8dd464574d36737d47e495cad14346653cShaopeng Jia Pattern validNumberPattern = 2422372bff8dd464574d36737d47e495cad14346653cShaopeng Jia regexCache.getPatternForRegex(generalDesc.getNationalNumberPattern()); 2423a48b2d221ba46df7446d1a87244efa985e8e292fShaopeng Jia maybeStripNationalPrefixAndCarrierCode( 2424a48b2d221ba46df7446d1a87244efa985e8e292fShaopeng Jia potentialNationalNumber, defaultRegionMetadata, null /* Don't need the carrier code */); 2425372bff8dd464574d36737d47e495cad14346653cShaopeng Jia Pattern possibleNumberPattern = 2426372bff8dd464574d36737d47e495cad14346653cShaopeng Jia regexCache.getPatternForRegex(generalDesc.getPossibleNumberPattern()); 2427372bff8dd464574d36737d47e495cad14346653cShaopeng Jia // If the number was not valid before but is valid now, or if it was too long before, we 2428372bff8dd464574d36737d47e495cad14346653cShaopeng Jia // consider the number with the country calling code stripped to be a better result and 2429372bff8dd464574d36737d47e495cad14346653cShaopeng Jia // keep that instead. 2430372bff8dd464574d36737d47e495cad14346653cShaopeng Jia if ((!validNumberPattern.matcher(fullNumber).matches() && 2431372bff8dd464574d36737d47e495cad14346653cShaopeng Jia validNumberPattern.matcher(potentialNationalNumber).matches()) || 2432372bff8dd464574d36737d47e495cad14346653cShaopeng Jia testNumberLengthAgainstPattern(possibleNumberPattern, fullNumber.toString()) 2433372bff8dd464574d36737d47e495cad14346653cShaopeng Jia == ValidationResult.TOO_LONG) { 2434372bff8dd464574d36737d47e495cad14346653cShaopeng Jia nationalNumber.append(potentialNationalNumber); 2435372bff8dd464574d36737d47e495cad14346653cShaopeng Jia if (keepRawInput) { 2436372bff8dd464574d36737d47e495cad14346653cShaopeng Jia phoneNumber.setCountryCodeSource(CountryCodeSource.FROM_NUMBER_WITHOUT_PLUS_SIGN); 24371524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } 2438372bff8dd464574d36737d47e495cad14346653cShaopeng Jia phoneNumber.setCountryCode(defaultCountryCode); 2439372bff8dd464574d36737d47e495cad14346653cShaopeng Jia return defaultCountryCode; 24401524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } 24411524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } 24421524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } 2443372bff8dd464574d36737d47e495cad14346653cShaopeng Jia // No country calling code present. 24445c24149d269da6e7d7b6b2797df096fdea64a019Shaopeng Jia phoneNumber.setCountryCode(0); 24451524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia return 0; 24461524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } 24471524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia 24481524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia /** 24491524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * Strips the IDD from the start of the number if present. Helper function used by 24501524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * maybeStripInternationalPrefixAndNormalize. 24511524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia */ 2452372bff8dd464574d36737d47e495cad14346653cShaopeng Jia private boolean parsePrefixAsIdd(Pattern iddPattern, StringBuilder number) { 24531524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia Matcher m = iddPattern.matcher(number); 24541524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia if (m.lookingAt()) { 24551524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia int matchEnd = m.end(); 2456372bff8dd464574d36737d47e495cad14346653cShaopeng Jia // Only strip this if the first digit after the match is not a 0, since country calling codes 2457372bff8dd464574d36737d47e495cad14346653cShaopeng Jia // cannot begin with 0. 24581524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia Matcher digitMatcher = CAPTURING_DIGIT_PATTERN.matcher(number.substring(matchEnd)); 24591524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia if (digitMatcher.find()) { 2460d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia String normalizedGroup = normalizeDigitsOnly(digitMatcher.group(1)); 24611524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia if (normalizedGroup.equals("0")) { 24621524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia return false; 24631524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } 24641524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } 24651524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia number.delete(0, matchEnd); 24661524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia return true; 24671524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } 24681524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia return false; 24691524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } 24701524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia 24711524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia /** 24721524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * Strips any international prefix (such as +, 00, 011) present in the number provided, normalizes 2473f59ccfca9dd02c4e3cf3e06b5cf184a8d0e67626Shaopeng Jia * the resulting number, and indicates if an international prefix was present. 24741524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * 24751524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * @param number the non-normalized telephone number that we wish to strip any international 247674aa862e30b4d1b2722e90b1a8684274441a7541Shaopeng Jia * dialing prefix from. 2477372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * @param possibleIddPrefix the international direct dialing prefix from the region we 24781524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * think this number may be dialed in 24795c24149d269da6e7d7b6b2797df096fdea64a019Shaopeng Jia * @return the corresponding CountryCodeSource if an international dialing prefix could be 2480372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * removed from the number, otherwise CountryCodeSource.FROM_DEFAULT_COUNTRY if the number did 2481372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * not seem to be in international format. 24821524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia */ 2483ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia // @VisibleForTesting 24845c24149d269da6e7d7b6b2797df096fdea64a019Shaopeng Jia CountryCodeSource maybeStripInternationalPrefixAndNormalize( 2485372bff8dd464574d36737d47e495cad14346653cShaopeng Jia StringBuilder number, 24865c24149d269da6e7d7b6b2797df096fdea64a019Shaopeng Jia String possibleIddPrefix) { 24871524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia if (number.length() == 0) { 24885c24149d269da6e7d7b6b2797df096fdea64a019Shaopeng Jia return CountryCodeSource.FROM_DEFAULT_COUNTRY; 24891524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } 2490256a5f71a05ffd182a0fda2cfed6f93345cc889fLara Rennie // Check to see if the number begins with one or more plus signs. 2491256a5f71a05ffd182a0fda2cfed6f93345cc889fLara Rennie Matcher m = PLUS_CHARS_PATTERN.matcher(number); 2492256a5f71a05ffd182a0fda2cfed6f93345cc889fLara Rennie if (m.lookingAt()) { 2493256a5f71a05ffd182a0fda2cfed6f93345cc889fLara Rennie number.delete(0, m.end()); 24941524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia // Can now normalize the rest of the number since we've consumed the "+" sign at the start. 24951524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia normalize(number); 24965c24149d269da6e7d7b6b2797df096fdea64a019Shaopeng Jia return CountryCodeSource.FROM_NUMBER_WITH_PLUS_SIGN; 24971524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } 24981524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia // Attempt to parse the first digits as an international prefix. 2499be1af2f8b62d5435eca48f3dd5c82e3d2c9bfa17Shaopeng Jia Pattern iddPattern = regexCache.getPatternForRegex(possibleIddPrefix); 25001524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia normalize(number); 25015c24149d269da6e7d7b6b2797df096fdea64a019Shaopeng Jia return parsePrefixAsIdd(iddPattern, number) 2502f59ccfca9dd02c4e3cf3e06b5cf184a8d0e67626Shaopeng Jia ? CountryCodeSource.FROM_NUMBER_WITH_IDD 2503f59ccfca9dd02c4e3cf3e06b5cf184a8d0e67626Shaopeng Jia : CountryCodeSource.FROM_DEFAULT_COUNTRY; 25041524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } 25051524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia 25061524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia /** 25071524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * Strips any national prefix (such as 0, 1) present in the number provided. 25081524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * 25091524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * @param number the normalized telephone number that we wish to strip any national 25101524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * dialing prefix from 2511372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * @param metadata the metadata for the region that we think this number is from 2512a48b2d221ba46df7446d1a87244efa985e8e292fShaopeng Jia * @param carrierCode a place to insert the carrier code if one is extracted 2513a48b2d221ba46df7446d1a87244efa985e8e292fShaopeng Jia * @return true if a national prefix or carrier code (or both) could be extracted. 25141524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia */ 2515ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia // @VisibleForTesting 2516a48b2d221ba46df7446d1a87244efa985e8e292fShaopeng Jia boolean maybeStripNationalPrefixAndCarrierCode( 2517a48b2d221ba46df7446d1a87244efa985e8e292fShaopeng Jia StringBuilder number, PhoneMetadata metadata, StringBuilder carrierCode) { 25181524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia int numberLength = number.length(); 251952699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia String possibleNationalPrefix = metadata.getNationalPrefixForParsing(); 2520be1af2f8b62d5435eca48f3dd5c82e3d2c9bfa17Shaopeng Jia if (numberLength == 0 || possibleNationalPrefix.length() == 0) { 25211524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia // Early return for numbers of zero length. 2522a48b2d221ba46df7446d1a87244efa985e8e292fShaopeng Jia return false; 25231524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } 25241524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia // Attempt to parse the first digits as a national prefix. 252552699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia Matcher prefixMatcher = regexCache.getPatternForRegex(possibleNationalPrefix).matcher(number); 252652699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia if (prefixMatcher.lookingAt()) { 252752699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia Pattern nationalNumberRule = 252852699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia regexCache.getPatternForRegex(metadata.getGeneralDesc().getNationalNumberPattern()); 2529f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia // Check if the original number is viable. 2530f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia boolean isViableOriginalNumber = nationalNumberRule.matcher(number).matches(); 253152699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia // prefixMatcher.group(numOfGroups) == null implies nothing was captured by the capturing 253252699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia // groups in possibleNationalPrefix; therefore, no transformation is necessary, and we just 253352699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia // remove the national prefix. 253452699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia int numOfGroups = prefixMatcher.groupCount(); 253552699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia String transformRule = metadata.getNationalPrefixTransformRule(); 253652699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia if (transformRule == null || transformRule.length() == 0 || 253752699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia prefixMatcher.group(numOfGroups) == null) { 2538f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia // If the original number was viable, and the resultant number is not, we return. 2539f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia if (isViableOriginalNumber && 2540f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia !nationalNumberRule.matcher(number.substring(prefixMatcher.end())).matches()) { 2541a48b2d221ba46df7446d1a87244efa985e8e292fShaopeng Jia return false; 254252699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia } 2543a48b2d221ba46df7446d1a87244efa985e8e292fShaopeng Jia if (carrierCode != null && numOfGroups > 0 && prefixMatcher.group(numOfGroups) != null) { 2544a48b2d221ba46df7446d1a87244efa985e8e292fShaopeng Jia carrierCode.append(prefixMatcher.group(1)); 25451524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } 254652699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia number.delete(0, prefixMatcher.end()); 2547a48b2d221ba46df7446d1a87244efa985e8e292fShaopeng Jia return true; 25481524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } else { 2549f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia // Check that the resultant number is still viable. If not, return. Check this by copying 2550f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia // the string buffer and making the transformation on the copy first. 2551372bff8dd464574d36737d47e495cad14346653cShaopeng Jia StringBuilder transformedNumber = new StringBuilder(number); 255252699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia transformedNumber.replace(0, numberLength, prefixMatcher.replaceFirst(transformRule)); 2553f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia if (isViableOriginalNumber && 2554f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia !nationalNumberRule.matcher(transformedNumber.toString()).matches()) { 2555a48b2d221ba46df7446d1a87244efa985e8e292fShaopeng Jia return false; 255652699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia } 2557a48b2d221ba46df7446d1a87244efa985e8e292fShaopeng Jia if (carrierCode != null && numOfGroups > 1) { 2558a48b2d221ba46df7446d1a87244efa985e8e292fShaopeng Jia carrierCode.append(prefixMatcher.group(1)); 25591524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } 25601524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia number.replace(0, number.length(), transformedNumber.toString()); 2561a48b2d221ba46df7446d1a87244efa985e8e292fShaopeng Jia return true; 25621524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } 25631524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } 2564a48b2d221ba46df7446d1a87244efa985e8e292fShaopeng Jia return false; 25651524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } 25661524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia 25671524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia /** 25681524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * Strips any extension (as in, the part of the number dialled after the call is connected, 25691524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * usually indicated with extn, ext, x or similar) from the end of the number, and returns it. 25701524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * 25711524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * @param number the non-normalized telephone number that we wish to strip the extension from 25721524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * @return the phone extension 25731524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia */ 2574ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia // @VisibleForTesting 2575372bff8dd464574d36737d47e495cad14346653cShaopeng Jia String maybeStripExtension(StringBuilder number) { 25761524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia Matcher m = EXTN_PATTERN.matcher(number); 25771524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia // If we find a potential extension, and the number preceding this is a viable number, we assume 25781524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia // it is an extension. 25791524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia if (m.find() && isViablePhoneNumber(number.substring(0, m.start()))) { 25801524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia // The numbers are captured into groups in the regular expression. 25814b7846722d1a5acb0577b07e98324f744f5e7942Shaopeng Jia for (int i = 1, length = m.groupCount(); i <= length; i++) { 25821524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia if (m.group(i) != null) { 25831524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia // We go through the capturing groups until we find one that captured some digits. If none 25841524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia // did, then we will return the empty string. 25851524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia String extension = m.group(i); 25861524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia number.delete(m.start(), number.length()); 25871524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia return extension; 25881524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } 25891524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } 25901524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } 25911524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia return ""; 25921524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } 25931524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia 25941524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia /** 259574aa862e30b4d1b2722e90b1a8684274441a7541Shaopeng Jia * Checks to see that the region code used is valid, or if it is not valid, that the number to 2596372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * parse starts with a + symbol so that we can attempt to infer the region from the number. 259774aa862e30b4d1b2722e90b1a8684274441a7541Shaopeng Jia * Returns false if it cannot use the region provided and the region cannot be inferred. 259874aa862e30b4d1b2722e90b1a8684274441a7541Shaopeng Jia */ 2599372bff8dd464574d36737d47e495cad14346653cShaopeng Jia private boolean checkRegionForParsing(String numberToParse, String defaultRegion) { 2600372bff8dd464574d36737d47e495cad14346653cShaopeng Jia if (!isValidRegionCode(defaultRegion)) { 2601372bff8dd464574d36737d47e495cad14346653cShaopeng Jia // If the number is null or empty, we can't infer the region. 260274aa862e30b4d1b2722e90b1a8684274441a7541Shaopeng Jia if (numberToParse == null || numberToParse.length() == 0 || 260374aa862e30b4d1b2722e90b1a8684274441a7541Shaopeng Jia !PLUS_CHARS_PATTERN.matcher(numberToParse).lookingAt()) { 260474aa862e30b4d1b2722e90b1a8684274441a7541Shaopeng Jia return false; 260574aa862e30b4d1b2722e90b1a8684274441a7541Shaopeng Jia } 260674aa862e30b4d1b2722e90b1a8684274441a7541Shaopeng Jia } 260774aa862e30b4d1b2722e90b1a8684274441a7541Shaopeng Jia return true; 260874aa862e30b4d1b2722e90b1a8684274441a7541Shaopeng Jia } 260974aa862e30b4d1b2722e90b1a8684274441a7541Shaopeng Jia 261074aa862e30b4d1b2722e90b1a8684274441a7541Shaopeng Jia /** 26111524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * Parses a string and returns it in proto buffer format. This method will throw a 261293f6965c2c041ac707bf1b3bcf5a3f60e452f421Shaopeng Jia * {@link com.android.i18n.phonenumbers.NumberParseException} if the number is not considered to be 2613372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * a possible number. Note that validation of whether the number is actually a valid number for a 2614372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * particular region is not performed. This can be done separately with {@link #isValidNumber}. 26151524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * 26161524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * @param numberToParse number that we are attempting to parse. This can contain formatting 2617bf5d9756fe9b13f5b2e0696c62949cea77396687Shaopeng Jia * such as +, ( and -, as well as a phone number extension. It can also 2618bf5d9756fe9b13f5b2e0696c62949cea77396687Shaopeng Jia * be provided in RFC3966 format. 2619d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia * @param defaultRegion region that we are expecting the number to be from. This is only used 2620d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia * if the number being parsed is not written in international format. 2621372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * The country_code for the number in this case would be stored as that 2622372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * of the default region supplied. If the number is guaranteed to 2623d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia * start with a '+' followed by the country calling code, then 2624d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia * "ZZ" or null can be supplied. 26251524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * @return a phone number proto buffer filled with the parsed number 26261524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * @throws NumberParseException if the string is not considered to be a viable phone number or if 2627372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * no default region was supplied and the number is not in 2628f59ccfca9dd02c4e3cf3e06b5cf184a8d0e67626Shaopeng Jia * international format (does not start with +) 26291524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia */ 2630372bff8dd464574d36737d47e495cad14346653cShaopeng Jia public PhoneNumber parse(String numberToParse, String defaultRegion) 26311524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia throws NumberParseException { 263276f6569af0619d12afd19991d8ff69a9bea4c142Shaopeng Jia PhoneNumber phoneNumber = new PhoneNumber(); 2633372bff8dd464574d36737d47e495cad14346653cShaopeng Jia parse(numberToParse, defaultRegion, phoneNumber); 263476f6569af0619d12afd19991d8ff69a9bea4c142Shaopeng Jia return phoneNumber; 2635be1af2f8b62d5435eca48f3dd5c82e3d2c9bfa17Shaopeng Jia } 2636be1af2f8b62d5435eca48f3dd5c82e3d2c9bfa17Shaopeng Jia 2637d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia /** 2638d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia * Same as {@link #parse(String, String)}, but accepts mutable PhoneNumber as a parameter to 2639d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia * decrease object creation when invoked many times. 2640d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia */ 2641372bff8dd464574d36737d47e495cad14346653cShaopeng Jia public void parse(String numberToParse, String defaultRegion, PhoneNumber phoneNumber) 2642be1af2f8b62d5435eca48f3dd5c82e3d2c9bfa17Shaopeng Jia throws NumberParseException { 2643372bff8dd464574d36737d47e495cad14346653cShaopeng Jia parseHelper(numberToParse, defaultRegion, false, true, phoneNumber); 26447900ea273b8c33b3c6f70d7dd559127938d0fc3dShaopeng Jia } 26457900ea273b8c33b3c6f70d7dd559127938d0fc3dShaopeng Jia 26467900ea273b8c33b3c6f70d7dd559127938d0fc3dShaopeng Jia /** 2647372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * Parses a string and returns it in proto buffer format. This method differs from {@link #parse} 2648372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * in that it always populates the raw_input field of the protocol buffer with numberToParse as 2649372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * well as the country_code_source field. 26507900ea273b8c33b3c6f70d7dd559127938d0fc3dShaopeng Jia * 26517900ea273b8c33b3c6f70d7dd559127938d0fc3dShaopeng Jia * @param numberToParse number that we are attempting to parse. This can contain formatting 26527900ea273b8c33b3c6f70d7dd559127938d0fc3dShaopeng Jia * such as +, ( and -, as well as a phone number extension. 2653d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia * @param defaultRegion region that we are expecting the number to be from. This is only used 2654d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia * if the number being parsed is not written in international format. 2655d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia * The country calling code for the number in this case would be stored 2656d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia * as that of the default region supplied. 26577900ea273b8c33b3c6f70d7dd559127938d0fc3dShaopeng Jia * @return a phone number proto buffer filled with the parsed number 26587900ea273b8c33b3c6f70d7dd559127938d0fc3dShaopeng Jia * @throws NumberParseException if the string is not considered to be a viable phone number or if 2659372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * no default region was supplied 26607900ea273b8c33b3c6f70d7dd559127938d0fc3dShaopeng Jia */ 2661372bff8dd464574d36737d47e495cad14346653cShaopeng Jia public PhoneNumber parseAndKeepRawInput(String numberToParse, String defaultRegion) 26627900ea273b8c33b3c6f70d7dd559127938d0fc3dShaopeng Jia throws NumberParseException { 266376f6569af0619d12afd19991d8ff69a9bea4c142Shaopeng Jia PhoneNumber phoneNumber = new PhoneNumber(); 2664372bff8dd464574d36737d47e495cad14346653cShaopeng Jia parseAndKeepRawInput(numberToParse, defaultRegion, phoneNumber); 266576f6569af0619d12afd19991d8ff69a9bea4c142Shaopeng Jia return phoneNumber; 2666be1af2f8b62d5435eca48f3dd5c82e3d2c9bfa17Shaopeng Jia } 2667be1af2f8b62d5435eca48f3dd5c82e3d2c9bfa17Shaopeng Jia 2668d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia /** 2669d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia * Same as{@link #parseAndKeepRawInput(String, String)}, but accepts a mutable PhoneNumber as 2670d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia * a parameter to decrease object creation when invoked many times. 2671d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia */ 2672372bff8dd464574d36737d47e495cad14346653cShaopeng Jia public void parseAndKeepRawInput(String numberToParse, String defaultRegion, 267376f6569af0619d12afd19991d8ff69a9bea4c142Shaopeng Jia PhoneNumber phoneNumber) 2674be1af2f8b62d5435eca48f3dd5c82e3d2c9bfa17Shaopeng Jia throws NumberParseException { 2675372bff8dd464574d36737d47e495cad14346653cShaopeng Jia parseHelper(numberToParse, defaultRegion, true, true, phoneNumber); 26761524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } 26771524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia 26781524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia /** 267952699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia * Returns an iterable over all {@link PhoneNumberMatch PhoneNumberMatches} in {@code text}. This 268052699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia * is a shortcut for {@link #findNumbers(CharSequence, String, Leniency, long) 2681372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * getMatcher(text, defaultRegion, Leniency.VALID, Long.MAX_VALUE)}. 268252699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia * 268352699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia * @param text the text to search for phone numbers, null for no text 2684d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia * @param defaultRegion region that we are expecting the number to be from. This is only used 2685d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia * if the number being parsed is not written in international format. The 2686d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia * country_code for the number in this case would be stored as that of 2687d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia * the default region supplied. May be null if only international 268852699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia * numbers are expected. 268952699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia */ 2690372bff8dd464574d36737d47e495cad14346653cShaopeng Jia public Iterable<PhoneNumberMatch> findNumbers(CharSequence text, String defaultRegion) { 2691372bff8dd464574d36737d47e495cad14346653cShaopeng Jia return findNumbers(text, defaultRegion, Leniency.VALID, Long.MAX_VALUE); 269252699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia } 269352699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia 269452699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia /** 269552699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia * Returns an iterable over all {@link PhoneNumberMatch PhoneNumberMatches} in {@code text}. 269652699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia * 269752699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia * @param text the text to search for phone numbers, null for no text 2698d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia * @param defaultRegion region that we are expecting the number to be from. This is only used 2699d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia * if the number being parsed is not written in international format. The 2700d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia * country_code for the number in this case would be stored as that of 2701d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia * the default region supplied. May be null if only international 270252699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia * numbers are expected. 270352699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia * @param leniency the leniency to use when evaluating candidate phone numbers 270452699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia * @param maxTries the maximum number of invalid numbers to try before giving up on the 270552699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia * text. This is to cover degenerate cases where the text has a lot of 270652699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia * false positives in it. Must be {@code >= 0}. 270752699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia */ 270852699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia public Iterable<PhoneNumberMatch> findNumbers( 2709372bff8dd464574d36737d47e495cad14346653cShaopeng Jia final CharSequence text, final String defaultRegion, final Leniency leniency, 271052699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia final long maxTries) { 271152699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia 271252699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia return new Iterable<PhoneNumberMatch>() { 271352699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia public Iterator<PhoneNumberMatch> iterator() { 271452699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia return new PhoneNumberMatcher( 2715372bff8dd464574d36737d47e495cad14346653cShaopeng Jia PhoneNumberUtil.this, text, defaultRegion, leniency, maxTries); 271652699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia } 271752699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia }; 271852699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia } 271952699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia 272052699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia /** 2721be1af2f8b62d5435eca48f3dd5c82e3d2c9bfa17Shaopeng Jia * Parses a string and fills up the phoneNumber. This method is the same as the public 2722372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * parse() method, with the exception that it allows the default region to be null, for use by 2723372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * isNumberMatch(). checkRegion should be set to false if it is permitted for the default region 272474aa862e30b4d1b2722e90b1a8684274441a7541Shaopeng Jia * to be null or unknown ("ZZ"). 27251524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia */ 2726372bff8dd464574d36737d47e495cad14346653cShaopeng Jia private void parseHelper(String numberToParse, String defaultRegion, boolean keepRawInput, 272774aa862e30b4d1b2722e90b1a8684274441a7541Shaopeng Jia boolean checkRegion, PhoneNumber phoneNumber) 27281524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia throws NumberParseException { 272974aa862e30b4d1b2722e90b1a8684274441a7541Shaopeng Jia if (numberToParse == null) { 273074aa862e30b4d1b2722e90b1a8684274441a7541Shaopeng Jia throw new NumberParseException(NumberParseException.ErrorType.NOT_A_NUMBER, 273174aa862e30b4d1b2722e90b1a8684274441a7541Shaopeng Jia "The phone number supplied was null."); 2732b0e21c22b1ca6b9aeb1426924cdf42a221c3d416Shaopeng Jia } else if (numberToParse.length() > MAX_INPUT_STRING_LENGTH) { 2733b0e21c22b1ca6b9aeb1426924cdf42a221c3d416Shaopeng Jia throw new NumberParseException(NumberParseException.ErrorType.TOO_LONG, 2734b0e21c22b1ca6b9aeb1426924cdf42a221c3d416Shaopeng Jia "The string supplied was too long to parse."); 273574aa862e30b4d1b2722e90b1a8684274441a7541Shaopeng Jia } 2736b210e301245cb5dc90aa3142f378632bd41cb172Shaopeng Jia 2737b210e301245cb5dc90aa3142f378632bd41cb172Shaopeng Jia StringBuilder nationalNumber = new StringBuilder(); 2738bf5d9756fe9b13f5b2e0696c62949cea77396687Shaopeng Jia buildNationalNumberForParsing(numberToParse, nationalNumber); 2739b210e301245cb5dc90aa3142f378632bd41cb172Shaopeng Jia 2740b210e301245cb5dc90aa3142f378632bd41cb172Shaopeng Jia if (!isViablePhoneNumber(nationalNumber.toString())) { 27411524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia throw new NumberParseException(NumberParseException.ErrorType.NOT_A_NUMBER, 27421524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia "The string supplied did not seem to be a phone number."); 27431524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } 27441524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia 2745372bff8dd464574d36737d47e495cad14346653cShaopeng Jia // Check the region supplied is valid, or that the extracted number starts with some sort of + 274674aa862e30b4d1b2722e90b1a8684274441a7541Shaopeng Jia // sign so the number's region can be determined. 2747b210e301245cb5dc90aa3142f378632bd41cb172Shaopeng Jia if (checkRegion && !checkRegionForParsing(nationalNumber.toString(), defaultRegion)) { 274874aa862e30b4d1b2722e90b1a8684274441a7541Shaopeng Jia throw new NumberParseException(NumberParseException.ErrorType.INVALID_COUNTRY_CODE, 2749372bff8dd464574d36737d47e495cad14346653cShaopeng Jia "Missing or invalid default region."); 275074aa862e30b4d1b2722e90b1a8684274441a7541Shaopeng Jia } 275174aa862e30b4d1b2722e90b1a8684274441a7541Shaopeng Jia 27527900ea273b8c33b3c6f70d7dd559127938d0fc3dShaopeng Jia if (keepRawInput) { 27537900ea273b8c33b3c6f70d7dd559127938d0fc3dShaopeng Jia phoneNumber.setRawInput(numberToParse); 27547900ea273b8c33b3c6f70d7dd559127938d0fc3dShaopeng Jia } 2755372bff8dd464574d36737d47e495cad14346653cShaopeng Jia // Attempt to parse extension first, since it doesn't require region-specific data and we want 27561524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia // to have the non-normalised number here. 27571524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia String extension = maybeStripExtension(nationalNumber); 2758be1af2f8b62d5435eca48f3dd5c82e3d2c9bfa17Shaopeng Jia if (extension.length() > 0) { 27591524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia phoneNumber.setExtension(extension); 27601524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } 27611524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia 2762372bff8dd464574d36737d47e495cad14346653cShaopeng Jia PhoneMetadata regionMetadata = getMetadataForRegion(defaultRegion); 27631524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia // Check to see if the number is given in international format so we know whether this number is 2764372bff8dd464574d36737d47e495cad14346653cShaopeng Jia // from the default region or not. 2765372bff8dd464574d36737d47e495cad14346653cShaopeng Jia StringBuilder normalizedNationalNumber = new StringBuilder(); 2766ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia int countryCode = 0; 2767ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia try { 2768ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia // TODO: This method should really just take in the string buffer that has already 2769ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia // been created, and just remove the prefix, rather than taking in a string and then 2770ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia // outputting a string buffer. 2771ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia countryCode = maybeExtractCountryCode(nationalNumber.toString(), regionMetadata, 2772ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia normalizedNationalNumber, keepRawInput, phoneNumber); 2773ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia } catch (NumberParseException e) { 2774ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia Matcher matcher = PLUS_CHARS_PATTERN.matcher(nationalNumber.toString()); 2775ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia if (e.getErrorType() == NumberParseException.ErrorType.INVALID_COUNTRY_CODE && 2776ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia matcher.lookingAt()) { 2777ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia // Strip the plus-char, and try again. 2778ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia countryCode = maybeExtractCountryCode(nationalNumber.substring(matcher.end()), 2779ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia regionMetadata, normalizedNationalNumber, 2780ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia keepRawInput, phoneNumber); 2781ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia if (countryCode == 0) { 2782ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia throw new NumberParseException(NumberParseException.ErrorType.INVALID_COUNTRY_CODE, 2783ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia "Could not interpret numbers after plus-sign."); 2784ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia } 2785ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia } else { 2786ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia throw new NumberParseException(e.getErrorType(), e.getMessage()); 2787ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia } 2788ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia } 27891524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia if (countryCode != 0) { 27901524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia String phoneNumberRegion = getRegionCodeForCountryCode(countryCode); 2791372bff8dd464574d36737d47e495cad14346653cShaopeng Jia if (!phoneNumberRegion.equals(defaultRegion)) { 2792203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia // Metadata cannot be null because the country calling code is valid. 2793528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia regionMetadata = getMetadataForRegionOrCallingCode(countryCode, phoneNumberRegion); 27945c24149d269da6e7d7b6b2797df096fdea64a019Shaopeng Jia } 27951524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } else { 2796372bff8dd464574d36737d47e495cad14346653cShaopeng Jia // If no extracted country calling code, use the region supplied instead. The national number 2797372bff8dd464574d36737d47e495cad14346653cShaopeng Jia // is just the normalized version of the number we were given to parse. 27981524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia normalize(nationalNumber); 27991524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia normalizedNationalNumber.append(nationalNumber); 2800372bff8dd464574d36737d47e495cad14346653cShaopeng Jia if (defaultRegion != null) { 2801372bff8dd464574d36737d47e495cad14346653cShaopeng Jia countryCode = regionMetadata.getCountryCode(); 28025c24149d269da6e7d7b6b2797df096fdea64a019Shaopeng Jia phoneNumber.setCountryCode(countryCode); 28035c24149d269da6e7d7b6b2797df096fdea64a019Shaopeng Jia } else if (keepRawInput) { 28045c24149d269da6e7d7b6b2797df096fdea64a019Shaopeng Jia phoneNumber.clearCountryCodeSource(); 28051524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } 28061524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } 28071524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia if (normalizedNationalNumber.length() < MIN_LENGTH_FOR_NSN) { 28081524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia throw new NumberParseException(NumberParseException.ErrorType.TOO_SHORT_NSN, 28091524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia "The string supplied is too short to be a phone number."); 28101524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } 2811372bff8dd464574d36737d47e495cad14346653cShaopeng Jia if (regionMetadata != null) { 2812a48b2d221ba46df7446d1a87244efa985e8e292fShaopeng Jia StringBuilder carrierCode = new StringBuilder(); 2813a48b2d221ba46df7446d1a87244efa985e8e292fShaopeng Jia maybeStripNationalPrefixAndCarrierCode(normalizedNationalNumber, regionMetadata, carrierCode); 281452699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia if (keepRawInput) { 2815a48b2d221ba46df7446d1a87244efa985e8e292fShaopeng Jia phoneNumber.setPreferredDomesticCarrierCode(carrierCode.toString()); 281652699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia } 28171524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } 28181524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia int lengthOfNationalNumber = normalizedNationalNumber.length(); 28191524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia if (lengthOfNationalNumber < MIN_LENGTH_FOR_NSN) { 28201524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia throw new NumberParseException(NumberParseException.ErrorType.TOO_SHORT_NSN, 2821be1af2f8b62d5435eca48f3dd5c82e3d2c9bfa17Shaopeng Jia "The string supplied is too short to be a phone number."); 28221524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } 28231524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia if (lengthOfNationalNumber > MAX_LENGTH_FOR_NSN) { 28241524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia throw new NumberParseException(NumberParseException.ErrorType.TOO_LONG, 2825be1af2f8b62d5435eca48f3dd5c82e3d2c9bfa17Shaopeng Jia "The string supplied is too long to be a phone number."); 28261524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } 2827f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia if (normalizedNationalNumber.charAt(0) == '0') { 28285c24149d269da6e7d7b6b2797df096fdea64a019Shaopeng Jia phoneNumber.setItalianLeadingZero(true); 28295c24149d269da6e7d7b6b2797df096fdea64a019Shaopeng Jia } 28301524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia phoneNumber.setNationalNumber(Long.parseLong(normalizedNationalNumber.toString())); 28311524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } 28321524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia 28331524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia /** 2834bf5d9756fe9b13f5b2e0696c62949cea77396687Shaopeng Jia * Converts numberToParse to a form that we can parse and write it to nationalNumber if it is 2835bf5d9756fe9b13f5b2e0696c62949cea77396687Shaopeng Jia * written in RFC3966; otherwise extract a possible number out of it and write to nationalNumber. 2836bf5d9756fe9b13f5b2e0696c62949cea77396687Shaopeng Jia */ 2837bf5d9756fe9b13f5b2e0696c62949cea77396687Shaopeng Jia private void buildNationalNumberForParsing(String numberToParse, StringBuilder nationalNumber) { 2838bf5d9756fe9b13f5b2e0696c62949cea77396687Shaopeng Jia int indexOfPhoneContext = numberToParse.indexOf(RFC3966_PHONE_CONTEXT); 2839bf5d9756fe9b13f5b2e0696c62949cea77396687Shaopeng Jia if (indexOfPhoneContext > 0) { 2840bf5d9756fe9b13f5b2e0696c62949cea77396687Shaopeng Jia int phoneContextStart = indexOfPhoneContext + RFC3966_PHONE_CONTEXT.length(); 2841bf5d9756fe9b13f5b2e0696c62949cea77396687Shaopeng Jia // If the phone context contains a phone number prefix, we need to capture it, whereas domains 2842bf5d9756fe9b13f5b2e0696c62949cea77396687Shaopeng Jia // will be ignored. 2843bf5d9756fe9b13f5b2e0696c62949cea77396687Shaopeng Jia if (numberToParse.charAt(phoneContextStart) == PLUS_SIGN) { 2844bf5d9756fe9b13f5b2e0696c62949cea77396687Shaopeng Jia // Additional parameters might follow the phone context. If so, we will remove them here 2845bf5d9756fe9b13f5b2e0696c62949cea77396687Shaopeng Jia // because the parameters after phone context are not important for parsing the 2846bf5d9756fe9b13f5b2e0696c62949cea77396687Shaopeng Jia // phone number. 2847bf5d9756fe9b13f5b2e0696c62949cea77396687Shaopeng Jia int phoneContextEnd = numberToParse.indexOf(';', phoneContextStart); 2848bf5d9756fe9b13f5b2e0696c62949cea77396687Shaopeng Jia if (phoneContextEnd > 0) { 2849bf5d9756fe9b13f5b2e0696c62949cea77396687Shaopeng Jia nationalNumber.append(numberToParse.substring(phoneContextStart, phoneContextEnd)); 2850bf5d9756fe9b13f5b2e0696c62949cea77396687Shaopeng Jia } else { 2851bf5d9756fe9b13f5b2e0696c62949cea77396687Shaopeng Jia nationalNumber.append(numberToParse.substring(phoneContextStart)); 2852bf5d9756fe9b13f5b2e0696c62949cea77396687Shaopeng Jia } 2853bf5d9756fe9b13f5b2e0696c62949cea77396687Shaopeng Jia } 2854bf5d9756fe9b13f5b2e0696c62949cea77396687Shaopeng Jia 2855bf5d9756fe9b13f5b2e0696c62949cea77396687Shaopeng Jia // Now append everything between the "tel:" prefix and the phone-context. This should include 2856bf5d9756fe9b13f5b2e0696c62949cea77396687Shaopeng Jia // the national number, an optional extension or isdn-subaddress component. 2857bf5d9756fe9b13f5b2e0696c62949cea77396687Shaopeng Jia nationalNumber.append(numberToParse.substring( 2858bf5d9756fe9b13f5b2e0696c62949cea77396687Shaopeng Jia numberToParse.indexOf(RFC3966_PREFIX) + RFC3966_PREFIX.length(), indexOfPhoneContext)); 2859bf5d9756fe9b13f5b2e0696c62949cea77396687Shaopeng Jia } else { 2860bf5d9756fe9b13f5b2e0696c62949cea77396687Shaopeng Jia // Extract a possible number from the string passed in (this strips leading characters that 2861bf5d9756fe9b13f5b2e0696c62949cea77396687Shaopeng Jia // could not be the start of a phone number.) 2862bf5d9756fe9b13f5b2e0696c62949cea77396687Shaopeng Jia nationalNumber.append(extractPossibleNumber(numberToParse)); 2863bf5d9756fe9b13f5b2e0696c62949cea77396687Shaopeng Jia } 2864bf5d9756fe9b13f5b2e0696c62949cea77396687Shaopeng Jia 2865bf5d9756fe9b13f5b2e0696c62949cea77396687Shaopeng Jia // Delete the isdn-subaddress and everything after it if it is present. Note extension won't 2866bf5d9756fe9b13f5b2e0696c62949cea77396687Shaopeng Jia // appear at the same time with isdn-subaddress according to paragraph 5.3 of the RFC3966 spec, 2867bf5d9756fe9b13f5b2e0696c62949cea77396687Shaopeng Jia int indexOfIsdn = nationalNumber.indexOf(RFC3966_ISDN_SUBADDRESS); 2868bf5d9756fe9b13f5b2e0696c62949cea77396687Shaopeng Jia if (indexOfIsdn > 0) { 2869bf5d9756fe9b13f5b2e0696c62949cea77396687Shaopeng Jia nationalNumber.delete(indexOfIsdn, nationalNumber.length()); 2870bf5d9756fe9b13f5b2e0696c62949cea77396687Shaopeng Jia } 2871bf5d9756fe9b13f5b2e0696c62949cea77396687Shaopeng Jia // If both phone context and isdn-subaddress are absent but other parameters are present, the 2872bf5d9756fe9b13f5b2e0696c62949cea77396687Shaopeng Jia // parameters are left in nationalNumber. This is because we are concerned about deleting 2873bf5d9756fe9b13f5b2e0696c62949cea77396687Shaopeng Jia // content from a potential number string when there is no strong evidence that the number is 2874bf5d9756fe9b13f5b2e0696c62949cea77396687Shaopeng Jia // actually written in RFC3966. 2875bf5d9756fe9b13f5b2e0696c62949cea77396687Shaopeng Jia } 2876bf5d9756fe9b13f5b2e0696c62949cea77396687Shaopeng Jia 2877bf5d9756fe9b13f5b2e0696c62949cea77396687Shaopeng Jia /** 28781524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * Takes two phone numbers and compares them for equality. 28791524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * 2880372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * <p>Returns EXACT_MATCH if the country_code, NSN, presence of a leading zero for Italian numbers 28811524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * and any extension present are the same. 2882372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * Returns NSN_MATCH if either or both has no region specified, and the NSNs and extensions are 28831524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * the same. 2884372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * Returns SHORT_NSN_MATCH if either or both has no region specified, or the region specified is 2885372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * the same, and one NSN could be a shorter version of the other number. This includes the case 28861524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * where one has an extension specified, and the other does not. 28871524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * Returns NO_MATCH otherwise. 28881524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * For example, the numbers +1 345 657 1234 and 657 1234 are a SHORT_NSN_MATCH. 28891524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * The numbers +1 345 657 1234 and 345 657 are a NO_MATCH. 28901524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * 28911524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * @param firstNumberIn first number to compare 28921524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * @param secondNumberIn second number to compare 28931524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * 28941524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * @return NO_MATCH, SHORT_NSN_MATCH, NSN_MATCH or EXACT_MATCH depending on the level of equality 28951524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * of the two numbers, described in the method definition. 28961524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia */ 28971524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia public MatchType isNumberMatch(PhoneNumber firstNumberIn, PhoneNumber secondNumberIn) { 28981524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia // Make copies of the phone number so that the numbers passed in are not edited. 289976f6569af0619d12afd19991d8ff69a9bea4c142Shaopeng Jia PhoneNumber firstNumber = new PhoneNumber(); 29001524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia firstNumber.mergeFrom(firstNumberIn); 290176f6569af0619d12afd19991d8ff69a9bea4c142Shaopeng Jia PhoneNumber secondNumber = new PhoneNumber(); 29021524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia secondNumber.mergeFrom(secondNumberIn); 290352699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia // First clear raw_input, country_code_source and preferred_domestic_carrier_code fields and any 290452699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia // empty-string extensions so that we can use the proto-buffer equality method. 29057900ea273b8c33b3c6f70d7dd559127938d0fc3dShaopeng Jia firstNumber.clearRawInput(); 29065c24149d269da6e7d7b6b2797df096fdea64a019Shaopeng Jia firstNumber.clearCountryCodeSource(); 290752699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia firstNumber.clearPreferredDomesticCarrierCode(); 29087900ea273b8c33b3c6f70d7dd559127938d0fc3dShaopeng Jia secondNumber.clearRawInput(); 29095c24149d269da6e7d7b6b2797df096fdea64a019Shaopeng Jia secondNumber.clearCountryCodeSource(); 291052699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia secondNumber.clearPreferredDomesticCarrierCode(); 29111524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia if (firstNumber.hasExtension() && 2912be1af2f8b62d5435eca48f3dd5c82e3d2c9bfa17Shaopeng Jia firstNumber.getExtension().length() == 0) { 29131524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia firstNumber.clearExtension(); 29141524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } 29151524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia if (secondNumber.hasExtension() && 2916be1af2f8b62d5435eca48f3dd5c82e3d2c9bfa17Shaopeng Jia secondNumber.getExtension().length() == 0) { 29171524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia secondNumber.clearExtension(); 29181524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } 29191524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia // Early exit if both had extensions and these are different. 292076f6569af0619d12afd19991d8ff69a9bea4c142Shaopeng Jia if (firstNumber.hasExtension() && secondNumber.hasExtension() && 292176f6569af0619d12afd19991d8ff69a9bea4c142Shaopeng Jia !firstNumber.getExtension().equals(secondNumber.getExtension())) { 29221524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia return MatchType.NO_MATCH; 29231524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } 292476f6569af0619d12afd19991d8ff69a9bea4c142Shaopeng Jia int firstNumberCountryCode = firstNumber.getCountryCode(); 292576f6569af0619d12afd19991d8ff69a9bea4c142Shaopeng Jia int secondNumberCountryCode = secondNumber.getCountryCode(); 2926372bff8dd464574d36737d47e495cad14346653cShaopeng Jia // Both had country_code specified. 29271524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia if (firstNumberCountryCode != 0 && secondNumberCountryCode != 0) { 292876f6569af0619d12afd19991d8ff69a9bea4c142Shaopeng Jia if (firstNumber.exactlySameAs(secondNumber)) { 29291524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia return MatchType.EXACT_MATCH; 29307900ea273b8c33b3c6f70d7dd559127938d0fc3dShaopeng Jia } else if (firstNumberCountryCode == secondNumberCountryCode && 293176f6569af0619d12afd19991d8ff69a9bea4c142Shaopeng Jia isNationalNumberSuffixOfTheOther(firstNumber, secondNumber)) { 29321524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia // A SHORT_NSN_MATCH occurs if there is a difference because of the presence or absence of 29331524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia // an 'Italian leading zero', the presence or absence of an extension, or one NSN being a 29341524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia // shorter variant of the other. 29357900ea273b8c33b3c6f70d7dd559127938d0fc3dShaopeng Jia return MatchType.SHORT_NSN_MATCH; 29361524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } 29371524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia // This is not a match. 29381524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia return MatchType.NO_MATCH; 29391524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } 2940372bff8dd464574d36737d47e495cad14346653cShaopeng Jia // Checks cases where one or both country_code fields were not specified. To make equality 2941372bff8dd464574d36737d47e495cad14346653cShaopeng Jia // checks easier, we first set the country_code fields to be equal. 294276f6569af0619d12afd19991d8ff69a9bea4c142Shaopeng Jia firstNumber.setCountryCode(secondNumberCountryCode); 29431524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia // If all else was the same, then this is an NSN_MATCH. 294476f6569af0619d12afd19991d8ff69a9bea4c142Shaopeng Jia if (firstNumber.exactlySameAs(secondNumber)) { 29451524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia return MatchType.NSN_MATCH; 29461524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } 294776f6569af0619d12afd19991d8ff69a9bea4c142Shaopeng Jia if (isNationalNumberSuffixOfTheOther(firstNumber, secondNumber)) { 29481524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia return MatchType.SHORT_NSN_MATCH; 29491524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } 2950be1af2f8b62d5435eca48f3dd5c82e3d2c9bfa17Shaopeng Jia return MatchType.NO_MATCH; 29511524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } 29521524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia 29537900ea273b8c33b3c6f70d7dd559127938d0fc3dShaopeng Jia // Returns true when one national number is the suffix of the other or both are the same. 29547900ea273b8c33b3c6f70d7dd559127938d0fc3dShaopeng Jia private boolean isNationalNumberSuffixOfTheOther(PhoneNumber firstNumber, 29557900ea273b8c33b3c6f70d7dd559127938d0fc3dShaopeng Jia PhoneNumber secondNumber) { 29567900ea273b8c33b3c6f70d7dd559127938d0fc3dShaopeng Jia String firstNumberNationalNumber = String.valueOf(firstNumber.getNationalNumber()); 29577900ea273b8c33b3c6f70d7dd559127938d0fc3dShaopeng Jia String secondNumberNationalNumber = String.valueOf(secondNumber.getNationalNumber()); 29587900ea273b8c33b3c6f70d7dd559127938d0fc3dShaopeng Jia // Note that endsWith returns true if the numbers are equal. 29597900ea273b8c33b3c6f70d7dd559127938d0fc3dShaopeng Jia return firstNumberNationalNumber.endsWith(secondNumberNationalNumber) || 29607900ea273b8c33b3c6f70d7dd559127938d0fc3dShaopeng Jia secondNumberNationalNumber.endsWith(firstNumberNationalNumber); 29617900ea273b8c33b3c6f70d7dd559127938d0fc3dShaopeng Jia } 29627900ea273b8c33b3c6f70d7dd559127938d0fc3dShaopeng Jia 29631524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia /** 29641524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * Takes two phone numbers as strings and compares them for equality. This is a convenience 296596a7214cdabf08f53f5b1a560304601c9f65e0b9Shaopeng Jia * wrapper for {@link #isNumberMatch(PhoneNumber, PhoneNumber)}. No default region is known. 29661524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * 2967372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * @param firstNumber first number to compare. Can contain formatting, and can have country 2968372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * calling code specified with + at the start. 29691524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * @param secondNumber second number to compare. Can contain formatting, and can have country 2970372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * calling code specified with + at the start. 297174aa862e30b4d1b2722e90b1a8684274441a7541Shaopeng Jia * @return NOT_A_NUMBER, NO_MATCH, SHORT_NSN_MATCH, NSN_MATCH, EXACT_MATCH. See 297296a7214cdabf08f53f5b1a560304601c9f65e0b9Shaopeng Jia * {@link #isNumberMatch(PhoneNumber, PhoneNumber)} for more details. 29731524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia */ 297474aa862e30b4d1b2722e90b1a8684274441a7541Shaopeng Jia public MatchType isNumberMatch(String firstNumber, String secondNumber) { 297574aa862e30b4d1b2722e90b1a8684274441a7541Shaopeng Jia try { 297674aa862e30b4d1b2722e90b1a8684274441a7541Shaopeng Jia PhoneNumber firstNumberAsProto = parse(firstNumber, UNKNOWN_REGION); 297774aa862e30b4d1b2722e90b1a8684274441a7541Shaopeng Jia return isNumberMatch(firstNumberAsProto, secondNumber); 297874aa862e30b4d1b2722e90b1a8684274441a7541Shaopeng Jia } catch (NumberParseException e) { 297974aa862e30b4d1b2722e90b1a8684274441a7541Shaopeng Jia if (e.getErrorType() == NumberParseException.ErrorType.INVALID_COUNTRY_CODE) { 298074aa862e30b4d1b2722e90b1a8684274441a7541Shaopeng Jia try { 298174aa862e30b4d1b2722e90b1a8684274441a7541Shaopeng Jia PhoneNumber secondNumberAsProto = parse(secondNumber, UNKNOWN_REGION); 298274aa862e30b4d1b2722e90b1a8684274441a7541Shaopeng Jia return isNumberMatch(secondNumberAsProto, firstNumber); 298374aa862e30b4d1b2722e90b1a8684274441a7541Shaopeng Jia } catch (NumberParseException e2) { 298474aa862e30b4d1b2722e90b1a8684274441a7541Shaopeng Jia if (e2.getErrorType() == NumberParseException.ErrorType.INVALID_COUNTRY_CODE) { 298574aa862e30b4d1b2722e90b1a8684274441a7541Shaopeng Jia try { 298674aa862e30b4d1b2722e90b1a8684274441a7541Shaopeng Jia PhoneNumber firstNumberProto = new PhoneNumber(); 298774aa862e30b4d1b2722e90b1a8684274441a7541Shaopeng Jia PhoneNumber secondNumberProto = new PhoneNumber(); 298874aa862e30b4d1b2722e90b1a8684274441a7541Shaopeng Jia parseHelper(firstNumber, null, false, false, firstNumberProto); 298974aa862e30b4d1b2722e90b1a8684274441a7541Shaopeng Jia parseHelper(secondNumber, null, false, false, secondNumberProto); 299074aa862e30b4d1b2722e90b1a8684274441a7541Shaopeng Jia return isNumberMatch(firstNumberProto, secondNumberProto); 299174aa862e30b4d1b2722e90b1a8684274441a7541Shaopeng Jia } catch (NumberParseException e3) { 299274aa862e30b4d1b2722e90b1a8684274441a7541Shaopeng Jia // Fall through and return MatchType.NOT_A_NUMBER. 299374aa862e30b4d1b2722e90b1a8684274441a7541Shaopeng Jia } 299474aa862e30b4d1b2722e90b1a8684274441a7541Shaopeng Jia } 299574aa862e30b4d1b2722e90b1a8684274441a7541Shaopeng Jia } 299674aa862e30b4d1b2722e90b1a8684274441a7541Shaopeng Jia } 299774aa862e30b4d1b2722e90b1a8684274441a7541Shaopeng Jia } 299874aa862e30b4d1b2722e90b1a8684274441a7541Shaopeng Jia // One or more of the phone numbers we are trying to match is not a viable phone number. 299974aa862e30b4d1b2722e90b1a8684274441a7541Shaopeng Jia return MatchType.NOT_A_NUMBER; 30001524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } 30011524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia 30021524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia /** 30031524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * Takes two phone numbers and compares them for equality. This is a convenience wrapper for 300496a7214cdabf08f53f5b1a560304601c9f65e0b9Shaopeng Jia * {@link #isNumberMatch(PhoneNumber, PhoneNumber)}. No default region is known. 30051524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * 30061524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * @param firstNumber first number to compare in proto buffer format. 30071524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * @param secondNumber second number to compare. Can contain formatting, and can have country 3008372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * calling code specified with + at the start. 300974aa862e30b4d1b2722e90b1a8684274441a7541Shaopeng Jia * @return NOT_A_NUMBER, NO_MATCH, SHORT_NSN_MATCH, NSN_MATCH, EXACT_MATCH. See 301096a7214cdabf08f53f5b1a560304601c9f65e0b9Shaopeng Jia * {@link #isNumberMatch(PhoneNumber, PhoneNumber)} for more details. 30111524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia */ 301274aa862e30b4d1b2722e90b1a8684274441a7541Shaopeng Jia public MatchType isNumberMatch(PhoneNumber firstNumber, String secondNumber) { 3013372bff8dd464574d36737d47e495cad14346653cShaopeng Jia // First see if the second number has an implicit country calling code, by attempting to parse 3014372bff8dd464574d36737d47e495cad14346653cShaopeng Jia // it. 301574aa862e30b4d1b2722e90b1a8684274441a7541Shaopeng Jia try { 301674aa862e30b4d1b2722e90b1a8684274441a7541Shaopeng Jia PhoneNumber secondNumberAsProto = parse(secondNumber, UNKNOWN_REGION); 301774aa862e30b4d1b2722e90b1a8684274441a7541Shaopeng Jia return isNumberMatch(firstNumber, secondNumberAsProto); 301874aa862e30b4d1b2722e90b1a8684274441a7541Shaopeng Jia } catch (NumberParseException e) { 301974aa862e30b4d1b2722e90b1a8684274441a7541Shaopeng Jia if (e.getErrorType() == NumberParseException.ErrorType.INVALID_COUNTRY_CODE) { 3020372bff8dd464574d36737d47e495cad14346653cShaopeng Jia // The second number has no country calling code. EXACT_MATCH is no longer possible. 302174aa862e30b4d1b2722e90b1a8684274441a7541Shaopeng Jia // We parse it as if the region was the same as that for the first number, and if 302274aa862e30b4d1b2722e90b1a8684274441a7541Shaopeng Jia // EXACT_MATCH is returned, we replace this with NSN_MATCH. 302374aa862e30b4d1b2722e90b1a8684274441a7541Shaopeng Jia String firstNumberRegion = getRegionCodeForCountryCode(firstNumber.getCountryCode()); 302474aa862e30b4d1b2722e90b1a8684274441a7541Shaopeng Jia try { 302574aa862e30b4d1b2722e90b1a8684274441a7541Shaopeng Jia if (!firstNumberRegion.equals(UNKNOWN_REGION)) { 302674aa862e30b4d1b2722e90b1a8684274441a7541Shaopeng Jia PhoneNumber secondNumberWithFirstNumberRegion = parse(secondNumber, firstNumberRegion); 302774aa862e30b4d1b2722e90b1a8684274441a7541Shaopeng Jia MatchType match = isNumberMatch(firstNumber, secondNumberWithFirstNumberRegion); 302874aa862e30b4d1b2722e90b1a8684274441a7541Shaopeng Jia if (match == MatchType.EXACT_MATCH) { 302974aa862e30b4d1b2722e90b1a8684274441a7541Shaopeng Jia return MatchType.NSN_MATCH; 303074aa862e30b4d1b2722e90b1a8684274441a7541Shaopeng Jia } 303174aa862e30b4d1b2722e90b1a8684274441a7541Shaopeng Jia return match; 303274aa862e30b4d1b2722e90b1a8684274441a7541Shaopeng Jia } else { 3033372bff8dd464574d36737d47e495cad14346653cShaopeng Jia // If the first number didn't have a valid country calling code, then we parse the 3034372bff8dd464574d36737d47e495cad14346653cShaopeng Jia // second number without one as well. 303574aa862e30b4d1b2722e90b1a8684274441a7541Shaopeng Jia PhoneNumber secondNumberProto = new PhoneNumber(); 303674aa862e30b4d1b2722e90b1a8684274441a7541Shaopeng Jia parseHelper(secondNumber, null, false, false, secondNumberProto); 303774aa862e30b4d1b2722e90b1a8684274441a7541Shaopeng Jia return isNumberMatch(firstNumber, secondNumberProto); 303874aa862e30b4d1b2722e90b1a8684274441a7541Shaopeng Jia } 303974aa862e30b4d1b2722e90b1a8684274441a7541Shaopeng Jia } catch (NumberParseException e2) { 304074aa862e30b4d1b2722e90b1a8684274441a7541Shaopeng Jia // Fall-through to return NOT_A_NUMBER. 304174aa862e30b4d1b2722e90b1a8684274441a7541Shaopeng Jia } 304274aa862e30b4d1b2722e90b1a8684274441a7541Shaopeng Jia } 304374aa862e30b4d1b2722e90b1a8684274441a7541Shaopeng Jia } 304474aa862e30b4d1b2722e90b1a8684274441a7541Shaopeng Jia // One or more of the phone numbers we are trying to match is not a viable phone number. 304574aa862e30b4d1b2722e90b1a8684274441a7541Shaopeng Jia return MatchType.NOT_A_NUMBER; 304674aa862e30b4d1b2722e90b1a8684274441a7541Shaopeng Jia } 304774aa862e30b4d1b2722e90b1a8684274441a7541Shaopeng Jia 304874aa862e30b4d1b2722e90b1a8684274441a7541Shaopeng Jia /** 3049528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia * Returns true if the number can be dialled from outside the region, or unknown. If the number 3050528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia * can only be dialled from within the region, returns false. Does not check the number is a valid 3051528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia * number. 3052528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia * TODO: Make this method public when we have enough metadata to make it worthwhile. 305374aa862e30b4d1b2722e90b1a8684274441a7541Shaopeng Jia * 3054528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia * @param number the phone-number for which we want to know whether it is diallable from 3055528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia * outside the region 305674aa862e30b4d1b2722e90b1a8684274441a7541Shaopeng Jia */ 3057528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia // @VisibleForTesting 305874aa862e30b4d1b2722e90b1a8684274441a7541Shaopeng Jia boolean canBeInternationallyDialled(PhoneNumber number) { 3059203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia PhoneMetadata metadata = getMetadataForRegion(getRegionCodeForNumber(number)); 3060203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia if (metadata == null) { 3061528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia // Note numbers belonging to non-geographical entities (e.g. +800 numbers) are always 3062528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia // internationally diallable, and will be caught here. 306374aa862e30b4d1b2722e90b1a8684274441a7541Shaopeng Jia return true; 306474aa862e30b4d1b2722e90b1a8684274441a7541Shaopeng Jia } 3065528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia String nationalSignificantNumber = getNationalSignificantNumber(number); 306674aa862e30b4d1b2722e90b1a8684274441a7541Shaopeng Jia return !isNumberMatchingDesc(nationalSignificantNumber, metadata.getNoInternationalDialling()); 30671524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } 30681524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia} 3069