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 17a77faddfc3b3e4cca8f585c82d669054aec221f4Narayan Kamathpackage com.google.i18n.phonenumbers; 181524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia 1993399cc7a32833de9cb538ef7940eed61a23edcaNeil Fullerimport com.google.i18n.phonenumbers.Phonemetadata.NumberFormat; 2093399cc7a32833de9cb538ef7940eed61a23edcaNeil Fullerimport com.google.i18n.phonenumbers.Phonemetadata.PhoneMetadata; 211524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia 221524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jiaimport java.util.ArrayList; 23df19cbfb8a1e8720bae76bb763ab29622e057c42Shaopeng Jiaimport java.util.Iterator; 241524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jiaimport java.util.List; 251524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jiaimport java.util.regex.Matcher; 261524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jiaimport java.util.regex.Pattern; 271524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia 281524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia/** 291524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * A formatter which formats phone numbers as they are entered. 301524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * 31372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * <p>An AsYouTypeFormatter can be created by invoking 32372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * {@link PhoneNumberUtil#getAsYouTypeFormatter}. After that, digits can be added by invoking 33372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * {@link #inputDigit} on the formatter instance, and the partially formatted phone number will be 34372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * returned each time a digit is added. {@link #clear} can be invoked before formatting a new 35372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * number. 361524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * 37372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * <p>See the unittests for more details on how the formatter is to be used. 381524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * 391524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * @author Shaopeng Jia 401524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia */ 411524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jiapublic class AsYouTypeFormatter { 42df19cbfb8a1e8720bae76bb763ab29622e057c42Shaopeng Jia private String currentOutput = ""; 43372bff8dd464574d36737d47e495cad14346653cShaopeng Jia private StringBuilder formattingTemplate = new StringBuilder(); 44df19cbfb8a1e8720bae76bb763ab29622e057c42Shaopeng Jia // The pattern from numberFormat that is currently used to create formattingTemplate. 45df19cbfb8a1e8720bae76bb763ab29622e057c42Shaopeng Jia private String currentFormattingPattern = ""; 46372bff8dd464574d36737d47e495cad14346653cShaopeng Jia private StringBuilder accruedInput = new StringBuilder(); 47372bff8dd464574d36737d47e495cad14346653cShaopeng Jia private StringBuilder accruedInputWithoutFormatting = new StringBuilder(); 48ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia // This indicates whether AsYouTypeFormatter is currently doing the formatting. 497900ea273b8c33b3c6f70d7dd559127938d0fc3dShaopeng Jia private boolean ableToFormat = true; 50ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia // Set to true when users enter their own formatting. AsYouTypeFormatter will do no formatting at 51ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia // all when this is set to true. 52ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia private boolean inputHasFormatting = false; 53203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia // This is set to true when we know the user is entering a full national significant number, since 54203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia // we have either detected a national prefix or an international dialing prefix. When this is 55203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia // true, we will no longer use local number formatting patterns. 56203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia private boolean isCompleteNumber = false; 57372bff8dd464574d36737d47e495cad14346653cShaopeng Jia private boolean isExpectingCountryCallingCode = false; 581524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia private final PhoneNumberUtil phoneUtil = PhoneNumberUtil.getInstance(); 591524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia private String defaultCountry; 60372bff8dd464574d36737d47e495cad14346653cShaopeng Jia 61203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia // Character used when appropriate to separate a prefix, such as a long NDD or a country calling 62203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia // code, from the national number. 63203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia private static final char SEPARATOR_BEFORE_NATIONAL_NUMBER = ' '; 6493399cc7a32833de9cb538ef7940eed61a23edcaNeil Fuller private static final PhoneMetadata EMPTY_METADATA = 6593399cc7a32833de9cb538ef7940eed61a23edcaNeil Fuller new PhoneMetadata().setInternationalPrefix("NA"); 66bb78ce92eae2d5de9aa06b27ed3b87bc496c79eeShaopeng Jia private PhoneMetadata defaultMetadata; 67bb78ce92eae2d5de9aa06b27ed3b87bc496c79eeShaopeng Jia private PhoneMetadata currentMetadata; 681524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia 694b7846722d1a5acb0577b07e98324f744f5e7942Shaopeng Jia // A pattern that is used to match character classes in regular expressions. An example of a 704b7846722d1a5acb0577b07e98324f744f5e7942Shaopeng Jia // character class is [1-4]. 7152699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia private static final Pattern CHARACTER_CLASS_PATTERN = Pattern.compile("\\[([^\\[\\]])*\\]"); 724b7846722d1a5acb0577b07e98324f744f5e7942Shaopeng Jia // Any digit in a regular expression that actually denotes a digit. For example, in the regular 734b7846722d1a5acb0577b07e98324f744f5e7942Shaopeng Jia // expression 80[0-2]\d{6,10}, the first 2 digits (8 and 0) are standalone digits, but the rest 744b7846722d1a5acb0577b07e98324f744f5e7942Shaopeng Jia // are not. 754b7846722d1a5acb0577b07e98324f744f5e7942Shaopeng Jia // Two look-aheads are needed because the number following \\d could be a two-digit number, since 764b7846722d1a5acb0577b07e98324f744f5e7942Shaopeng Jia // the phone number can be as long as 15 digits. 774b7846722d1a5acb0577b07e98324f744f5e7942Shaopeng Jia private static final Pattern STANDALONE_DIGIT_PATTERN = Pattern.compile("\\d(?=[^,}][^,}])"); 784b7846722d1a5acb0577b07e98324f744f5e7942Shaopeng Jia 79372bff8dd464574d36737d47e495cad14346653cShaopeng Jia // A pattern that is used to determine if a numberFormat under availableFormats is eligible to be 80372bff8dd464574d36737d47e495cad14346653cShaopeng Jia // used by the AYTF. It is eligible when the format element under numberFormat contains groups of 81372bff8dd464574d36737d47e495cad14346653cShaopeng Jia // the dollar sign followed by a single digit, separated by valid phone number punctuation. This 82372bff8dd464574d36737d47e495cad14346653cShaopeng Jia // prevents invalid punctuation (such as the star sign in Israeli star numbers) getting into the 83372bff8dd464574d36737d47e495cad14346653cShaopeng Jia // output of the AYTF. 84372bff8dd464574d36737d47e495cad14346653cShaopeng Jia private static final Pattern ELIGIBLE_FORMAT_PATTERN = 85372bff8dd464574d36737d47e495cad14346653cShaopeng Jia Pattern.compile("[" + PhoneNumberUtil.VALID_PUNCTUATION + "]*" + 86372bff8dd464574d36737d47e495cad14346653cShaopeng Jia "(\\$\\d" + "[" + PhoneNumberUtil.VALID_PUNCTUATION + "]*)+"); 87203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia // A set of characters that, if found in a national prefix formatting rules, are an indicator to 88203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia // us that we should separate the national prefix from the number when formatting. 89203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia private static final Pattern NATIONAL_PREFIX_SEPARATORS_PATTERN = Pattern.compile("[- ]"); 90372bff8dd464574d36737d47e495cad14346653cShaopeng Jia 91df19cbfb8a1e8720bae76bb763ab29622e057c42Shaopeng Jia // This is the minimum length of national number accrued that is required to trigger the 92df19cbfb8a1e8720bae76bb763ab29622e057c42Shaopeng Jia // formatter. The first element of the leadingDigitsPattern of each numberFormat contains a 93df19cbfb8a1e8720bae76bb763ab29622e057c42Shaopeng Jia // regular expression that matches up to this number of digits. 94df19cbfb8a1e8720bae76bb763ab29622e057c42Shaopeng Jia private static final int MIN_LEADING_DIGITS_LENGTH = 3; 95df19cbfb8a1e8720bae76bb763ab29622e057c42Shaopeng Jia 961524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia // The digits that have not been entered yet will be represented by a \u2008, the punctuation 971524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia // space. 98203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia private static final String DIGIT_PLACEHOLDER = "\u2008"; 99203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia private static final Pattern DIGIT_PATTERN = Pattern.compile(DIGIT_PLACEHOLDER); 1001524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia private int lastMatchPosition = 0; 1014b7846722d1a5acb0577b07e98324f744f5e7942Shaopeng Jia // The position of a digit upon which inputDigitAndRememberPosition is most recently invoked, as 1024b7846722d1a5acb0577b07e98324f744f5e7942Shaopeng Jia // found in the original sequence of characters the user entered. 1030b3c1fb05c01bc853ad927356eee743b62a8121bShaopeng Jia private int originalPosition = 0; 104df19cbfb8a1e8720bae76bb763ab29622e057c42Shaopeng Jia // The position of a digit upon which inputDigitAndRememberPosition is most recently invoked, as 105df19cbfb8a1e8720bae76bb763ab29622e057c42Shaopeng Jia // found in accruedInputWithoutFormatting. 106df19cbfb8a1e8720bae76bb763ab29622e057c42Shaopeng Jia private int positionToRemember = 0; 107ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia // This contains anything that has been entered so far preceding the national significant number, 108ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia // and it is formatted (e.g. with space inserted). For example, this can contain IDD, country 109ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia // code, and/or NDD, etc. 110372bff8dd464574d36737d47e495cad14346653cShaopeng Jia private StringBuilder prefixBeforeNationalNumber = new StringBuilder(); 111203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia private boolean shouldAddSpaceAfterNationalPrefix = false; 112ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia // This contains the national prefix that has been extracted. It contains only digits without 113ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia // formatting. 114b03a14984ad9b0d8b88337ca714cb831233b99c3Shaopeng Jia private String extractedNationalPrefix = ""; 115372bff8dd464574d36737d47e495cad14346653cShaopeng Jia private StringBuilder nationalNumber = new StringBuilder(); 116df19cbfb8a1e8720bae76bb763ab29622e057c42Shaopeng Jia private List<NumberFormat> possibleFormats = new ArrayList<NumberFormat>(); 117df19cbfb8a1e8720bae76bb763ab29622e057c42Shaopeng Jia 11893399cc7a32833de9cb538ef7940eed61a23edcaNeil Fuller // A cache for frequently used country-specific regular expressions. 119df19cbfb8a1e8720bae76bb763ab29622e057c42Shaopeng Jia private RegexCache regexCache = new RegexCache(64); 1201524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia 1211524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia /** 12252699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia * Constructs an as-you-type formatter. Should be obtained from {@link 12352699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia * PhoneNumberUtil#getAsYouTypeFormatter}. 1241524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * 1251524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * @param regionCode the country/region where the phone number is being entered 1261524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia */ 1271524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia AsYouTypeFormatter(String regionCode) { 1281524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia defaultCountry = regionCode; 129bb78ce92eae2d5de9aa06b27ed3b87bc496c79eeShaopeng Jia currentMetadata = getMetadataForRegion(defaultCountry); 130bb78ce92eae2d5de9aa06b27ed3b87bc496c79eeShaopeng Jia defaultMetadata = currentMetadata; 1311524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } 1321524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia 133249f28fc9d984e6a7d5ff05ca78d8e7ce280eb54Shaopeng Jia // The metadata needed by this class is the same for all regions sharing the same country calling 134249f28fc9d984e6a7d5ff05ca78d8e7ce280eb54Shaopeng Jia // code. Therefore, we return the metadata for "main" region for this country calling code. 135372bff8dd464574d36737d47e495cad14346653cShaopeng Jia private PhoneMetadata getMetadataForRegion(String regionCode) { 136249f28fc9d984e6a7d5ff05ca78d8e7ce280eb54Shaopeng Jia int countryCallingCode = phoneUtil.getCountryCodeForRegion(regionCode); 137249f28fc9d984e6a7d5ff05ca78d8e7ce280eb54Shaopeng Jia String mainCountry = phoneUtil.getRegionCodeForCountryCode(countryCallingCode); 138249f28fc9d984e6a7d5ff05ca78d8e7ce280eb54Shaopeng Jia PhoneMetadata metadata = phoneUtil.getMetadataForRegion(mainCountry); 139372bff8dd464574d36737d47e495cad14346653cShaopeng Jia if (metadata != null) { 140372bff8dd464574d36737d47e495cad14346653cShaopeng Jia return metadata; 14152699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia } 142372bff8dd464574d36737d47e495cad14346653cShaopeng Jia // Set to a default instance of the metadata. This allows us to function with an incorrect 143372bff8dd464574d36737d47e495cad14346653cShaopeng Jia // region code, even if formatting only works for numbers specified with "+". 144372bff8dd464574d36737d47e495cad14346653cShaopeng Jia return EMPTY_METADATA; 1451524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } 1461524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia 147df19cbfb8a1e8720bae76bb763ab29622e057c42Shaopeng Jia // Returns true if a new template is created as opposed to reusing the existing template. 148df19cbfb8a1e8720bae76bb763ab29622e057c42Shaopeng Jia private boolean maybeCreateNewTemplate() { 149df19cbfb8a1e8720bae76bb763ab29622e057c42Shaopeng Jia // When there are multiple available formats, the formatter uses the first format where a 150df19cbfb8a1e8720bae76bb763ab29622e057c42Shaopeng Jia // formatting template could be created. 151d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia Iterator<NumberFormat> it = possibleFormats.iterator(); 152d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia while (it.hasNext()) { 153d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia NumberFormat numberFormat = it.next(); 15493399cc7a32833de9cb538ef7940eed61a23edcaNeil Fuller String pattern = numberFormat.getPattern(); 155df19cbfb8a1e8720bae76bb763ab29622e057c42Shaopeng Jia if (currentFormattingPattern.equals(pattern)) { 156df19cbfb8a1e8720bae76bb763ab29622e057c42Shaopeng Jia return false; 157df19cbfb8a1e8720bae76bb763ab29622e057c42Shaopeng Jia } 158df19cbfb8a1e8720bae76bb763ab29622e057c42Shaopeng Jia if (createFormattingTemplate(numberFormat)) { 159df19cbfb8a1e8720bae76bb763ab29622e057c42Shaopeng Jia currentFormattingPattern = pattern; 160203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia shouldAddSpaceAfterNationalPrefix = 161203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia NATIONAL_PREFIX_SEPARATORS_PATTERN.matcher( 16293399cc7a32833de9cb538ef7940eed61a23edcaNeil Fuller numberFormat.getNationalPrefixFormattingRule()).find(); 163ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia // With a new formatting template, the matched position using the old template needs to be 164ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia // reset. 165ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia lastMatchPosition = 0; 166df19cbfb8a1e8720bae76bb763ab29622e057c42Shaopeng Jia return true; 167d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia } else { // Remove the current number format from possibleFormats. 168d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia it.remove(); 1691524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } 1701524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } 171df19cbfb8a1e8720bae76bb763ab29622e057c42Shaopeng Jia ableToFormat = false; 172df19cbfb8a1e8720bae76bb763ab29622e057c42Shaopeng Jia return false; 1731524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } 1741524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia 1759ecee8b74bf330f20a902e4b974eddb7abedd627Shaopeng Jia private void getAvailableFormats(String leadingDigits) { 17693399cc7a32833de9cb538ef7940eed61a23edcaNeil Fuller List<NumberFormat> formatList = 17793399cc7a32833de9cb538ef7940eed61a23edcaNeil Fuller (isCompleteNumber && currentMetadata.intlNumberFormatSize() > 0) 17893399cc7a32833de9cb538ef7940eed61a23edcaNeil Fuller ? currentMetadata.intlNumberFormats() 17993399cc7a32833de9cb538ef7940eed61a23edcaNeil Fuller : currentMetadata.numberFormats(); 18093399cc7a32833de9cb538ef7940eed61a23edcaNeil Fuller boolean nationalPrefixIsUsedByCountry = currentMetadata.hasNationalPrefix(); 18193399cc7a32833de9cb538ef7940eed61a23edcaNeil Fuller for (NumberFormat format : formatList) { 182203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia if (!nationalPrefixIsUsedByCountry || isCompleteNumber || 18393399cc7a32833de9cb538ef7940eed61a23edcaNeil Fuller format.isNationalPrefixOptionalWhenFormatting() || 1847a81979b0076f18b31b47b7df2beac29735f3a37Cecilia Roes PhoneNumberUtil.formattingRuleHasFirstGroupOnly( 18593399cc7a32833de9cb538ef7940eed61a23edcaNeil Fuller format.getNationalPrefixFormattingRule())) { 18693399cc7a32833de9cb538ef7940eed61a23edcaNeil Fuller if (isFormatEligible(format.getFormat())) { 187203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia possibleFormats.add(format); 188203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia } 189372bff8dd464574d36737d47e495cad14346653cShaopeng Jia } 190372bff8dd464574d36737d47e495cad14346653cShaopeng Jia } 1919ecee8b74bf330f20a902e4b974eddb7abedd627Shaopeng Jia narrowDownPossibleFormats(leadingDigits); 192df19cbfb8a1e8720bae76bb763ab29622e057c42Shaopeng Jia } 193df19cbfb8a1e8720bae76bb763ab29622e057c42Shaopeng Jia 194372bff8dd464574d36737d47e495cad14346653cShaopeng Jia private boolean isFormatEligible(String format) { 195372bff8dd464574d36737d47e495cad14346653cShaopeng Jia return ELIGIBLE_FORMAT_PATTERN.matcher(format).matches(); 196372bff8dd464574d36737d47e495cad14346653cShaopeng Jia } 197372bff8dd464574d36737d47e495cad14346653cShaopeng Jia 198df19cbfb8a1e8720bae76bb763ab29622e057c42Shaopeng Jia private void narrowDownPossibleFormats(String leadingDigits) { 199372bff8dd464574d36737d47e495cad14346653cShaopeng Jia int indexOfLeadingDigitsPattern = leadingDigits.length() - MIN_LEADING_DIGITS_LENGTH; 200df19cbfb8a1e8720bae76bb763ab29622e057c42Shaopeng Jia Iterator<NumberFormat> it = possibleFormats.iterator(); 201df19cbfb8a1e8720bae76bb763ab29622e057c42Shaopeng Jia while (it.hasNext()) { 202df19cbfb8a1e8720bae76bb763ab29622e057c42Shaopeng Jia NumberFormat format = it.next(); 20393399cc7a32833de9cb538ef7940eed61a23edcaNeil Fuller if (format.leadingDigitsPatternSize() == 0) { 2049ecee8b74bf330f20a902e4b974eddb7abedd627Shaopeng Jia // Keep everything that isn't restricted by leading digits. 2059ecee8b74bf330f20a902e4b974eddb7abedd627Shaopeng Jia continue; 2069ecee8b74bf330f20a902e4b974eddb7abedd627Shaopeng Jia } 2079ecee8b74bf330f20a902e4b974eddb7abedd627Shaopeng Jia int lastLeadingDigitsPattern = 20893399cc7a32833de9cb538ef7940eed61a23edcaNeil Fuller Math.min(indexOfLeadingDigitsPattern, format.leadingDigitsPatternSize() - 1); 2099ecee8b74bf330f20a902e4b974eddb7abedd627Shaopeng Jia Pattern leadingDigitsPattern = regexCache.getPatternForRegex( 21093399cc7a32833de9cb538ef7940eed61a23edcaNeil Fuller format.getLeadingDigitsPattern(lastLeadingDigitsPattern)); 2119ecee8b74bf330f20a902e4b974eddb7abedd627Shaopeng Jia Matcher m = leadingDigitsPattern.matcher(leadingDigits); 2129ecee8b74bf330f20a902e4b974eddb7abedd627Shaopeng Jia if (!m.lookingAt()) { 2139ecee8b74bf330f20a902e4b974eddb7abedd627Shaopeng Jia it.remove(); 2149ecee8b74bf330f20a902e4b974eddb7abedd627Shaopeng Jia } 2151524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } 2161524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } 2171524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia 2181524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia private boolean createFormattingTemplate(NumberFormat format) { 21993399cc7a32833de9cb538ef7940eed61a23edcaNeil Fuller String numberPattern = format.getPattern(); 2201524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia 2210199c997f87434f2c5a7d1df4bb4b5f904312b9fShaopeng Jia // The formatter doesn't format numbers when numberPattern contains "|", e.g. 2220199c997f87434f2c5a7d1df4bb4b5f904312b9fShaopeng Jia // (20|3)\d{4}. In those cases we quickly return. 2230199c997f87434f2c5a7d1df4bb4b5f904312b9fShaopeng Jia if (numberPattern.indexOf('|') != -1) { 2241524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia return false; 2251524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } 2261524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia 2271524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia // Replace anything in the form of [..] with \d 2280199c997f87434f2c5a7d1df4bb4b5f904312b9fShaopeng Jia numberPattern = CHARACTER_CLASS_PATTERN.matcher(numberPattern).replaceAll("\\\\d"); 2291524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia 2301524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia // Replace any standalone digit (not the one in d{}) with \d 2310199c997f87434f2c5a7d1df4bb4b5f904312b9fShaopeng Jia numberPattern = STANDALONE_DIGIT_PATTERN.matcher(numberPattern).replaceAll("\\\\d"); 232df19cbfb8a1e8720bae76bb763ab29622e057c42Shaopeng Jia formattingTemplate.setLength(0); 23393399cc7a32833de9cb538ef7940eed61a23edcaNeil Fuller String tempTemplate = getFormattingTemplate(numberPattern, format.getFormat()); 234d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia if (tempTemplate.length() > 0) { 23552699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia formattingTemplate.append(tempTemplate); 23652699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia return true; 23752699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia } 23852699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia return false; 2391524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } 2401524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia 241372bff8dd464574d36737d47e495cad14346653cShaopeng Jia // Gets a formatting template which can be used to efficiently format a partial number where 2421524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia // digits are added one by one. 2431524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia private String getFormattingTemplate(String numberPattern, String numberFormat) { 2441524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia // Creates a phone number consisting only of the digit 9 that matches the 2451524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia // numberPattern by applying the pattern to the longestPhoneNumber string. 2461524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia String longestPhoneNumber = "999999999999999"; 247df19cbfb8a1e8720bae76bb763ab29622e057c42Shaopeng Jia Matcher m = regexCache.getPatternForRegex(numberPattern).matcher(longestPhoneNumber); 2481524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia m.find(); // this will always succeed 2491524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia String aPhoneNumber = m.group(); 250d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia // No formatting template can be created if the number of digits entered so far is longer than 251d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia // the maximum the current formatting rule can accommodate. 252d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia if (aPhoneNumber.length() < nationalNumber.length()) { 253d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia return ""; 254d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia } 2551524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia // Formats the number according to numberFormat 2561524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia String template = aPhoneNumber.replaceAll(numberPattern, numberFormat); 257203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia // Replaces each digit with character DIGIT_PLACEHOLDER 258203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia template = template.replaceAll("9", DIGIT_PLACEHOLDER); 2591524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia return template; 2601524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } 2611524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia 2621524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia /** 263372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * Clears the internal state of the formatter, so it can be reused. 2641524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia */ 2651524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia public void clear() { 266df19cbfb8a1e8720bae76bb763ab29622e057c42Shaopeng Jia currentOutput = ""; 2670199c997f87434f2c5a7d1df4bb4b5f904312b9fShaopeng Jia accruedInput.setLength(0); 2680199c997f87434f2c5a7d1df4bb4b5f904312b9fShaopeng Jia accruedInputWithoutFormatting.setLength(0); 269df19cbfb8a1e8720bae76bb763ab29622e057c42Shaopeng Jia formattingTemplate.setLength(0); 2701524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia lastMatchPosition = 0; 271df19cbfb8a1e8720bae76bb763ab29622e057c42Shaopeng Jia currentFormattingPattern = ""; 2720199c997f87434f2c5a7d1df4bb4b5f904312b9fShaopeng Jia prefixBeforeNationalNumber.setLength(0); 273b03a14984ad9b0d8b88337ca714cb831233b99c3Shaopeng Jia extractedNationalPrefix = ""; 2740199c997f87434f2c5a7d1df4bb4b5f904312b9fShaopeng Jia nationalNumber.setLength(0); 2751524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia ableToFormat = true; 276ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia inputHasFormatting = false; 277df19cbfb8a1e8720bae76bb763ab29622e057c42Shaopeng Jia positionToRemember = 0; 2780b3c1fb05c01bc853ad927356eee743b62a8121bShaopeng Jia originalPosition = 0; 279203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia isCompleteNumber = false; 280372bff8dd464574d36737d47e495cad14346653cShaopeng Jia isExpectingCountryCallingCode = false; 281df19cbfb8a1e8720bae76bb763ab29622e057c42Shaopeng Jia possibleFormats.clear(); 282203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia shouldAddSpaceAfterNationalPrefix = false; 283bb78ce92eae2d5de9aa06b27ed3b87bc496c79eeShaopeng Jia if (!currentMetadata.equals(defaultMetadata)) { 284bb78ce92eae2d5de9aa06b27ed3b87bc496c79eeShaopeng Jia currentMetadata = getMetadataForRegion(defaultCountry); 2851524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } 2861524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } 2871524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia 288df19cbfb8a1e8720bae76bb763ab29622e057c42Shaopeng Jia /** 289df19cbfb8a1e8720bae76bb763ab29622e057c42Shaopeng Jia * Formats a phone number on-the-fly as each digit is entered. 290df19cbfb8a1e8720bae76bb763ab29622e057c42Shaopeng Jia * 291df19cbfb8a1e8720bae76bb763ab29622e057c42Shaopeng Jia * @param nextChar the most recently entered digit of a phone number. Formatting characters are 292372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * allowed, but as soon as they are encountered this method formats the number as entered and 293372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * not "as you type" anymore. Full width digits and Arabic-indic digits are allowed, and will 294372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * be shown as they are. 295df19cbfb8a1e8720bae76bb763ab29622e057c42Shaopeng Jia * @return the partially formatted phone number. 296df19cbfb8a1e8720bae76bb763ab29622e057c42Shaopeng Jia */ 2974b7846722d1a5acb0577b07e98324f744f5e7942Shaopeng Jia public String inputDigit(char nextChar) { 298df19cbfb8a1e8720bae76bb763ab29622e057c42Shaopeng Jia currentOutput = inputDigitWithOptionToRememberPosition(nextChar, false); 299df19cbfb8a1e8720bae76bb763ab29622e057c42Shaopeng Jia return currentOutput; 3004b7846722d1a5acb0577b07e98324f744f5e7942Shaopeng Jia } 3014b7846722d1a5acb0577b07e98324f744f5e7942Shaopeng Jia 3021524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia /** 303372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * Same as {@link #inputDigit}, but remembers the position where {@code nextChar} is inserted, so 304372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * that it can be retrieved later by using {@link #getRememberedPosition}. The remembered 305372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * position will be automatically adjusted if additional formatting characters are later 306372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * inserted/removed in front of {@code nextChar}. 3071524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia */ 3084b7846722d1a5acb0577b07e98324f744f5e7942Shaopeng Jia public String inputDigitAndRememberPosition(char nextChar) { 309df19cbfb8a1e8720bae76bb763ab29622e057c42Shaopeng Jia currentOutput = inputDigitWithOptionToRememberPosition(nextChar, true); 310df19cbfb8a1e8720bae76bb763ab29622e057c42Shaopeng Jia return currentOutput; 3114b7846722d1a5acb0577b07e98324f744f5e7942Shaopeng Jia } 3124b7846722d1a5acb0577b07e98324f744f5e7942Shaopeng Jia 31352699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia @SuppressWarnings("fallthrough") 3144b7846722d1a5acb0577b07e98324f744f5e7942Shaopeng Jia private String inputDigitWithOptionToRememberPosition(char nextChar, boolean rememberPosition) { 3151524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia accruedInput.append(nextChar); 3164b7846722d1a5acb0577b07e98324f744f5e7942Shaopeng Jia if (rememberPosition) { 317df19cbfb8a1e8720bae76bb763ab29622e057c42Shaopeng Jia originalPosition = accruedInput.length(); 3184b7846722d1a5acb0577b07e98324f744f5e7942Shaopeng Jia } 319f7e0224b862054893f28d2736b3f6804d9935886Shaopeng Jia // We do formatting on-the-fly only when each character entered is either a digit, or a plus 32016b56da4e787a614d16bedcd02b5086d40efbbdbShaopeng Jia // sign (accepted at the start of the number only). 32116b56da4e787a614d16bedcd02b5086d40efbbdbShaopeng Jia if (!isDigitOrLeadingPlusSign(nextChar)) { 3221524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia ableToFormat = false; 323ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia inputHasFormatting = true; 324ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia } else { 325ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia nextChar = normalizeAndAccrueDigitsAndPlusSign(nextChar, rememberPosition); 3261524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } 3271524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia if (!ableToFormat) { 328ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia // When we are unable to format because of reasons other than that formatting chars have been 329ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia // entered, it can be due to really long IDDs or NDDs. If that is the case, we might be able 330ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia // to do formatting again after extracting them. 331ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia if (inputHasFormatting) { 332ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia return accruedInput.toString(); 333ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia } else if (attemptToExtractIdd()) { 334ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia if (attemptToExtractCountryCallingCode()) { 335ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia return attemptToChoosePatternWithPrefixExtracted(); 336ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia } 337ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia } else if (ableToExtractLongerNdd()) { 338ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia // Add an additional space to separate long NDD and national significant number for 339203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia // readability. We don't set shouldAddSpaceAfterNationalPrefix to true, since we don't want 340203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia // this to change later when we choose formatting templates. 341203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia prefixBeforeNationalNumber.append(SEPARATOR_BEFORE_NATIONAL_NUMBER); 342ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia return attemptToChoosePatternWithPrefixExtracted(); 343ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia } 3441524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia return accruedInput.toString(); 3451524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } 3461524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia 347df19cbfb8a1e8720bae76bb763ab29622e057c42Shaopeng Jia // We start to attempt to format only when at least MIN_LEADING_DIGITS_LENGTH digits (the plus 348df19cbfb8a1e8720bae76bb763ab29622e057c42Shaopeng Jia // sign is counted as a digit as well for this purpose) have been entered. 3491524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia switch (accruedInputWithoutFormatting.length()) { 350372bff8dd464574d36737d47e495cad14346653cShaopeng Jia case 0: 3511524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia case 1: 3521524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia case 2: 353df19cbfb8a1e8720bae76bb763ab29622e057c42Shaopeng Jia return accruedInput.toString(); 3541524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia case 3: 355df19cbfb8a1e8720bae76bb763ab29622e057c42Shaopeng Jia if (attemptToExtractIdd()) { 356372bff8dd464574d36737d47e495cad14346653cShaopeng Jia isExpectingCountryCallingCode = true; 357ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia } else { // No IDD or plus sign is found, might be entering in national format. 358b03a14984ad9b0d8b88337ca714cb831233b99c3Shaopeng Jia extractedNationalPrefix = removeNationalPrefixFromNationalNumber(); 359df19cbfb8a1e8720bae76bb763ab29622e057c42Shaopeng Jia return attemptToChooseFormattingPattern(); 360df19cbfb8a1e8720bae76bb763ab29622e057c42Shaopeng Jia } 361ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia default: 362372bff8dd464574d36737d47e495cad14346653cShaopeng Jia if (isExpectingCountryCallingCode) { 363372bff8dd464574d36737d47e495cad14346653cShaopeng Jia if (attemptToExtractCountryCallingCode()) { 364372bff8dd464574d36737d47e495cad14346653cShaopeng Jia isExpectingCountryCallingCode = false; 365df19cbfb8a1e8720bae76bb763ab29622e057c42Shaopeng Jia } 366df19cbfb8a1e8720bae76bb763ab29622e057c42Shaopeng Jia return prefixBeforeNationalNumber + nationalNumber.toString(); 367df19cbfb8a1e8720bae76bb763ab29622e057c42Shaopeng Jia } 3689ecee8b74bf330f20a902e4b974eddb7abedd627Shaopeng Jia if (possibleFormats.size() > 0) { // The formatting patterns are already chosen. 369df19cbfb8a1e8720bae76bb763ab29622e057c42Shaopeng Jia String tempNationalNumber = inputDigitHelper(nextChar); 370df19cbfb8a1e8720bae76bb763ab29622e057c42Shaopeng Jia // See if the accrued digits can be formatted properly already. If not, use the results 371df19cbfb8a1e8720bae76bb763ab29622e057c42Shaopeng Jia // from inputDigitHelper, which does formatting based on the formatting pattern chosen. 372df19cbfb8a1e8720bae76bb763ab29622e057c42Shaopeng Jia String formattedNumber = attemptToFormatAccruedDigits(); 373df19cbfb8a1e8720bae76bb763ab29622e057c42Shaopeng Jia if (formattedNumber.length() > 0) { 374df19cbfb8a1e8720bae76bb763ab29622e057c42Shaopeng Jia return formattedNumber; 375df19cbfb8a1e8720bae76bb763ab29622e057c42Shaopeng Jia } 376df19cbfb8a1e8720bae76bb763ab29622e057c42Shaopeng Jia narrowDownPossibleFormats(nationalNumber.toString()); 377df19cbfb8a1e8720bae76bb763ab29622e057c42Shaopeng Jia if (maybeCreateNewTemplate()) { 378df19cbfb8a1e8720bae76bb763ab29622e057c42Shaopeng Jia return inputAccruedNationalNumber(); 379df19cbfb8a1e8720bae76bb763ab29622e057c42Shaopeng Jia } 3800b3c1fb05c01bc853ad927356eee743b62a8121bShaopeng Jia return ableToFormat 381203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia ? appendNationalNumber(tempNationalNumber) 382f3c6df010e7bc8ead25ba577ae09474b70d08adcShaopeng Jia : accruedInput.toString(); 3831524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } else { 384df19cbfb8a1e8720bae76bb763ab29622e057c42Shaopeng Jia return attemptToChooseFormattingPattern(); 3851524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } 3861524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } 3871524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } 3881524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia 389ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia private String attemptToChoosePatternWithPrefixExtracted() { 390ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia ableToFormat = true; 391ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia isExpectingCountryCallingCode = false; 392ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia possibleFormats.clear(); 3937491c3442ffdba4a604c18a7a853590a3b32fcfcNarayan Kamath lastMatchPosition = 0; 3947491c3442ffdba4a604c18a7a853590a3b32fcfcNarayan Kamath formattingTemplate.setLength(0); 3957491c3442ffdba4a604c18a7a853590a3b32fcfcNarayan Kamath currentFormattingPattern = ""; 396ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia return attemptToChooseFormattingPattern(); 397ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia } 398ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia 399b03a14984ad9b0d8b88337ca714cb831233b99c3Shaopeng Jia // @VisibleForTesting 400b03a14984ad9b0d8b88337ca714cb831233b99c3Shaopeng Jia String getExtractedNationalPrefix() { 401b03a14984ad9b0d8b88337ca714cb831233b99c3Shaopeng Jia return extractedNationalPrefix; 402b03a14984ad9b0d8b88337ca714cb831233b99c3Shaopeng Jia } 403b03a14984ad9b0d8b88337ca714cb831233b99c3Shaopeng Jia 404ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia // Some national prefixes are a substring of others. If extracting the shorter NDD doesn't result 405ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia // in a number we can format, we try to see if we can extract a longer version here. 406ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia private boolean ableToExtractLongerNdd() { 407b03a14984ad9b0d8b88337ca714cb831233b99c3Shaopeng Jia if (extractedNationalPrefix.length() > 0) { 408ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia // Put the extracted NDD back to the national number before attempting to extract a new NDD. 409b03a14984ad9b0d8b88337ca714cb831233b99c3Shaopeng Jia nationalNumber.insert(0, extractedNationalPrefix); 410ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia // Remove the previously extracted NDD from prefixBeforeNationalNumber. We cannot simply set 41177aadd284847681bd66af639636c2fa43e418c2bShaopeng Jia // it to empty string because people sometimes incorrectly enter national prefix after the 41277aadd284847681bd66af639636c2fa43e418c2bShaopeng Jia // country code, e.g. +44 (0)20-1234-5678. 413b03a14984ad9b0d8b88337ca714cb831233b99c3Shaopeng Jia int indexOfPreviousNdd = prefixBeforeNationalNumber.lastIndexOf(extractedNationalPrefix); 414ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia prefixBeforeNationalNumber.setLength(indexOfPreviousNdd); 415ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia } 416b03a14984ad9b0d8b88337ca714cb831233b99c3Shaopeng Jia return !extractedNationalPrefix.equals(removeNationalPrefixFromNationalNumber()); 417ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia } 418ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia 41916b56da4e787a614d16bedcd02b5086d40efbbdbShaopeng Jia private boolean isDigitOrLeadingPlusSign(char nextChar) { 42016b56da4e787a614d16bedcd02b5086d40efbbdbShaopeng Jia return Character.isDigit(nextChar) || 42116b56da4e787a614d16bedcd02b5086d40efbbdbShaopeng Jia (accruedInput.length() == 1 && 42216b56da4e787a614d16bedcd02b5086d40efbbdbShaopeng Jia PhoneNumberUtil.PLUS_CHARS_PATTERN.matcher(Character.toString(nextChar)).matches()); 42316b56da4e787a614d16bedcd02b5086d40efbbdbShaopeng Jia } 42416b56da4e787a614d16bedcd02b5086d40efbbdbShaopeng Jia 425203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia /** 426203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia * Check to see if there is an exact pattern match for these digits. If so, we should use this 427203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia * instead of any other formatting template whose leadingDigitsPattern also matches the input. 428203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia */ 429df19cbfb8a1e8720bae76bb763ab29622e057c42Shaopeng Jia String attemptToFormatAccruedDigits() { 430203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia for (NumberFormat numberFormat : possibleFormats) { 43193399cc7a32833de9cb538ef7940eed61a23edcaNeil Fuller Matcher m = regexCache.getPatternForRegex(numberFormat.getPattern()).matcher(nationalNumber); 432df19cbfb8a1e8720bae76bb763ab29622e057c42Shaopeng Jia if (m.matches()) { 433203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia shouldAddSpaceAfterNationalPrefix = 434203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia NATIONAL_PREFIX_SEPARATORS_PATTERN.matcher( 43593399cc7a32833de9cb538ef7940eed61a23edcaNeil Fuller numberFormat.getNationalPrefixFormattingRule()).find(); 43693399cc7a32833de9cb538ef7940eed61a23edcaNeil Fuller String formattedNumber = m.replaceAll(numberFormat.getFormat()); 437203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia return appendNationalNumber(formattedNumber); 438df19cbfb8a1e8720bae76bb763ab29622e057c42Shaopeng Jia } 4390b3c1fb05c01bc853ad927356eee743b62a8121bShaopeng Jia } 440df19cbfb8a1e8720bae76bb763ab29622e057c42Shaopeng Jia return ""; 4410b3c1fb05c01bc853ad927356eee743b62a8121bShaopeng Jia } 4420b3c1fb05c01bc853ad927356eee743b62a8121bShaopeng Jia 4430b3c1fb05c01bc853ad927356eee743b62a8121bShaopeng Jia /** 4440b3c1fb05c01bc853ad927356eee743b62a8121bShaopeng Jia * Returns the current position in the partially formatted phone number of the character which was 445372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * previously passed in as the parameter of {@link #inputDigitAndRememberPosition}. 4460b3c1fb05c01bc853ad927356eee743b62a8121bShaopeng Jia */ 4470b3c1fb05c01bc853ad927356eee743b62a8121bShaopeng Jia public int getRememberedPosition() { 448df19cbfb8a1e8720bae76bb763ab29622e057c42Shaopeng Jia if (!ableToFormat) { 449df19cbfb8a1e8720bae76bb763ab29622e057c42Shaopeng Jia return originalPosition; 450df19cbfb8a1e8720bae76bb763ab29622e057c42Shaopeng Jia } 45152699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia int accruedInputIndex = 0, currentOutputIndex = 0; 452372bff8dd464574d36737d47e495cad14346653cShaopeng Jia while (accruedInputIndex < positionToRemember && currentOutputIndex < currentOutput.length()) { 453df19cbfb8a1e8720bae76bb763ab29622e057c42Shaopeng Jia if (accruedInputWithoutFormatting.charAt(accruedInputIndex) == 454df19cbfb8a1e8720bae76bb763ab29622e057c42Shaopeng Jia currentOutput.charAt(currentOutputIndex)) { 455df19cbfb8a1e8720bae76bb763ab29622e057c42Shaopeng Jia accruedInputIndex++; 456df19cbfb8a1e8720bae76bb763ab29622e057c42Shaopeng Jia } 457372bff8dd464574d36737d47e495cad14346653cShaopeng Jia currentOutputIndex++; 458df19cbfb8a1e8720bae76bb763ab29622e057c42Shaopeng Jia } 459df19cbfb8a1e8720bae76bb763ab29622e057c42Shaopeng Jia return currentOutputIndex; 4600b3c1fb05c01bc853ad927356eee743b62a8121bShaopeng Jia } 4610b3c1fb05c01bc853ad927356eee743b62a8121bShaopeng Jia 462203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia /** 463203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia * Combines the national number with any prefix (IDD/+ and country code or national prefix) that 464203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia * was collected. A space will be inserted between them if the current formatting template 465203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia * indicates this to be suitable. 466203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia */ 467203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia private String appendNationalNumber(String nationalNumber) { 468203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia int prefixBeforeNationalNumberLength = prefixBeforeNationalNumber.length(); 469203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia if (shouldAddSpaceAfterNationalPrefix && prefixBeforeNationalNumberLength > 0 && 470203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia prefixBeforeNationalNumber.charAt(prefixBeforeNationalNumberLength - 1) 471203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia != SEPARATOR_BEFORE_NATIONAL_NUMBER) { 472203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia // We want to add a space after the national prefix if the national prefix formatting rule 473203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia // indicates that this would normally be done, with the exception of the case where we already 474203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia // appended a space because the NDD was surprisingly long. 475203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia return new String(prefixBeforeNationalNumber) + SEPARATOR_BEFORE_NATIONAL_NUMBER 476203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia + nationalNumber; 477203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia } else { 478203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia return prefixBeforeNationalNumber + nationalNumber; 479203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia } 480203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia } 481203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia 482203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia /** 483203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia * Attempts to set the formatting template and returns a string which contains the formatted 484203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia * version of the digits entered so far. 485203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia */ 486df19cbfb8a1e8720bae76bb763ab29622e057c42Shaopeng Jia private String attemptToChooseFormattingPattern() { 487bb78ce92eae2d5de9aa06b27ed3b87bc496c79eeShaopeng Jia // We start to attempt to format only when at least MIN_LEADING_DIGITS_LENGTH digits of national 488df19cbfb8a1e8720bae76bb763ab29622e057c42Shaopeng Jia // number (excluding national prefix) have been entered. 489df19cbfb8a1e8720bae76bb763ab29622e057c42Shaopeng Jia if (nationalNumber.length() >= MIN_LEADING_DIGITS_LENGTH) { 4909ecee8b74bf330f20a902e4b974eddb7abedd627Shaopeng Jia 4919ecee8b74bf330f20a902e4b974eddb7abedd627Shaopeng Jia getAvailableFormats(nationalNumber.toString()); 492bb78ce92eae2d5de9aa06b27ed3b87bc496c79eeShaopeng Jia // See if the accrued digits can be formatted properly already. 493bb78ce92eae2d5de9aa06b27ed3b87bc496c79eeShaopeng Jia String formattedNumber = attemptToFormatAccruedDigits(); 494bb78ce92eae2d5de9aa06b27ed3b87bc496c79eeShaopeng Jia if (formattedNumber.length() > 0) { 495bb78ce92eae2d5de9aa06b27ed3b87bc496c79eeShaopeng Jia return formattedNumber; 496bb78ce92eae2d5de9aa06b27ed3b87bc496c79eeShaopeng Jia } 49796a7214cdabf08f53f5b1a560304601c9f65e0b9Shaopeng Jia return maybeCreateNewTemplate() ? inputAccruedNationalNumber() : accruedInput.toString(); 4981524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } else { 499203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia return appendNationalNumber(nationalNumber.toString()); 5001524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } 5011524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } 5021524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia 503203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia /** 504203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia * Invokes inputDigitHelper on each digit of the national number accrued, and returns a formatted 505203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia * string in the end. 506203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia */ 507df19cbfb8a1e8720bae76bb763ab29622e057c42Shaopeng Jia private String inputAccruedNationalNumber() { 5081524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia int lengthOfNationalNumber = nationalNumber.length(); 5091524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia if (lengthOfNationalNumber > 0) { 5104b7846722d1a5acb0577b07e98324f744f5e7942Shaopeng Jia String tempNationalNumber = ""; 5114b7846722d1a5acb0577b07e98324f744f5e7942Shaopeng Jia for (int i = 0; i < lengthOfNationalNumber; i++) { 512df19cbfb8a1e8720bae76bb763ab29622e057c42Shaopeng Jia tempNationalNumber = inputDigitHelper(nationalNumber.charAt(i)); 5131524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } 514203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia return ableToFormat ? appendNationalNumber(tempNationalNumber) : accruedInput.toString(); 5151524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } else { 5161524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia return prefixBeforeNationalNumber.toString(); 5171524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } 5181524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } 5191524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia 520203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia /** 521203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia * Returns true if the current country is a NANPA country and the national number begins with 522203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia * the national prefix. 523203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia */ 524203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia private boolean isNanpaNumberWithNationalPrefix() { 525203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia // For NANPA numbers beginning with 1[2-9], treat the 1 as the national prefix. The reason is 526203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia // that national significant numbers in NANPA always start with [2-9] after the national prefix. 527203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia // Numbers beginning with 1[01] can only be short/emergency numbers, which don't need the 528203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia // national prefix. 52993399cc7a32833de9cb538ef7940eed61a23edcaNeil Fuller return (currentMetadata.getCountryCode() == 1) && (nationalNumber.charAt(0) == '1') && 530203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia (nationalNumber.charAt(1) != '0') && (nationalNumber.charAt(1) != '1'); 531203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia } 532203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia 533ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia // Returns the national prefix extracted, or an empty string if it is not present. 534ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia private String removeNationalPrefixFromNationalNumber() { 5351524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia int startOfNationalNumber = 0; 536203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia if (isNanpaNumberWithNationalPrefix()) { 53794c2440dc41689b7d9c169edf5089eeebf7527d7Shaopeng Jia startOfNationalNumber = 1; 538203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia prefixBeforeNationalNumber.append('1').append(SEPARATOR_BEFORE_NATIONAL_NUMBER); 539203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia isCompleteNumber = true; 54093399cc7a32833de9cb538ef7940eed61a23edcaNeil Fuller } else if (currentMetadata.hasNationalPrefixForParsing()) { 541372bff8dd464574d36737d47e495cad14346653cShaopeng Jia Pattern nationalPrefixForParsing = 54293399cc7a32833de9cb538ef7940eed61a23edcaNeil Fuller regexCache.getPatternForRegex(currentMetadata.getNationalPrefixForParsing()); 5431524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia Matcher m = nationalPrefixForParsing.matcher(nationalNumber); 544bb78ce92eae2d5de9aa06b27ed3b87bc496c79eeShaopeng Jia // Since some national prefix patterns are entirely optional, check that a national prefix 545bb78ce92eae2d5de9aa06b27ed3b87bc496c79eeShaopeng Jia // could actually be extracted. 546bb78ce92eae2d5de9aa06b27ed3b87bc496c79eeShaopeng Jia if (m.lookingAt() && m.end() > 0) { 547f59ccfca9dd02c4e3cf3e06b5cf184a8d0e67626Shaopeng Jia // When the national prefix is detected, we use international formatting rules instead of 548f59ccfca9dd02c4e3cf3e06b5cf184a8d0e67626Shaopeng Jia // national ones, because national formatting rules could contain local formatting rules 549f59ccfca9dd02c4e3cf3e06b5cf184a8d0e67626Shaopeng Jia // for numbers entered without area code. 550203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia isCompleteNumber = true; 5511524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia startOfNationalNumber = m.end(); 5521524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia prefixBeforeNationalNumber.append(nationalNumber.substring(0, startOfNationalNumber)); 5531524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } 5541524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } 555ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia String nationalPrefix = nationalNumber.substring(0, startOfNationalNumber); 5561524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia nationalNumber.delete(0, startOfNationalNumber); 557ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia return nationalPrefix; 5581524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } 5591524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia 5601524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia /** 561df19cbfb8a1e8720bae76bb763ab29622e057c42Shaopeng Jia * Extracts IDD and plus sign to prefixBeforeNationalNumber when they are available, and places 562df19cbfb8a1e8720bae76bb763ab29622e057c42Shaopeng Jia * the remaining input into nationalNumber. 5631524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * 564df19cbfb8a1e8720bae76bb763ab29622e057c42Shaopeng Jia * @return true when accruedInputWithoutFormatting begins with the plus sign or valid IDD for 565df19cbfb8a1e8720bae76bb763ab29622e057c42Shaopeng Jia * defaultCountry. 5661524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia */ 567df19cbfb8a1e8720bae76bb763ab29622e057c42Shaopeng Jia private boolean attemptToExtractIdd() { 568372bff8dd464574d36737d47e495cad14346653cShaopeng Jia Pattern internationalPrefix = 569372bff8dd464574d36737d47e495cad14346653cShaopeng Jia regexCache.getPatternForRegex("\\" + PhoneNumberUtil.PLUS_SIGN + "|" + 57093399cc7a32833de9cb538ef7940eed61a23edcaNeil Fuller currentMetadata.getInternationalPrefix()); 5711524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia Matcher iddMatcher = internationalPrefix.matcher(accruedInputWithoutFormatting); 5721524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia if (iddMatcher.lookingAt()) { 573203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia isCompleteNumber = true; 574372bff8dd464574d36737d47e495cad14346653cShaopeng Jia int startOfCountryCallingCode = iddMatcher.end(); 575df19cbfb8a1e8720bae76bb763ab29622e057c42Shaopeng Jia nationalNumber.setLength(0); 576372bff8dd464574d36737d47e495cad14346653cShaopeng Jia nationalNumber.append(accruedInputWithoutFormatting.substring(startOfCountryCallingCode)); 577ca1e43d6e1fac07c7fc29c66c7da1fa9d7cf50f2Shaopeng Jia prefixBeforeNationalNumber.setLength(0); 578df19cbfb8a1e8720bae76bb763ab29622e057c42Shaopeng Jia prefixBeforeNationalNumber.append( 579372bff8dd464574d36737d47e495cad14346653cShaopeng Jia accruedInputWithoutFormatting.substring(0, startOfCountryCallingCode)); 580df19cbfb8a1e8720bae76bb763ab29622e057c42Shaopeng Jia if (accruedInputWithoutFormatting.charAt(0) != PhoneNumberUtil.PLUS_SIGN) { 581203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia prefixBeforeNationalNumber.append(SEPARATOR_BEFORE_NATIONAL_NUMBER); 582df19cbfb8a1e8720bae76bb763ab29622e057c42Shaopeng Jia } 583df19cbfb8a1e8720bae76bb763ab29622e057c42Shaopeng Jia return true; 584df19cbfb8a1e8720bae76bb763ab29622e057c42Shaopeng Jia } 585df19cbfb8a1e8720bae76bb763ab29622e057c42Shaopeng Jia return false; 586df19cbfb8a1e8720bae76bb763ab29622e057c42Shaopeng Jia } 587df19cbfb8a1e8720bae76bb763ab29622e057c42Shaopeng Jia 588df19cbfb8a1e8720bae76bb763ab29622e057c42Shaopeng Jia /** 589372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * Extracts the country calling code from the beginning of nationalNumber to 590372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * prefixBeforeNationalNumber when they are available, and places the remaining input into 591372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * nationalNumber. 592df19cbfb8a1e8720bae76bb763ab29622e057c42Shaopeng Jia * 593372bff8dd464574d36737d47e495cad14346653cShaopeng Jia * @return true when a valid country calling code can be found. 594df19cbfb8a1e8720bae76bb763ab29622e057c42Shaopeng Jia */ 595372bff8dd464574d36737d47e495cad14346653cShaopeng Jia private boolean attemptToExtractCountryCallingCode() { 596f59ccfca9dd02c4e3cf3e06b5cf184a8d0e67626Shaopeng Jia if (nationalNumber.length() == 0) { 597f59ccfca9dd02c4e3cf3e06b5cf184a8d0e67626Shaopeng Jia return false; 598f59ccfca9dd02c4e3cf3e06b5cf184a8d0e67626Shaopeng Jia } 599372bff8dd464574d36737d47e495cad14346653cShaopeng Jia StringBuilder numberWithoutCountryCallingCode = new StringBuilder(); 600372bff8dd464574d36737d47e495cad14346653cShaopeng Jia int countryCode = phoneUtil.extractCountryCode(nationalNumber, numberWithoutCountryCallingCode); 601f59ccfca9dd02c4e3cf3e06b5cf184a8d0e67626Shaopeng Jia if (countryCode == 0) { 602f59ccfca9dd02c4e3cf3e06b5cf184a8d0e67626Shaopeng Jia return false; 603f59ccfca9dd02c4e3cf3e06b5cf184a8d0e67626Shaopeng Jia } 604372bff8dd464574d36737d47e495cad14346653cShaopeng Jia nationalNumber.setLength(0); 605372bff8dd464574d36737d47e495cad14346653cShaopeng Jia nationalNumber.append(numberWithoutCountryCallingCode); 606372bff8dd464574d36737d47e495cad14346653cShaopeng Jia String newRegionCode = phoneUtil.getRegionCodeForCountryCode(countryCode); 607528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia if (PhoneNumberUtil.REGION_CODE_FOR_NON_GEO_ENTITY.equals(newRegionCode)) { 608bb78ce92eae2d5de9aa06b27ed3b87bc496c79eeShaopeng Jia currentMetadata = phoneUtil.getMetadataForNonGeographicalRegion(countryCode); 609528b0d12a556ff0c2d16f99d56fcdd62657f433cShaopeng Jia } else if (!newRegionCode.equals(defaultCountry)) { 610bb78ce92eae2d5de9aa06b27ed3b87bc496c79eeShaopeng Jia currentMetadata = getMetadataForRegion(newRegionCode); 611372bff8dd464574d36737d47e495cad14346653cShaopeng Jia } 612372bff8dd464574d36737d47e495cad14346653cShaopeng Jia String countryCodeString = Integer.toString(countryCode); 613203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia prefixBeforeNationalNumber.append(countryCodeString).append(SEPARATOR_BEFORE_NATIONAL_NUMBER); 614b03a14984ad9b0d8b88337ca714cb831233b99c3Shaopeng Jia // When we have successfully extracted the IDD, the previously extracted NDD should be cleared 615b03a14984ad9b0d8b88337ca714cb831233b99c3Shaopeng Jia // because it is no longer valid. 616b03a14984ad9b0d8b88337ca714cb831233b99c3Shaopeng Jia extractedNationalPrefix = ""; 6171524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia return true; 6181524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } 6191524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia 6201524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia // Accrues digits and the plus sign to accruedInputWithoutFormatting for later use. If nextChar 6211524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia // contains a digit in non-ASCII format (e.g. the full-width version of digits), it is first 6221524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia // normalized to the ASCII version. The return value is nextChar itself, or its normalized 623372bff8dd464574d36737d47e495cad14346653cShaopeng Jia // version, if nextChar is a digit in non-ASCII format. This method assumes its input is either a 624372bff8dd464574d36737d47e495cad14346653cShaopeng Jia // digit or the plus sign. 625df19cbfb8a1e8720bae76bb763ab29622e057c42Shaopeng Jia private char normalizeAndAccrueDigitsAndPlusSign(char nextChar, boolean rememberPosition) { 626d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia char normalizedChar; 6271524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia if (nextChar == PhoneNumberUtil.PLUS_SIGN) { 628d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia normalizedChar = nextChar; 6291524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia accruedInputWithoutFormatting.append(nextChar); 630372bff8dd464574d36737d47e495cad14346653cShaopeng Jia } else { 631d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia int radix = 10; 632d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia normalizedChar = Character.forDigit(Character.digit(nextChar, radix), radix); 633d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia accruedInputWithoutFormatting.append(normalizedChar); 634d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia nationalNumber.append(normalizedChar); 6351524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } 636df19cbfb8a1e8720bae76bb763ab29622e057c42Shaopeng Jia if (rememberPosition) { 637df19cbfb8a1e8720bae76bb763ab29622e057c42Shaopeng Jia positionToRemember = accruedInputWithoutFormatting.length(); 638df19cbfb8a1e8720bae76bb763ab29622e057c42Shaopeng Jia } 639d1db4c508088ac27cb0815a222cf2600f16ad5b9Shaopeng Jia return normalizedChar; 6401524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } 6411524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia 642df19cbfb8a1e8720bae76bb763ab29622e057c42Shaopeng Jia private String inputDigitHelper(char nextChar) { 6437491c3442ffdba4a604c18a7a853590a3b32fcfcNarayan Kamath // Note that formattingTemplate is not guaranteed to have a value, it could be empty, e.g. 6447491c3442ffdba4a604c18a7a853590a3b32fcfcNarayan Kamath // when the next digit is entered after extracting an IDD or NDD. 645203cf688f8d56e2c1f9828801b113110465f39a7Shaopeng Jia Matcher digitMatcher = DIGIT_PATTERN.matcher(formattingTemplate); 6461524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia if (digitMatcher.find(lastMatchPosition)) { 647df19cbfb8a1e8720bae76bb763ab29622e057c42Shaopeng Jia String tempTemplate = digitMatcher.replaceFirst(Character.toString(nextChar)); 648df19cbfb8a1e8720bae76bb763ab29622e057c42Shaopeng Jia formattingTemplate.replace(0, tempTemplate.length(), tempTemplate); 6491524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia lastMatchPosition = digitMatcher.start(); 650df19cbfb8a1e8720bae76bb763ab29622e057c42Shaopeng Jia return formattingTemplate.substring(0, lastMatchPosition + 1); 65152699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia } else { 65252699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia if (possibleFormats.size() == 1) { 65352699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia // More digits are entered than we could handle, and there are no other valid patterns to 65452699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia // try. 65552699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia ableToFormat = false; 65652699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia } // else, we just reset the formatting pattern. 65752699e08e855fb0957944b4e73358ad9e0007c0cShaopeng Jia currentFormattingPattern = ""; 6580b3c1fb05c01bc853ad927356eee743b62a8121bShaopeng Jia return accruedInput.toString(); 6591524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } 6601524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia } 6611524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia} 662