Home | History | Annotate | Download | only in phonenumbers
      1 /*
      2  * Copyright (C) 2009 The Libphonenumber Authors
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  * http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.i18n.phonenumbers;
     18 
     19 import com.android.i18n.phonenumbers.Phonemetadata.NumberFormat;
     20 import com.android.i18n.phonenumbers.Phonemetadata.PhoneMetadata;
     21 
     22 import java.util.ArrayList;
     23 import java.util.Iterator;
     24 import java.util.List;
     25 import java.util.regex.Matcher;
     26 import java.util.regex.Pattern;
     27 
     28 /**
     29  * A formatter which formats phone numbers as they are entered.
     30  *
     31  * <p>An AsYouTypeFormatter can be created by invoking
     32  * {@link PhoneNumberUtil#getAsYouTypeFormatter}. After that, digits can be added by invoking
     33  * {@link #inputDigit} on the formatter instance, and the partially formatted phone number will be
     34  * returned each time a digit is added. {@link #clear} can be invoked before formatting a new
     35  * number.
     36  *
     37  * <p>See the unittests for more details on how the formatter is to be used.
     38  *
     39  * @author Shaopeng Jia
     40  */
     41 public class AsYouTypeFormatter {
     42   private String currentOutput = "";
     43   private StringBuilder formattingTemplate = new StringBuilder();
     44   // The pattern from numberFormat that is currently used to create formattingTemplate.
     45   private String currentFormattingPattern = "";
     46   private StringBuilder accruedInput = new StringBuilder();
     47   private StringBuilder accruedInputWithoutFormatting = new StringBuilder();
     48   // This indicates whether AsYouTypeFormatter is currently doing the formatting.
     49   private boolean ableToFormat = true;
     50   // Set to true when users enter their own formatting. AsYouTypeFormatter will do no formatting at
     51   // all when this is set to true.
     52   private boolean inputHasFormatting = false;
     53   private boolean isInternationalFormatting = false;
     54   private boolean isExpectingCountryCallingCode = false;
     55   private final PhoneNumberUtil phoneUtil = PhoneNumberUtil.getInstance();
     56   private String defaultCountry;
     57 
     58   private static final PhoneMetadata EMPTY_METADATA =
     59       new PhoneMetadata().setInternationalPrefix("NA");
     60   private PhoneMetadata defaultMetaData;
     61   private PhoneMetadata currentMetaData;
     62 
     63   // A pattern that is used to match character classes in regular expressions. An example of a
     64   // character class is [1-4].
     65   private static final Pattern CHARACTER_CLASS_PATTERN = Pattern.compile("\\[([^\\[\\]])*\\]");
     66   // Any digit in a regular expression that actually denotes a digit. For example, in the regular
     67   // expression 80[0-2]\d{6,10}, the first 2 digits (8 and 0) are standalone digits, but the rest
     68   // are not.
     69   // Two look-aheads are needed because the number following \\d could be a two-digit number, since
     70   // the phone number can be as long as 15 digits.
     71   private static final Pattern STANDALONE_DIGIT_PATTERN = Pattern.compile("\\d(?=[^,}][^,}])");
     72 
     73   // A pattern that is used to determine if a numberFormat under availableFormats is eligible to be
     74   // used by the AYTF. It is eligible when the format element under numberFormat contains groups of
     75   // the dollar sign followed by a single digit, separated by valid phone number punctuation. This
     76   // prevents invalid punctuation (such as the star sign in Israeli star numbers) getting into the
     77   // output of the AYTF.
     78   private static final Pattern ELIGIBLE_FORMAT_PATTERN =
     79       Pattern.compile("[" + PhoneNumberUtil.VALID_PUNCTUATION + "]*" +
     80           "(\\$\\d" + "[" + PhoneNumberUtil.VALID_PUNCTUATION + "]*)+");
     81 
     82   // This is the minimum length of national number accrued that is required to trigger the
     83   // formatter. The first element of the leadingDigitsPattern of each numberFormat contains a
     84   // regular expression that matches up to this number of digits.
     85   private static final int MIN_LEADING_DIGITS_LENGTH = 3;
     86 
     87   // The digits that have not been entered yet will be represented by a \u2008, the punctuation
     88   // space.
     89   private String digitPlaceholder = "\u2008";
     90   private Pattern digitPattern = Pattern.compile(digitPlaceholder);
     91   private int lastMatchPosition = 0;
     92   // The position of a digit upon which inputDigitAndRememberPosition is most recently invoked, as
     93   // found in the original sequence of characters the user entered.
     94   private int originalPosition = 0;
     95   // The position of a digit upon which inputDigitAndRememberPosition is most recently invoked, as
     96   // found in accruedInputWithoutFormatting.
     97   private int positionToRemember = 0;
     98   // This contains anything that has been entered so far preceding the national significant number,
     99   // and it is formatted (e.g. with space inserted). For example, this can contain IDD, country
    100   // code, and/or NDD, etc.
    101   private StringBuilder prefixBeforeNationalNumber = new StringBuilder();
    102   // This contains the national prefix that has been extracted. It contains only digits without
    103   // formatting.
    104   private String nationalPrefixExtracted = "";
    105   private StringBuilder nationalNumber = new StringBuilder();
    106   private List<NumberFormat> possibleFormats = new ArrayList<NumberFormat>();
    107 
    108     // A cache for frequently used country-specific regular expressions.
    109   private RegexCache regexCache = new RegexCache(64);
    110 
    111   /**
    112    * Constructs an as-you-type formatter. Should be obtained from {@link
    113    * PhoneNumberUtil#getAsYouTypeFormatter}.
    114    *
    115    * @param regionCode  the country/region where the phone number is being entered
    116    */
    117   AsYouTypeFormatter(String regionCode) {
    118     defaultCountry = regionCode;
    119     currentMetaData = getMetadataForRegion(defaultCountry);
    120     defaultMetaData = currentMetaData;
    121   }
    122 
    123   // The metadata needed by this class is the same for all regions sharing the same country calling
    124   // code. Therefore, we return the metadata for "main" region for this country calling code.
    125   private PhoneMetadata getMetadataForRegion(String regionCode) {
    126     int countryCallingCode = phoneUtil.getCountryCodeForRegion(regionCode);
    127     String mainCountry = phoneUtil.getRegionCodeForCountryCode(countryCallingCode);
    128     PhoneMetadata metadata = phoneUtil.getMetadataForRegion(mainCountry);
    129     if (metadata != null) {
    130       return metadata;
    131     }
    132     // Set to a default instance of the metadata. This allows us to function with an incorrect
    133     // region code, even if formatting only works for numbers specified with "+".
    134     return EMPTY_METADATA;
    135   }
    136 
    137   // Returns true if a new template is created as opposed to reusing the existing template.
    138   private boolean maybeCreateNewTemplate() {
    139     // When there are multiple available formats, the formatter uses the first format where a
    140     // formatting template could be created.
    141     Iterator<NumberFormat> it = possibleFormats.iterator();
    142     while (it.hasNext()) {
    143       NumberFormat numberFormat = it.next();
    144       String pattern = numberFormat.getPattern();
    145       if (currentFormattingPattern.equals(pattern)) {
    146         return false;
    147       }
    148       if (createFormattingTemplate(numberFormat)) {
    149         currentFormattingPattern = pattern;
    150         // With a new formatting template, the matched position using the old template needs to be
    151         // reset.
    152         lastMatchPosition = 0;
    153         return true;
    154       } else {  // Remove the current number format from possibleFormats.
    155         it.remove();
    156       }
    157     }
    158     ableToFormat = false;
    159     return false;
    160   }
    161 
    162   private void getAvailableFormats(String leadingThreeDigits) {
    163     List<NumberFormat> formatList =
    164         (isInternationalFormatting && currentMetaData.intlNumberFormatSize() > 0)
    165         ? currentMetaData.intlNumberFormats()
    166         : currentMetaData.numberFormats();
    167     for (NumberFormat format : formatList) {
    168       if (isFormatEligible(format.getFormat())) {
    169         possibleFormats.add(format);
    170       }
    171     }
    172     narrowDownPossibleFormats(leadingThreeDigits);
    173   }
    174 
    175   private boolean isFormatEligible(String format) {
    176     return ELIGIBLE_FORMAT_PATTERN.matcher(format).matches();
    177   }
    178 
    179   private void narrowDownPossibleFormats(String leadingDigits) {
    180     int indexOfLeadingDigitsPattern = leadingDigits.length() - MIN_LEADING_DIGITS_LENGTH;
    181     Iterator<NumberFormat> it = possibleFormats.iterator();
    182     while (it.hasNext()) {
    183       NumberFormat format = it.next();
    184       if (format.leadingDigitsPatternSize() > indexOfLeadingDigitsPattern) {
    185         Pattern leadingDigitsPattern =
    186             regexCache.getPatternForRegex(
    187                 format.getLeadingDigitsPattern(indexOfLeadingDigitsPattern));
    188         Matcher m = leadingDigitsPattern.matcher(leadingDigits);
    189         if (!m.lookingAt()) {
    190           it.remove();
    191         }
    192       } // else the particular format has no more specific leadingDigitsPattern, and it should be
    193         // retained.
    194     }
    195   }
    196 
    197   private boolean createFormattingTemplate(NumberFormat format) {
    198     String numberPattern = format.getPattern();
    199 
    200     // The formatter doesn't format numbers when numberPattern contains "|", e.g.
    201     // (20|3)\d{4}. In those cases we quickly return.
    202     if (numberPattern.indexOf('|') != -1) {
    203       return false;
    204     }
    205 
    206     // Replace anything in the form of [..] with \d
    207     numberPattern = CHARACTER_CLASS_PATTERN.matcher(numberPattern).replaceAll("\\\\d");
    208 
    209     // Replace any standalone digit (not the one in d{}) with \d
    210     numberPattern = STANDALONE_DIGIT_PATTERN.matcher(numberPattern).replaceAll("\\\\d");
    211     formattingTemplate.setLength(0);
    212     String tempTemplate = getFormattingTemplate(numberPattern, format.getFormat());
    213     if (tempTemplate.length() > 0) {
    214       formattingTemplate.append(tempTemplate);
    215       return true;
    216     }
    217     return false;
    218   }
    219 
    220   // Gets a formatting template which can be used to efficiently format a partial number where
    221   // digits are added one by one.
    222   private String getFormattingTemplate(String numberPattern, String numberFormat) {
    223     // Creates a phone number consisting only of the digit 9 that matches the
    224     // numberPattern by applying the pattern to the longestPhoneNumber string.
    225     String longestPhoneNumber = "999999999999999";
    226     Matcher m = regexCache.getPatternForRegex(numberPattern).matcher(longestPhoneNumber);
    227     m.find();  // this will always succeed
    228     String aPhoneNumber = m.group();
    229     // No formatting template can be created if the number of digits entered so far is longer than
    230     // the maximum the current formatting rule can accommodate.
    231     if (aPhoneNumber.length() < nationalNumber.length()) {
    232       return "";
    233     }
    234     // Formats the number according to numberFormat
    235     String template = aPhoneNumber.replaceAll(numberPattern, numberFormat);
    236     // Replaces each digit with character digitPlaceholder
    237     template = template.replaceAll("9", digitPlaceholder);
    238     return template;
    239   }
    240 
    241   /**
    242    * Clears the internal state of the formatter, so it can be reused.
    243    */
    244   public void clear() {
    245     currentOutput = "";
    246     accruedInput.setLength(0);
    247     accruedInputWithoutFormatting.setLength(0);
    248     formattingTemplate.setLength(0);
    249     lastMatchPosition = 0;
    250     currentFormattingPattern = "";
    251     prefixBeforeNationalNumber.setLength(0);
    252     nationalPrefixExtracted = "";
    253     nationalNumber.setLength(0);
    254     ableToFormat = true;
    255     inputHasFormatting = false;
    256     positionToRemember = 0;
    257     originalPosition = 0;
    258     isInternationalFormatting = false;
    259     isExpectingCountryCallingCode = false;
    260     possibleFormats.clear();
    261     if (!currentMetaData.equals(defaultMetaData)) {
    262       currentMetaData = getMetadataForRegion(defaultCountry);
    263     }
    264   }
    265 
    266   /**
    267    * Formats a phone number on-the-fly as each digit is entered.
    268    *
    269    * @param nextChar  the most recently entered digit of a phone number. Formatting characters are
    270    *     allowed, but as soon as they are encountered this method formats the number as entered and
    271    *     not "as you type" anymore. Full width digits and Arabic-indic digits are allowed, and will
    272    *     be shown as they are.
    273    * @return  the partially formatted phone number.
    274    */
    275   public String inputDigit(char nextChar) {
    276     currentOutput = inputDigitWithOptionToRememberPosition(nextChar, false);
    277     return currentOutput;
    278   }
    279 
    280   /**
    281    * Same as {@link #inputDigit}, but remembers the position where {@code nextChar} is inserted, so
    282    * that it can be retrieved later by using {@link #getRememberedPosition}. The remembered
    283    * position will be automatically adjusted if additional formatting characters are later
    284    * inserted/removed in front of {@code nextChar}.
    285    */
    286   public String inputDigitAndRememberPosition(char nextChar) {
    287     currentOutput = inputDigitWithOptionToRememberPosition(nextChar, true);
    288     return currentOutput;
    289   }
    290 
    291   @SuppressWarnings("fallthrough")
    292   private String inputDigitWithOptionToRememberPosition(char nextChar, boolean rememberPosition) {
    293     accruedInput.append(nextChar);
    294     if (rememberPosition) {
    295       originalPosition = accruedInput.length();
    296     }
    297     // We do formatting on-the-fly only when each character entered is either a digit, or a plus
    298     // sign (accepted at the start of the number only).
    299     if (!isDigitOrLeadingPlusSign(nextChar)) {
    300       ableToFormat = false;
    301       inputHasFormatting = true;
    302     } else {
    303       nextChar = normalizeAndAccrueDigitsAndPlusSign(nextChar, rememberPosition);
    304     }
    305     if (!ableToFormat) {
    306       // When we are unable to format because of reasons other than that formatting chars have been
    307       // entered, it can be due to really long IDDs or NDDs. If that is the case, we might be able
    308       // to do formatting again after extracting them.
    309       if (inputHasFormatting) {
    310         return accruedInput.toString();
    311       } else if (attemptToExtractIdd()) {
    312         if (attemptToExtractCountryCallingCode()) {
    313           return attemptToChoosePatternWithPrefixExtracted();
    314         }
    315       } else if (ableToExtractLongerNdd()) {
    316         // Add an additional space to separate long NDD and national significant number for
    317         // readability.
    318         prefixBeforeNationalNumber.append(" ");
    319         return attemptToChoosePatternWithPrefixExtracted();
    320       }
    321       return accruedInput.toString();
    322     }
    323 
    324     // We start to attempt to format only when at least MIN_LEADING_DIGITS_LENGTH digits (the plus
    325     // sign is counted as a digit as well for this purpose) have been entered.
    326     switch (accruedInputWithoutFormatting.length()) {
    327       case 0:
    328       case 1:
    329       case 2:
    330         return accruedInput.toString();
    331       case 3:
    332         if (attemptToExtractIdd()) {
    333           isExpectingCountryCallingCode = true;
    334         } else {  // No IDD or plus sign is found, might be entering in national format.
    335           nationalPrefixExtracted = removeNationalPrefixFromNationalNumber();
    336           return attemptToChooseFormattingPattern();
    337         }
    338       default:
    339         if (isExpectingCountryCallingCode) {
    340           if (attemptToExtractCountryCallingCode()) {
    341             isExpectingCountryCallingCode = false;
    342           }
    343           return prefixBeforeNationalNumber + nationalNumber.toString();
    344         }
    345         if (possibleFormats.size() > 0) {  // The formatting pattern is already chosen.
    346           String tempNationalNumber = inputDigitHelper(nextChar);
    347           // See if the accrued digits can be formatted properly already. If not, use the results
    348           // from inputDigitHelper, which does formatting based on the formatting pattern chosen.
    349           String formattedNumber = attemptToFormatAccruedDigits();
    350           if (formattedNumber.length() > 0) {
    351             return formattedNumber;
    352           }
    353           narrowDownPossibleFormats(nationalNumber.toString());
    354           if (maybeCreateNewTemplate()) {
    355             return inputAccruedNationalNumber();
    356           }
    357           return ableToFormat
    358              ? prefixBeforeNationalNumber + tempNationalNumber
    359              : accruedInput.toString();
    360         } else {
    361           return attemptToChooseFormattingPattern();
    362         }
    363     }
    364   }
    365 
    366   private String attemptToChoosePatternWithPrefixExtracted() {
    367     ableToFormat = true;
    368     isExpectingCountryCallingCode = false;
    369     possibleFormats.clear();
    370     return attemptToChooseFormattingPattern();
    371   }
    372 
    373   // Some national prefixes are a substring of others. If extracting the shorter NDD doesn't result
    374   // in a number we can format, we try to see if we can extract a longer version here.
    375   private boolean ableToExtractLongerNdd() {
    376     if (nationalPrefixExtracted.length() > 0) {
    377       // Put the extracted NDD back to the national number before attempting to extract a new NDD.
    378       nationalNumber.insert(0, nationalPrefixExtracted);
    379       // Remove the previously extracted NDD from prefixBeforeNationalNumber. We cannot simply set
    380       // it to empty string because people sometimes enter national prefix after country code, e.g
    381       // +44 (0)20-1234-5678.
    382       int indexOfPreviousNdd = prefixBeforeNationalNumber.lastIndexOf(nationalPrefixExtracted);
    383       prefixBeforeNationalNumber.setLength(indexOfPreviousNdd);
    384     }
    385     return !nationalPrefixExtracted.equals(removeNationalPrefixFromNationalNumber());
    386   }
    387 
    388   private boolean isDigitOrLeadingPlusSign(char nextChar) {
    389     return Character.isDigit(nextChar) ||
    390         (accruedInput.length() == 1 &&
    391          PhoneNumberUtil.PLUS_CHARS_PATTERN.matcher(Character.toString(nextChar)).matches());
    392   }
    393 
    394   String attemptToFormatAccruedDigits() {
    395     for (NumberFormat numFormat : possibleFormats) {
    396       Matcher m = regexCache.getPatternForRegex(numFormat.getPattern()).matcher(nationalNumber);
    397       if (m.matches()) {
    398         String formattedNumber = m.replaceAll(numFormat.getFormat());
    399         return prefixBeforeNationalNumber + formattedNumber;
    400       }
    401     }
    402     return "";
    403   }
    404 
    405   /**
    406    * Returns the current position in the partially formatted phone number of the character which was
    407    * previously passed in as the parameter of {@link #inputDigitAndRememberPosition}.
    408    */
    409   public int getRememberedPosition() {
    410     if (!ableToFormat) {
    411       return originalPosition;
    412     }
    413     int accruedInputIndex = 0, currentOutputIndex = 0;
    414     while (accruedInputIndex < positionToRemember && currentOutputIndex < currentOutput.length()) {
    415       if (accruedInputWithoutFormatting.charAt(accruedInputIndex) ==
    416           currentOutput.charAt(currentOutputIndex)) {
    417         accruedInputIndex++;
    418       }
    419       currentOutputIndex++;
    420     }
    421     return currentOutputIndex;
    422   }
    423 
    424   // Attempts to set the formatting template and returns a string which contains the formatted
    425   // version of the digits entered so far.
    426   private String attemptToChooseFormattingPattern() {
    427     // We start to attempt to format only when as least MIN_LEADING_DIGITS_LENGTH digits of national
    428     // number (excluding national prefix) have been entered.
    429     if (nationalNumber.length() >= MIN_LEADING_DIGITS_LENGTH) {
    430       getAvailableFormats(nationalNumber.substring(0, MIN_LEADING_DIGITS_LENGTH));
    431       return maybeCreateNewTemplate() ? inputAccruedNationalNumber() : accruedInput.toString();
    432     } else {
    433       return prefixBeforeNationalNumber + nationalNumber.toString();
    434     }
    435   }
    436 
    437   // Invokes inputDigitHelper on each digit of the national number accrued, and returns a formatted
    438   // string in the end.
    439   private String inputAccruedNationalNumber() {
    440     int lengthOfNationalNumber = nationalNumber.length();
    441     if (lengthOfNationalNumber > 0) {
    442       String tempNationalNumber = "";
    443       for (int i = 0; i < lengthOfNationalNumber; i++) {
    444         tempNationalNumber = inputDigitHelper(nationalNumber.charAt(i));
    445       }
    446       return ableToFormat
    447           ? prefixBeforeNationalNumber + tempNationalNumber
    448           : accruedInput.toString();
    449     } else {
    450       return prefixBeforeNationalNumber.toString();
    451     }
    452   }
    453 
    454   // Returns the national prefix extracted, or an empty string if it is not present.
    455   private String removeNationalPrefixFromNationalNumber() {
    456     int startOfNationalNumber = 0;
    457     if (currentMetaData.getCountryCode() == 1 && nationalNumber.charAt(0) == '1') {
    458       startOfNationalNumber = 1;
    459       prefixBeforeNationalNumber.append("1 ");
    460       isInternationalFormatting = true;
    461     } else if (currentMetaData.hasNationalPrefixForParsing()) {
    462       Pattern nationalPrefixForParsing =
    463         regexCache.getPatternForRegex(currentMetaData.getNationalPrefixForParsing());
    464       Matcher m = nationalPrefixForParsing.matcher(nationalNumber);
    465       if (m.lookingAt()) {
    466         // When the national prefix is detected, we use international formatting rules instead of
    467         // national ones, because national formatting rules could contain local formatting rules
    468         // for numbers entered without area code.
    469         isInternationalFormatting = true;
    470         startOfNationalNumber = m.end();
    471         prefixBeforeNationalNumber.append(nationalNumber.substring(0, startOfNationalNumber));
    472       }
    473     }
    474     String nationalPrefix = nationalNumber.substring(0, startOfNationalNumber);
    475     nationalNumber.delete(0, startOfNationalNumber);
    476     return nationalPrefix;
    477   }
    478 
    479   /**
    480    * Extracts IDD and plus sign to prefixBeforeNationalNumber when they are available, and places
    481    * the remaining input into nationalNumber.
    482    *
    483    * @return  true when accruedInputWithoutFormatting begins with the plus sign or valid IDD for
    484    *     defaultCountry.
    485    */
    486   private boolean attemptToExtractIdd() {
    487     Pattern internationalPrefix =
    488         regexCache.getPatternForRegex("\\" + PhoneNumberUtil.PLUS_SIGN + "|" +
    489             currentMetaData.getInternationalPrefix());
    490     Matcher iddMatcher = internationalPrefix.matcher(accruedInputWithoutFormatting);
    491     if (iddMatcher.lookingAt()) {
    492       isInternationalFormatting = true;
    493       int startOfCountryCallingCode = iddMatcher.end();
    494       nationalNumber.setLength(0);
    495       nationalNumber.append(accruedInputWithoutFormatting.substring(startOfCountryCallingCode));
    496       prefixBeforeNationalNumber.setLength(0);
    497       prefixBeforeNationalNumber.append(
    498           accruedInputWithoutFormatting.substring(0, startOfCountryCallingCode));
    499       if (accruedInputWithoutFormatting.charAt(0) != PhoneNumberUtil.PLUS_SIGN) {
    500         prefixBeforeNationalNumber.append(" ");
    501       }
    502       return true;
    503     }
    504     return false;
    505   }
    506 
    507   /**
    508    * Extracts the country calling code from the beginning of nationalNumber to
    509    * prefixBeforeNationalNumber when they are available, and places the remaining input into
    510    * nationalNumber.
    511    *
    512    * @return  true when a valid country calling code can be found.
    513    */
    514   private boolean attemptToExtractCountryCallingCode() {
    515     if (nationalNumber.length() == 0) {
    516       return false;
    517     }
    518     StringBuilder numberWithoutCountryCallingCode = new StringBuilder();
    519     int countryCode = phoneUtil.extractCountryCode(nationalNumber, numberWithoutCountryCallingCode);
    520     if (countryCode == 0) {
    521       return false;
    522     }
    523     nationalNumber.setLength(0);
    524     nationalNumber.append(numberWithoutCountryCallingCode);
    525     String newRegionCode = phoneUtil.getRegionCodeForCountryCode(countryCode);
    526     if (PhoneNumberUtil.REGION_CODE_FOR_NON_GEO_ENTITY.equals(newRegionCode)) {
    527       currentMetaData = phoneUtil.getMetadataForNonGeographicalRegion(countryCode);
    528     } else if (!newRegionCode.equals(defaultCountry)) {
    529       currentMetaData = getMetadataForRegion(newRegionCode);
    530     }
    531     String countryCodeString = Integer.toString(countryCode);
    532     prefixBeforeNationalNumber.append(countryCodeString).append(" ");
    533     return true;
    534   }
    535 
    536   // Accrues digits and the plus sign to accruedInputWithoutFormatting for later use. If nextChar
    537   // contains a digit in non-ASCII format (e.g. the full-width version of digits), it is first
    538   // normalized to the ASCII version. The return value is nextChar itself, or its normalized
    539   // version, if nextChar is a digit in non-ASCII format. This method assumes its input is either a
    540   // digit or the plus sign.
    541   private char normalizeAndAccrueDigitsAndPlusSign(char nextChar, boolean rememberPosition) {
    542     char normalizedChar;
    543     if (nextChar == PhoneNumberUtil.PLUS_SIGN) {
    544       normalizedChar = nextChar;
    545       accruedInputWithoutFormatting.append(nextChar);
    546     } else {
    547       int radix = 10;
    548       normalizedChar = Character.forDigit(Character.digit(nextChar, radix), radix);
    549       accruedInputWithoutFormatting.append(normalizedChar);
    550       nationalNumber.append(normalizedChar);
    551     }
    552     if (rememberPosition) {
    553       positionToRemember = accruedInputWithoutFormatting.length();
    554     }
    555     return normalizedChar;
    556   }
    557 
    558   private String inputDigitHelper(char nextChar) {
    559     Matcher digitMatcher = digitPattern.matcher(formattingTemplate);
    560     if (digitMatcher.find(lastMatchPosition)) {
    561       String tempTemplate = digitMatcher.replaceFirst(Character.toString(nextChar));
    562       formattingTemplate.replace(0, tempTemplate.length(), tempTemplate);
    563       lastMatchPosition = digitMatcher.start();
    564       return formattingTemplate.substring(0, lastMatchPosition + 1);
    565     } else {
    566       if (possibleFormats.size() == 1) {
    567         // More digits are entered than we could handle, and there are no other valid patterns to
    568         // try.
    569         ableToFormat = false;
    570       }  // else, we just reset the formatting pattern.
    571       currentFormattingPattern = "";
    572       return accruedInput.toString();
    573     }
    574   }
    575 }
    576