AsYouTypeFormatter.java revision 0b3c1fb05c01bc853ad927356eee743b62a8121b
11524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia/*
21524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * Copyright (C) 2009 Google Inc.
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
171524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jiapackage com.google.i18n.phonenumbers;
181524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia
191524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jiaimport com.google.i18n.phonenumbers.Phonemetadata.NumberFormat;
207900ea273b8c33b3c6f70d7dd559127938d0fc3dShaopeng Jiaimport com.google.i18n.phonenumbers.Phonemetadata.PhoneMetadata;
211524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia
221524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jiaimport java.util.ArrayList;
231524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jiaimport java.util.List;
241524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jiaimport java.util.regex.Matcher;
251524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jiaimport java.util.regex.Pattern;
261524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia
271524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia/**
281524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * A formatter which formats phone numbers as they are entered.
291524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia *
301524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * An AsYouTypeFormatter could be created by invoking the getAsYouTypeFormatter method of the
311524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * PhoneNumberUtil. After that digits could be added by invoking the inputDigit method on the
321524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * formatter instance, and the partially formatted phone number will be returned each time a digit
331524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * is added. The clear method could be invoked before a new number needs to be formatted.
341524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia *
351524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * See testAsYouTypeFormatterUS(), testAsYouTestFormatterGB() and testAsYouTypeFormatterDE() in
361524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * PhoneNumberUtilTest.java for more details on how the formatter is to be used.
371524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia *
381524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia * @author Shaopeng Jia
391524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia */
401524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jiapublic class AsYouTypeFormatter {
411524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia  private StringBuffer currentOutput;
421524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia  private String formattingTemplate;
431524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia  private StringBuffer accruedInput;
441524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia  private StringBuffer accruedInputWithoutFormatting;
457900ea273b8c33b3c6f70d7dd559127938d0fc3dShaopeng Jia  private boolean ableToFormat = true;
467900ea273b8c33b3c6f70d7dd559127938d0fc3dShaopeng Jia  private boolean isInternationalFormatting = false;
471524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia  private final PhoneNumberUtil phoneUtil = PhoneNumberUtil.getInstance();
481524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia  private String defaultCountry;
497900ea273b8c33b3c6f70d7dd559127938d0fc3dShaopeng Jia  private Phonemetadata.PhoneMetadata defaultMetaData;
501524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia  private PhoneMetadata currentMetaData;
511524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia
521524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia  // The digits that have not been entered yet will be represented by a \u2008, the punctuation
531524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia  // space.
541524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia  private String digitPlaceholder = "\u2008";
551524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia  private Pattern digitPattern = Pattern.compile(digitPlaceholder);
561524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia  private int lastMatchPosition = 0;
570b3c1fb05c01bc853ad927356eee743b62a8121bShaopeng Jia  private boolean rememberPosition = false;
580b3c1fb05c01bc853ad927356eee743b62a8121bShaopeng Jia  private int positionRemembered = 0;
590b3c1fb05c01bc853ad927356eee743b62a8121bShaopeng Jia  private int originalPosition = 0;
601524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia  private Pattern nationalPrefixForParsing;
611524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia  private Pattern internationalPrefix;
621524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia  private StringBuffer prefixBeforeNationalNumber;
631524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia  private StringBuffer nationalNumber;
640b3c1fb05c01bc853ad927356eee743b62a8121bShaopeng Jia  // No formatting will be applied when any of the character in the following character class is
650b3c1fb05c01bc853ad927356eee743b62a8121bShaopeng Jia  // entered by users.
660b3c1fb05c01bc853ad927356eee743b62a8121bShaopeng Jia  private final Pattern UNSUPPORTED_SYNTAX = Pattern.compile("[- *#;,.()/a-zA-Z]");
670199c997f87434f2c5a7d1df4bb4b5f904312b9fShaopeng Jia  private final Pattern CHARACTER_CLASS_PATTERN = Pattern.compile("\\[([^\\[\\]])*\\]");
680199c997f87434f2c5a7d1df4bb4b5f904312b9fShaopeng Jia  private final Pattern STANDALONE_DIGIT_PATTERN = Pattern.compile("\\d(?=[^,}][^,}])");
691524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia
701524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia  /**
711524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia   * Constructs a light-weight formatter which does no formatting, but outputs exactly what is
721524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia   * fed into the inputDigit method.
731524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia   *
741524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia   * @param regionCode  the country/region where the phone number is being entered
751524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia   */
761524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia  AsYouTypeFormatter(String regionCode) {
771524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia    accruedInput = new StringBuffer();
781524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia    accruedInputWithoutFormatting = new StringBuffer();
791524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia    currentOutput = new StringBuffer();
801524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia    prefixBeforeNationalNumber = new StringBuffer();
811524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia    nationalNumber = new StringBuffer();
821524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia    defaultCountry = regionCode;
831524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia    initializeCountrySpecificInfo(defaultCountry);
841524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia    defaultMetaData = currentMetaData;
851524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia  }
861524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia
871524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia  private void initializeCountrySpecificInfo(String regionCode) {
881524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia    currentMetaData = phoneUtil.getMetadataForRegion(regionCode);
891524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia    nationalPrefixForParsing =
901524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia        Pattern.compile(currentMetaData.getNationalPrefixForParsing());
911524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia    internationalPrefix =
921524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia        Pattern.compile("\\+|" + currentMetaData.getInternationalPrefix());
931524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia  }
941524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia
951524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia  private void chooseFormatAndCreateTemplate(String leadingFourDigitsOfNationalNumber) {
961524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia    List<NumberFormat> formatList = getAvailableFormats(leadingFourDigitsOfNationalNumber);
971524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia    if (formatList.size() < 1) {
981524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia      ableToFormat = false;
991524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia    } else {
1001524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia      // When there are multiple available formats, the formatter uses the first format.
1011524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia      NumberFormat format = formatList.get(0);
1021524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia      if (!createFormattingTemplate(format)) {
1031524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia        ableToFormat = false;
1041524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia      } else {
1051524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia        currentOutput = new StringBuffer(formattingTemplate);
1061524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia      }
1071524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia    }
1081524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia  }
1091524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia
1101524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia  private List<NumberFormat> getAvailableFormats(String leadingFourDigits) {
1111524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia    List<NumberFormat> matchedList = new ArrayList<NumberFormat>();
1127900ea273b8c33b3c6f70d7dd559127938d0fc3dShaopeng Jia    List<NumberFormat> formatList =
1137900ea273b8c33b3c6f70d7dd559127938d0fc3dShaopeng Jia        (isInternationalFormatting && currentMetaData.getIntlNumberFormatCount() > 0)
1147900ea273b8c33b3c6f70d7dd559127938d0fc3dShaopeng Jia        ? currentMetaData.getIntlNumberFormatList()
1157900ea273b8c33b3c6f70d7dd559127938d0fc3dShaopeng Jia        : currentMetaData.getNumberFormatList();
1161524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia    for (NumberFormat format : formatList) {
1171524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia      if (format.hasLeadingDigits()) {
1181524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia        Pattern leadingDigitsPattern = Pattern.compile(format.getLeadingDigits());
1191524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia        Matcher m = leadingDigitsPattern.matcher(leadingFourDigits);
1201524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia        if (m.lookingAt()) {
1211524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia          matchedList.add(format);
1221524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia        }
1231524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia      } else {
1241524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia        matchedList.add(format);
1251524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia      }
1261524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia    }
1271524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia    return matchedList;
1281524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia  }
1291524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia
1301524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia  private boolean createFormattingTemplate(NumberFormat format) {
1311524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia    String numberFormat = format.getFormat();
1321524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia    String numberPattern = format.getPattern();
1331524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia
1340199c997f87434f2c5a7d1df4bb4b5f904312b9fShaopeng Jia    // The formatter doesn't format numbers when numberPattern contains "|", e.g.
1350199c997f87434f2c5a7d1df4bb4b5f904312b9fShaopeng Jia    // (20|3)\d{4}. In those cases we quickly return.
1360199c997f87434f2c5a7d1df4bb4b5f904312b9fShaopeng Jia    if (numberPattern.indexOf('|') != -1) {
1371524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia      return false;
1381524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia    }
1391524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia
1401524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia    // Replace anything in the form of [..] with \d
1410199c997f87434f2c5a7d1df4bb4b5f904312b9fShaopeng Jia    numberPattern = CHARACTER_CLASS_PATTERN.matcher(numberPattern).replaceAll("\\\\d");
1421524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia
1431524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia    // Replace any standalone digit (not the one in d{}) with \d
1440199c997f87434f2c5a7d1df4bb4b5f904312b9fShaopeng Jia    numberPattern = STANDALONE_DIGIT_PATTERN.matcher(numberPattern).replaceAll("\\\\d");
1451524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia
1461524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia    formattingTemplate = getFormattingTemplate(numberPattern, numberFormat);
1471524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia    return true;
1481524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia  }
1491524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia
1501524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia  // Gets a formatting template which could be used to efficiently format a partial number where
1511524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia  // digits are added one by one.
1521524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia  private String getFormattingTemplate(String numberPattern, String numberFormat) {
1531524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia    // Creates a phone number consisting only of the digit 9 that matches the
1541524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia    // numberPattern by applying the pattern to the longestPhoneNumber string.
1551524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia    String longestPhoneNumber = "999999999999999";
1561524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia    Matcher m = Pattern.compile(numberPattern).matcher(longestPhoneNumber);
1571524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia    m.find();  // this will always succeed
1581524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia    String aPhoneNumber = m.group();
1591524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia    // Formats the number according to numberFormat
1601524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia    String template = aPhoneNumber.replaceAll(numberPattern, numberFormat);
1611524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia    // Replaces each digit with character digitPlaceholder
1621524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia    template = template.replaceAll("9", digitPlaceholder);
1631524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia    return template;
1641524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia  }
1651524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia
1661524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia  /**
1671524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia   * Clears the internal state of the formatter, so it could be reused.
1681524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia   */
1691524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia  public void clear() {
1700199c997f87434f2c5a7d1df4bb4b5f904312b9fShaopeng Jia    accruedInput.setLength(0);
1710199c997f87434f2c5a7d1df4bb4b5f904312b9fShaopeng Jia    accruedInputWithoutFormatting.setLength(0);
1720199c997f87434f2c5a7d1df4bb4b5f904312b9fShaopeng Jia    currentOutput.setLength(0);
1731524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia    lastMatchPosition = 0;
1740199c997f87434f2c5a7d1df4bb4b5f904312b9fShaopeng Jia    prefixBeforeNationalNumber.setLength(0);
1750199c997f87434f2c5a7d1df4bb4b5f904312b9fShaopeng Jia    nationalNumber.setLength(0);
1761524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia    ableToFormat = true;
1770b3c1fb05c01bc853ad927356eee743b62a8121bShaopeng Jia    positionRemembered = 0;
1780b3c1fb05c01bc853ad927356eee743b62a8121bShaopeng Jia    originalPosition = 0;
1797900ea273b8c33b3c6f70d7dd559127938d0fc3dShaopeng Jia    isInternationalFormatting = false;
1801524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia    if (!currentMetaData.equals(defaultMetaData)) {
1811524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia      initializeCountrySpecificInfo(defaultCountry);
1821524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia    }
1831524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia  }
1841524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia
1851524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia  /**
1861524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia   * Formats a phone number on-the-fly as each digit is entered.
1871524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia   *
1881524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia   * @param nextChar  the most recently entered digit of a phone number. Formatting characters are
1891524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia   *     allowed, but they are removed from the result. Full width digits and Arabic-indic digits
1901524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia   *     are allowed, and will be shown as they are.
1910199c997f87434f2c5a7d1df4bb4b5f904312b9fShaopeng Jia   * @return  the partially formatted phone number.
1921524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia   */
1931524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia  public String inputDigit(char nextChar) {
1941524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia    accruedInput.append(nextChar);
1950b3c1fb05c01bc853ad927356eee743b62a8121bShaopeng Jia    rememberPosition();
1960199c997f87434f2c5a7d1df4bb4b5f904312b9fShaopeng Jia    if (UNSUPPORTED_SYNTAX.matcher(Character.toString(nextChar)).matches()) {
1971524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia      ableToFormat = false;
1981524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia    }
1991524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia    if (!ableToFormat) {
2000b3c1fb05c01bc853ad927356eee743b62a8121bShaopeng Jia      if (positionRemembered > 0 && currentOutput.length() > 0) {
2010b3c1fb05c01bc853ad927356eee743b62a8121bShaopeng Jia        positionRemembered = originalPosition;
2020b3c1fb05c01bc853ad927356eee743b62a8121bShaopeng Jia        currentOutput.setLength(0);
2030b3c1fb05c01bc853ad927356eee743b62a8121bShaopeng Jia      }
2041524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia      return accruedInput.toString();
2051524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia    }
2061524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia
2071524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia    nextChar = normalizeAndAccrueDigitsAndPlusSign(nextChar);
2081524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia
2091524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia    // We start to attempt to format only when at least 6 digits (the plus sign is counted as a
2101524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia    // digit as well for this purpose) have been entered.
2111524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia    switch (accruedInputWithoutFormatting.length()) {
2121524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia      case 0: // this is the case where the first few inputs are neither digits nor the plus sign.
2131524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia      case 1:
2141524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia      case 2:
2151524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia      case 3:
2161524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia      case 4:
2171524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia      case 5:
2181524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia        return accruedInput.toString();
2191524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia      case 6:
2201524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia        if (!extractIddAndValidCountryCode()) {
2211524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia          ableToFormat = false;
2221524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia          return accruedInput.toString();
2231524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia        }
2241524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia        removeNationalPrefixFromNationalNumber();
2251524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia        return attemptToChooseFormattingPattern();
2261524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia      default:
2271524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia        if (nationalNumber.length() > 4) {  // The formatting pattern is already chosen.
2280b3c1fb05c01bc853ad927356eee743b62a8121bShaopeng Jia          String temp = inputDigitHelper(nextChar);
2290b3c1fb05c01bc853ad927356eee743b62a8121bShaopeng Jia          return ableToFormat
2300b3c1fb05c01bc853ad927356eee743b62a8121bShaopeng Jia              ? prefixBeforeNationalNumber + temp
2310b3c1fb05c01bc853ad927356eee743b62a8121bShaopeng Jia              : temp;
2321524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia        } else {
2331524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia          return attemptToChooseFormattingPattern();
2341524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia        }
2351524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia    }
2361524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia  }
2371524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia
2380b3c1fb05c01bc853ad927356eee743b62a8121bShaopeng Jia  private void rememberPosition() {
2390b3c1fb05c01bc853ad927356eee743b62a8121bShaopeng Jia    if (rememberPosition) {
2400b3c1fb05c01bc853ad927356eee743b62a8121bShaopeng Jia      positionRemembered = accruedInput.length();
2410b3c1fb05c01bc853ad927356eee743b62a8121bShaopeng Jia      originalPosition = positionRemembered;
2420b3c1fb05c01bc853ad927356eee743b62a8121bShaopeng Jia    }
2430b3c1fb05c01bc853ad927356eee743b62a8121bShaopeng Jia  }
2440b3c1fb05c01bc853ad927356eee743b62a8121bShaopeng Jia
2450b3c1fb05c01bc853ad927356eee743b62a8121bShaopeng Jia  /**
2460b3c1fb05c01bc853ad927356eee743b62a8121bShaopeng Jia   * Same as inputDigit, but remembers the position where nextChar is inserted, so that it could be
2470b3c1fb05c01bc853ad927356eee743b62a8121bShaopeng Jia   * retrieved later by using getRememberedPosition(). The remembered position will be automatically
2480b3c1fb05c01bc853ad927356eee743b62a8121bShaopeng Jia   * adjusted if additional formatting characters are later inserted/removed in front of nextChar.
2490b3c1fb05c01bc853ad927356eee743b62a8121bShaopeng Jia   */
2500b3c1fb05c01bc853ad927356eee743b62a8121bShaopeng Jia  public String inputDigitAndRememberPosition(char nextChar) {
2510b3c1fb05c01bc853ad927356eee743b62a8121bShaopeng Jia    rememberPosition = true;
2520b3c1fb05c01bc853ad927356eee743b62a8121bShaopeng Jia    String result = inputDigit(nextChar);
2530b3c1fb05c01bc853ad927356eee743b62a8121bShaopeng Jia    rememberPosition = false;
2540b3c1fb05c01bc853ad927356eee743b62a8121bShaopeng Jia    return result;
2550b3c1fb05c01bc853ad927356eee743b62a8121bShaopeng Jia  }
2560b3c1fb05c01bc853ad927356eee743b62a8121bShaopeng Jia
2570b3c1fb05c01bc853ad927356eee743b62a8121bShaopeng Jia  /**
2580b3c1fb05c01bc853ad927356eee743b62a8121bShaopeng Jia   * Returns the current position in the partially formatted phone number of the character which was
2590b3c1fb05c01bc853ad927356eee743b62a8121bShaopeng Jia   * previously passed in as the parameter of inputDigitAndRememberPosition().
2600b3c1fb05c01bc853ad927356eee743b62a8121bShaopeng Jia   */
2610b3c1fb05c01bc853ad927356eee743b62a8121bShaopeng Jia  public int getRememberedPosition() {
2620b3c1fb05c01bc853ad927356eee743b62a8121bShaopeng Jia    return positionRemembered;
2630b3c1fb05c01bc853ad927356eee743b62a8121bShaopeng Jia  }
2640b3c1fb05c01bc853ad927356eee743b62a8121bShaopeng Jia
2651524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia  // Attempts to set the formatting template and returns a string which contains the formatted
2661524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia  // version of the digits entered so far.
2671524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia  private String attemptToChooseFormattingPattern() {
2681524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia    // We start to attempt to format only when as least 4 digits of national number (excluding
2691524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia    // national prefix) have been entered.
2701524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia    if (nationalNumber.length() >= 4) {
2711524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia      chooseFormatAndCreateTemplate(nationalNumber.substring(0, 4));
2721524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia      return inputAccruedNationalNumber();
2731524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia    } else {
2740b3c1fb05c01bc853ad927356eee743b62a8121bShaopeng Jia      if (rememberPosition) {
2750b3c1fb05c01bc853ad927356eee743b62a8121bShaopeng Jia        positionRemembered = prefixBeforeNationalNumber.length() + nationalNumber.length();
2760b3c1fb05c01bc853ad927356eee743b62a8121bShaopeng Jia      }
2771524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia      return prefixBeforeNationalNumber + nationalNumber.toString();
2781524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia    }
2791524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia  }
2801524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia
2811524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia  // Invokes inputDigitHelper on each digit of the national number accrued, and returns a formatted
2821524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia  // string in the end.
2831524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia  private String inputAccruedNationalNumber() {
2841524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia    int lengthOfNationalNumber = nationalNumber.length();
2851524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia    if (lengthOfNationalNumber > 0) {
2860b3c1fb05c01bc853ad927356eee743b62a8121bShaopeng Jia      // The positionRemembered should be only adjusted once in the loop that follows.
2870b3c1fb05c01bc853ad927356eee743b62a8121bShaopeng Jia      Boolean positionAlreadyAdjusted = false;
2881524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia      for (int i = 0; i < lengthOfNationalNumber - 1; i++) {
2890b3c1fb05c01bc853ad927356eee743b62a8121bShaopeng Jia        String temp = inputDigitHelper(nationalNumber.charAt(i));
2900b3c1fb05c01bc853ad927356eee743b62a8121bShaopeng Jia        if (!positionAlreadyAdjusted &&
2910b3c1fb05c01bc853ad927356eee743b62a8121bShaopeng Jia            positionRemembered - prefixBeforeNationalNumber.length() == i + 1) {
2920b3c1fb05c01bc853ad927356eee743b62a8121bShaopeng Jia          positionRemembered = prefixBeforeNationalNumber.length() + temp.length();
2930b3c1fb05c01bc853ad927356eee743b62a8121bShaopeng Jia          positionAlreadyAdjusted = true;
2940b3c1fb05c01bc853ad927356eee743b62a8121bShaopeng Jia        }
2951524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia      }
2960b3c1fb05c01bc853ad927356eee743b62a8121bShaopeng Jia      String temp = inputDigitHelper(nationalNumber.charAt(lengthOfNationalNumber - 1));
2970b3c1fb05c01bc853ad927356eee743b62a8121bShaopeng Jia      return ableToFormat
2980b3c1fb05c01bc853ad927356eee743b62a8121bShaopeng Jia          ? prefixBeforeNationalNumber + temp
2990b3c1fb05c01bc853ad927356eee743b62a8121bShaopeng Jia          : temp;
3001524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia    } else {
3010b3c1fb05c01bc853ad927356eee743b62a8121bShaopeng Jia      if (rememberPosition) {
3020b3c1fb05c01bc853ad927356eee743b62a8121bShaopeng Jia        positionRemembered = prefixBeforeNationalNumber.length();
3030b3c1fb05c01bc853ad927356eee743b62a8121bShaopeng Jia      }
3041524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia      return prefixBeforeNationalNumber.toString();
3051524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia    }
3061524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia  }
3071524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia
3081524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia  private void removeNationalPrefixFromNationalNumber() {
3091524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia    int startOfNationalNumber = 0;
31094c2440dc41689b7d9c169edf5089eeebf7527d7Shaopeng Jia    if (currentMetaData.getCountryCode() == 1 && nationalNumber.charAt(0) == '1') {
31194c2440dc41689b7d9c169edf5089eeebf7527d7Shaopeng Jia      startOfNationalNumber = 1;
3120b3c1fb05c01bc853ad927356eee743b62a8121bShaopeng Jia      prefixBeforeNationalNumber.append("1");
3130b3c1fb05c01bc853ad927356eee743b62a8121bShaopeng Jia      // Since a space will be inserted after the national prefix in this case, we increase the
3140b3c1fb05c01bc853ad927356eee743b62a8121bShaopeng Jia      // remembered position by 1 for anything that is after the national prefix.
3150b3c1fb05c01bc853ad927356eee743b62a8121bShaopeng Jia      if (positionRemembered > prefixBeforeNationalNumber.length()) {
3160b3c1fb05c01bc853ad927356eee743b62a8121bShaopeng Jia        positionRemembered++;
3170b3c1fb05c01bc853ad927356eee743b62a8121bShaopeng Jia      }
3180b3c1fb05c01bc853ad927356eee743b62a8121bShaopeng Jia      prefixBeforeNationalNumber.append(" ");
31994c2440dc41689b7d9c169edf5089eeebf7527d7Shaopeng Jia    } else if (currentMetaData.hasNationalPrefix()) {
3201524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia      Matcher m = nationalPrefixForParsing.matcher(nationalNumber);
3211524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia      if (m.lookingAt()) {
3221524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia        startOfNationalNumber = m.end();
3231524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia        prefixBeforeNationalNumber.append(nationalNumber.substring(0, startOfNationalNumber));
3241524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia      }
3251524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia    }
3261524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia    nationalNumber.delete(0, startOfNationalNumber);
3271524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia  }
3281524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia
3291524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia  /**
3301524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia   * Extracts IDD, plus sign and country code to prefixBeforeNationalNumber when they are available,
3311524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia   * and places the remaining input into nationalNumber.
3321524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia   *
3331524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia   * @return  false when accruedInputWithoutFormatting begins with the plus sign or valid IDD for
3341524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia   *     defaultCountry, but the sequence of digits after that does not form a valid country code.
3351524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia   *     It returns true for all other cases.
3361524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia   */
3371524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia  private boolean extractIddAndValidCountryCode() {
3380199c997f87434f2c5a7d1df4bb4b5f904312b9fShaopeng Jia    nationalNumber.setLength(0);
3391524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia    Matcher iddMatcher = internationalPrefix.matcher(accruedInputWithoutFormatting);
3401524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia    if (iddMatcher.lookingAt()) {
3417900ea273b8c33b3c6f70d7dd559127938d0fc3dShaopeng Jia      isInternationalFormatting = true;
3421524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia      int startOfCountryCode = iddMatcher.end();
3431524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia      StringBuffer numberIncludeCountryCode =
3441524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia          new StringBuffer(accruedInputWithoutFormatting.substring(startOfCountryCode));
3451524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia      int countryCode = phoneUtil.extractCountryCode(numberIncludeCountryCode, nationalNumber);
3461524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia      if (countryCode == 0) {
3471524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia        return false;
3481524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia      } else {
3491524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia        String newRegionCode = phoneUtil.getRegionCodeForCountryCode(countryCode);
3501524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia        if (!newRegionCode.equals(defaultCountry)) {
3511524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia          initializeCountrySpecificInfo(newRegionCode);
3521524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia        }
3531524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia        prefixBeforeNationalNumber.append(
3541524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia            accruedInputWithoutFormatting.substring(0, startOfCountryCode));
3551524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia        if (accruedInputWithoutFormatting.charAt(0) != PhoneNumberUtil.PLUS_SIGN ) {
3560b3c1fb05c01bc853ad927356eee743b62a8121bShaopeng Jia          if (positionRemembered > prefixBeforeNationalNumber.length()) {
3570b3c1fb05c01bc853ad927356eee743b62a8121bShaopeng Jia            // Since a space will be inserted in front of the country code in this case, we increase
3580b3c1fb05c01bc853ad927356eee743b62a8121bShaopeng Jia            // the remembered position by 1.
3590b3c1fb05c01bc853ad927356eee743b62a8121bShaopeng Jia            positionRemembered++;
3600b3c1fb05c01bc853ad927356eee743b62a8121bShaopeng Jia          }
3611524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia          prefixBeforeNationalNumber.append(" ");
3621524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia        }
3630b3c1fb05c01bc853ad927356eee743b62a8121bShaopeng Jia        String countryCodeString = Integer.toString(countryCode);
3640b3c1fb05c01bc853ad927356eee743b62a8121bShaopeng Jia        if (positionRemembered > prefixBeforeNationalNumber.length() + countryCodeString.length()) {
3650b3c1fb05c01bc853ad927356eee743b62a8121bShaopeng Jia          // Since a space will be inserted after the country code in this case, we increase the
3660b3c1fb05c01bc853ad927356eee743b62a8121bShaopeng Jia          // remembered position by 1.
3670b3c1fb05c01bc853ad927356eee743b62a8121bShaopeng Jia          positionRemembered++;
3680b3c1fb05c01bc853ad927356eee743b62a8121bShaopeng Jia        }
3690b3c1fb05c01bc853ad927356eee743b62a8121bShaopeng Jia        prefixBeforeNationalNumber.append(countryCodeString).append(" ");
3701524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia      }
3711524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia    } else {
3720199c997f87434f2c5a7d1df4bb4b5f904312b9fShaopeng Jia      nationalNumber.setLength(0);
3730199c997f87434f2c5a7d1df4bb4b5f904312b9fShaopeng Jia      nationalNumber.append(accruedInputWithoutFormatting);
3741524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia    }
3751524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia    return true;
3761524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia  }
3771524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia
3781524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia  // Accrues digits and the plus sign to accruedInputWithoutFormatting for later use. If nextChar
3791524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia  // contains a digit in non-ASCII format (e.g. the full-width version of digits), it is first
3801524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia  // normalized to the ASCII version. The return value is nextChar itself, or its normalized
3811524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia  // version, if nextChar is a digit in non-ASCII format.
3821524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia  private char normalizeAndAccrueDigitsAndPlusSign(char nextChar) {
3831524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia    if (nextChar == PhoneNumberUtil.PLUS_SIGN) {
3841524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia      accruedInputWithoutFormatting.append(nextChar);
3851524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia    }
3861524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia
3871524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia    if (PhoneNumberUtil.DIGIT_MAPPINGS.containsKey(nextChar)) {
3881524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia      nextChar = PhoneNumberUtil.DIGIT_MAPPINGS.get(nextChar);
3891524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia      accruedInputWithoutFormatting.append(nextChar);
3901524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia      nationalNumber.append(nextChar);
3911524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia    }
3921524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia    return nextChar;
3931524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia  }
3941524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia
3951524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia  private String inputDigitHelper(char nextChar) {
3961524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia    if (!PhoneNumberUtil.DIGIT_MAPPINGS.containsKey(nextChar)) {
3971524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia      return currentOutput.toString();
3981524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia    }
3991524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia
4001524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia    Matcher digitMatcher = digitPattern.matcher(currentOutput);
4011524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia    if (digitMatcher.find(lastMatchPosition)) {
4021524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia      currentOutput = new StringBuffer(digitMatcher.replaceFirst(Character.toString(nextChar)));
4031524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia      lastMatchPosition = digitMatcher.start();
4040b3c1fb05c01bc853ad927356eee743b62a8121bShaopeng Jia      if (rememberPosition) {
4050b3c1fb05c01bc853ad927356eee743b62a8121bShaopeng Jia        positionRemembered = prefixBeforeNationalNumber.length() + lastMatchPosition + 1;
4060b3c1fb05c01bc853ad927356eee743b62a8121bShaopeng Jia      }
4075803259dcdfb1a04cc353e9ef02c1a3aef6a6176Shaopeng Jia      return currentOutput.substring(0, lastMatchPosition + 1);
4081524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia    } else {  // More digits are entered than we could handle.
4091524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia      currentOutput.append(nextChar);
4101524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia      ableToFormat = false;
4110b3c1fb05c01bc853ad927356eee743b62a8121bShaopeng Jia      if (positionRemembered > 0) {
4120b3c1fb05c01bc853ad927356eee743b62a8121bShaopeng Jia        positionRemembered = originalPosition;
4130b3c1fb05c01bc853ad927356eee743b62a8121bShaopeng Jia        currentOutput.setLength(0);
4140b3c1fb05c01bc853ad927356eee743b62a8121bShaopeng Jia      }
4150b3c1fb05c01bc853ad927356eee743b62a8121bShaopeng Jia      return accruedInput.toString();
4161524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia    }
4171524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia  }
4181524ca8c53cd2c3adee0bb2e2b95a93fee976862Shaopeng Jia}
419