diff options
Diffstat (limited to 'java/src/com/android/i18n/addressinput/LookupKey.java')
-rw-r--r-- | java/src/com/android/i18n/addressinput/LookupKey.java | 694 |
1 files changed, 347 insertions, 347 deletions
diff --git a/java/src/com/android/i18n/addressinput/LookupKey.java b/java/src/com/android/i18n/addressinput/LookupKey.java index 35aad1d..aea9847 100644 --- a/java/src/com/android/i18n/addressinput/LookupKey.java +++ b/java/src/com/android/i18n/addressinput/LookupKey.java @@ -34,403 +34,403 @@ import java.util.Map; */ final class LookupKey { - /** - * Key types. Address Widget organizes address info based on key types. For example, if you want - * to know how to verify or format an US address, you need to use {@link KeyType#DATA} to get - * that info; if you want to get an example address, you use {@link KeyType#EXAMPLES} instead. - */ - enum KeyType { - - /** - * Key type for getting address data. - */ - DATA, - /** - * Key type for getting examples. - */ - EXAMPLES - } + /** + * Key types. Address Widget organizes address info based on key types. For example, if you want + * to know how to verify or format an US address, you need to use {@link KeyType#DATA} to get + * that info; if you want to get an example address, you use {@link KeyType#EXAMPLES} instead. + */ + enum KeyType { /** - * Script types. This is used for countries that do not use Latin script, but accept it for - * transcribing their addresses. For example, you can write a Japanese address in Latin script - * instead of Japanese: - * - * <p> 7-2, Marunouchi 2-Chome, Chiyoda-ku, Tokyo 100-8799 </p> - * - * Notice that {@link ScriptType} is based on country/region, not language. + * Key type for getting address data. */ - enum ScriptType { - - /** - * The script that uses Roman characters like ABC (as opposed to scripts like Cyrillic or - * Arabic). - */ - LATIN, - - /** - * Local scripts. For Japan, it's Japanese (including Hiragana, Katagana, and Kanji); For - * Saudi Arabia, it's Arabic. Notice that for US, the local script is actually Latin script - * (The same goes for other countries that use Latin script). For these countries, we do not - * provide two set of data (Latin and local) since they use only Latin script. You have to - * specify the {@link ScriptType} as local instead Latin. - */ - LOCAL - } - + DATA, /** - * The universal address hierarchy. Notice that sub-administrative area is neglected here since - * it is not required to fill out address form. + * Key type for getting examples. */ - private static final AddressField[] HIERARCHY = { - AddressField.COUNTRY, - AddressField.ADMIN_AREA, - AddressField.LOCALITY, - AddressField.DEPENDENT_LOCALITY}; - - private static final String SLASH_DELIM = "/"; - - private static final String DASH_DELIM = "--"; - - private static final String DEFAULT_LANGUAGE = "_default"; - - private final KeyType mKeyType; - - private final ScriptType mScriptType; - - // Values for hierarchy address fields. - private final Map<AddressField, String> mNodes; - - private final String mKeyString; - - private final String mLanguageCode; - - private LookupKey(Builder builder) { - this.mKeyType = builder.keyType; - this.mScriptType = builder.script; - this.mNodes = builder.nodes; - this.mLanguageCode = builder.languageCode; - this.mKeyString = getKeyString(); - } + EXAMPLES + } + + /** + * Script types. This is used for countries that do not use Latin script, but accept it for + * transcribing their addresses. For example, you can write a Japanese address in Latin script + * instead of Japanese: + * + * <p> 7-2, Marunouchi 2-Chome, Chiyoda-ku, Tokyo 100-8799 </p> + * + * Notice that {@link ScriptType} is based on country/region, not language. + */ + enum ScriptType { /** - * Gets lookup key for the input address field. This method does not allow key with key type of - * {@link KeyType#EXAMPLES}. - * - * @param field a field in the address hierarchy. - * @return key of the specified address field. If address field is not in the hierarchy, or is - * more granular than the current key has, returns null. For example, if your current - * key is "data/US" (down to country level), and you want to get the key for Locality - * (more granular than country), it will return null. + * The script that uses Roman characters like ABC (as opposed to scripts like Cyrillic or + * Arabic). */ - LookupKey getKeyForUpperLevelField(AddressField field) { - if (mKeyType != KeyType.DATA) { - // We only support getting the parent key for the data key type. - throw new RuntimeException("Only support getting parent keys for the data key type."); - } - Builder newKeyBuilder = new Builder(this); - - boolean removeNode = false; - boolean fieldInHierarchy = false; - for (AddressField hierarchyField : HIERARCHY) { - if (removeNode) { - if (newKeyBuilder.nodes.containsKey(hierarchyField)) { - newKeyBuilder.nodes.remove(hierarchyField); - } - } - if (hierarchyField == field) { - if (!newKeyBuilder.nodes.containsKey(hierarchyField)) { - return null; - } - removeNode = true; - fieldInHierarchy = true; - } - } - - if (!fieldInHierarchy) { - return null; - } - - newKeyBuilder.languageCode = mLanguageCode; - newKeyBuilder.script = mScriptType; - - return newKeyBuilder.build(); - } + LATIN, /** - * Returns the string value of a field in a key for a particular - * AddressField. For example, for the key "data/US/CA" and the address - * field AddressField.COUNTRY, "US" would be returned. Returns an empty - * string if the key does not have this field in it. + * Local scripts. For Japan, it's Japanese (including Hiragana, Katagana, and Kanji); For + * Saudi Arabia, it's Arabic. Notice that for US, the local script is actually Latin script + * (The same goes for other countries that use Latin script). For these countries, we do not + * provide two set of data (Latin and local) since they use only Latin script. You have to + * specify the {@link ScriptType} as local instead Latin. */ - String getValueForUpperLevelField(AddressField field) { - // First, get the key for this field. - LookupKey key = getKeyForUpperLevelField(field); - // Now we know the last value in the string is the value for this field. - if (key != null) { - String keyString = key.toString(); - int lastSlashPosition = keyString.lastIndexOf(SLASH_DELIM); - if (lastSlashPosition > 0 && lastSlashPosition != keyString.length()) { - return keyString.substring(lastSlashPosition + 1); - } - } - return ""; + LOCAL + } + + /** + * The universal address hierarchy. Notice that sub-administrative area is neglected here since + * it is not required to fill out address form. + */ + private static final AddressField[] HIERARCHY = { + AddressField.COUNTRY, + AddressField.ADMIN_AREA, + AddressField.LOCALITY, + AddressField.DEPENDENT_LOCALITY}; + + private static final String SLASH_DELIM = "/"; + + private static final String DASH_DELIM = "--"; + + private static final String DEFAULT_LANGUAGE = "_default"; + + private final KeyType keyType; + + private final ScriptType scriptType; + + // Values for hierarchy address fields. + private final Map<AddressField, String> nodes; + + private final String keyString; + + private final String languageCode; + + private LookupKey(Builder builder) { + this.keyType = builder.keyType; + this.scriptType = builder.script; + this.nodes = builder.nodes; + this.languageCode = builder.languageCode; + this.keyString = getKeyString(); + } + + /** + * Gets lookup key for the input address field. This method does not allow key with key type of + * {@link KeyType#EXAMPLES}. + * + * @param field a field in the address hierarchy. + * @return key of the specified address field. If address field is not in the hierarchy, or is + * more granular than the current key has, returns null. For example, if your current + * key is "data/US" (down to country level), and you want to get the key for Locality + * (more granular than country), it will return null. + */ + LookupKey getKeyForUpperLevelField(AddressField field) { + if (keyType != KeyType.DATA) { + // We only support getting the parent key for the data key type. + throw new RuntimeException("Only support getting parent keys for the data key type."); } - - /** - * Gets parent key for data key. For example, parent key for "data/US/CA" is "data/US". This - * method does not allow key with key type of {@link KeyType#EXAMPLES}. - */ - LookupKey getParentKey() { - if (mKeyType != KeyType.DATA) { - throw new RuntimeException("Only support getting parent keys for the data key type."); + Builder newKeyBuilder = new Builder(this); + + boolean removeNode = false; + boolean fieldInHierarchy = false; + for (AddressField hierarchyField : HIERARCHY) { + if (removeNode) { + if (newKeyBuilder.nodes.containsKey(hierarchyField)) { + newKeyBuilder.nodes.remove(hierarchyField); } - // Root key's parent should be null. - if (!mNodes.containsKey(AddressField.COUNTRY)) { - return null; + } + if (hierarchyField == field) { + if (!newKeyBuilder.nodes.containsKey(hierarchyField)) { + return null; } + removeNode = true; + fieldInHierarchy = true; + } + } - Builder parentKeyBuilder = new Builder(this); - AddressField mostGranularField = AddressField.COUNTRY; - - for (AddressField hierarchyField : HIERARCHY) { - if (!mNodes.containsKey(hierarchyField)) { - break; - } - mostGranularField = hierarchyField; - } - parentKeyBuilder.nodes.remove(mostGranularField); - return parentKeyBuilder.build(); + if (!fieldInHierarchy) { + return null; } - KeyType getKeyType() { - return mKeyType; + newKeyBuilder.languageCode = languageCode; + newKeyBuilder.script = scriptType; + + return newKeyBuilder.build(); + } + + /** + * Returns the string value of a field in a key for a particular + * AddressField. For example, for the key "data/US/CA" and the address + * field AddressField.COUNTRY, "US" would be returned. Returns an empty + * string if the key does not have this field in it. + */ + String getValueForUpperLevelField(AddressField field) { + // First, get the key for this field. + LookupKey key = getKeyForUpperLevelField(field); + // Now we know the last value in the string is the value for this field. + if (key != null) { + String keyString = key.toString(); + int lastSlashPosition = keyString.lastIndexOf(SLASH_DELIM); + if (lastSlashPosition > 0 && lastSlashPosition != keyString.length()) { + return keyString.substring(lastSlashPosition + 1); + } + } + return ""; + } + + /** + * Gets parent key for data key. For example, parent key for "data/US/CA" is "data/US". This + * method does not allow key with key type of {@link KeyType#EXAMPLES}. + */ + LookupKey getParentKey() { + if (keyType != KeyType.DATA) { + throw new RuntimeException("Only support getting parent keys for the data key type."); + } + // Root key's parent should be null. + if (!nodes.containsKey(AddressField.COUNTRY)) { + return null; } - /** - * Gets a key in string format. E.g., "data/US/CA". - */ - private String getKeyString() { - StringBuilder keyBuilder = new StringBuilder(mKeyType.name().toLowerCase()); - - if (mKeyType == KeyType.DATA) { - for (AddressField field : HIERARCHY) { - if (!mNodes.containsKey(field)) { - break; - } - if (field == AddressField.COUNTRY && mLanguageCode != null) { - keyBuilder.append(SLASH_DELIM) - .append(mNodes.get(field)).append(DASH_DELIM) - .append(mLanguageCode); - } else { - keyBuilder.append(SLASH_DELIM).append(mNodes.get(field)); - } - } + Builder parentKeyBuilder = new Builder(this); + AddressField mostGranularField = AddressField.COUNTRY; + + for (AddressField hierarchyField : HIERARCHY) { + if (!nodes.containsKey(hierarchyField)) { + break; + } + mostGranularField = hierarchyField; + } + parentKeyBuilder.nodes.remove(mostGranularField); + return parentKeyBuilder.build(); + } + + KeyType getKeyType() { + return keyType; + } + + /** + * Gets a key in string format. E.g., "data/US/CA". + */ + private String getKeyString() { + StringBuilder keyBuilder = new StringBuilder(keyType.name().toLowerCase()); + + if (keyType == KeyType.DATA) { + for (AddressField field : HIERARCHY) { + if (!nodes.containsKey(field)) { + break; + } + if (field == AddressField.COUNTRY && languageCode != null) { + keyBuilder.append(SLASH_DELIM) + .append(nodes.get(field)).append(DASH_DELIM) + .append(languageCode); } else { - if (mNodes.containsKey(AddressField.COUNTRY)) { - // Example key. E.g., "examples/TW/local/_default". - keyBuilder.append(SLASH_DELIM).append(mNodes.get(AddressField.COUNTRY)) - .append(SLASH_DELIM).append(mScriptType.name().toLowerCase()) - .append(SLASH_DELIM).append(DEFAULT_LANGUAGE); - } + keyBuilder.append(SLASH_DELIM).append(nodes.get(field)); } - - return keyBuilder.toString(); + } + } else { + if (nodes.containsKey(AddressField.COUNTRY)) { + // Example key. E.g., "examples/TW/local/_default". + keyBuilder.append(SLASH_DELIM).append(nodes.get(AddressField.COUNTRY)) + .append(SLASH_DELIM).append(scriptType.name().toLowerCase()) + .append(SLASH_DELIM).append(DEFAULT_LANGUAGE); + } } - /** - * Gets a lookup key as a plain text string., e.g., "data/US/CA". - */ - @Override - public String toString() { - return mKeyString; + return keyBuilder.toString(); + } + + /** + * Gets a lookup key as a plain text string., e.g., "data/US/CA". + */ + @Override + public String toString() { + return keyString; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if ((obj == null) || (obj.getClass() != this.getClass())) { + return false; } - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if ((obj == null) || (obj.getClass() != this.getClass())) { - return false; - } + return ((LookupKey) obj).toString().equals(keyString); + } - return ((LookupKey) obj).toString().equals(mKeyString); - } + @Override + public int hashCode() { + return keyString.hashCode(); + } - @Override - public int hashCode() { - return mKeyString.hashCode(); + static boolean hasValidKeyPrefix(String key) { + for (KeyType type : KeyType.values()) { + if (key.startsWith(type.name().toLowerCase())) { + return true; + } } + return false; + } - static boolean hasValidKeyPrefix(String key) { - for (KeyType type : KeyType.values()) { - if (key.startsWith(type.name().toLowerCase())) { - return true; - } - } - return false; - } + /** + * Builds lookup keys. + */ + static class Builder { - /** - * Builds lookup keys. - */ - static class Builder { + private KeyType keyType; - private KeyType keyType; + // Default to LOCAL script. - // Default to LOCAL script. + private ScriptType script = ScriptType.LOCAL; - private ScriptType script = ScriptType.LOCAL; + private Map<AddressField, String> nodes = new EnumMap<AddressField, String>( + AddressField.class); - private Map<AddressField, String> nodes = new EnumMap<AddressField, String>( - AddressField.class); + private String languageCode; - private String languageCode; + /** + * Creates a new builder for the specified key type. keyType cannot be null. + */ + Builder(KeyType keyType) { + this.keyType = keyType; + } - /** - * Creates a new builder for the specified key type. keyType cannot be null. - */ - Builder(KeyType keyType) { - this.keyType = keyType; + /** + * Creates a new builder for the specified key. oldKey cannot be null. + */ + Builder(LookupKey oldKey) { + this.keyType = oldKey.keyType; + this.script = oldKey.scriptType; + this.languageCode = oldKey.languageCode; + for (AddressField field : HIERARCHY) { + if (!oldKey.nodes.containsKey(field)) { + break; } + this.nodes.put(field, oldKey.nodes.get(field)); + } + } - /** - * Creates a new builder for the specified key. oldKey cannot be null. - */ - Builder(LookupKey oldKey) { - this.keyType = oldKey.mKeyType; - this.script = oldKey.mScriptType; - this.languageCode = oldKey.mLanguageCode; - for (AddressField field : HIERARCHY) { - if (!oldKey.mNodes.containsKey(field)) { - break; - } - this.nodes.put(field, oldKey.mNodes.get(field)); + /** + * Builds the {@link LookupKey} with the input key string. Input string has to represent + * either a {@link KeyType#DATA} key or a {@link KeyType#EXAMPLES} key. Also, key hierarchy + * deeper than {@link AddressField#DEPENDENT_LOCALITY} is not allowed. Notice that if any + * node in the hierarchy is empty, all the descendant nodes' values will be neglected. For + * example, input string "data/US//Mt View" will become "data/US". + * + * @param keyString e.g., "data/US/CA" + */ + Builder(String keyString) { + String[] parts = keyString.split(SLASH_DELIM); + // Check some pre-conditions. + if (!parts[0].equals(KeyType.DATA.name().toLowerCase()) && + !parts[0].equals(KeyType.EXAMPLES.name().toLowerCase())) { + throw new RuntimeException("Wrong key type: " + parts[0]); + } + if (parts.length > HIERARCHY.length + 1) { + throw new RuntimeException( + "input key '" + keyString + "' deeper than supported hierarchy"); + } + if (parts[0].equals("data")) { + keyType = KeyType.DATA; + + // Parses country and language info. + if (parts.length > 1) { + String substr = Util.trimToNull(parts[1]); + if (substr.contains(DASH_DELIM)) { + String[] s = substr.split(DASH_DELIM); + if (s.length != 2) { + throw new RuntimeException( + "Wrong format: Substring should be country " + + "code--language code"); } + substr = s[0]; + languageCode = s[1]; + } + this.nodes.put(HIERARCHY[0], substr); } - /** - * Builds the {@link LookupKey} with the input key string. Input string has to represent - * either a {@link KeyType#DATA} key or a {@link KeyType#EXAMPLES} key. Also, key hierarchy - * deeper than {@link AddressField#DEPENDENT_LOCALITY} is not allowed. Notice that if any - * node in the hierarchy is empty, all the descendant nodes' values will be neglected. For - * example, input string "data/US//Mt View" will become "data/US". - * - * @param keyString e.g., "data/US/CA" - */ - Builder(String keyString) { - String[] parts = keyString.split(SLASH_DELIM); - // Check some pre-conditions. - if (!parts[0].equals(KeyType.DATA.name().toLowerCase()) && - !parts[0].equals(KeyType.EXAMPLES.name().toLowerCase())) { - throw new RuntimeException("Wrong key type: " + parts[0]); - } - if (parts.length > HIERARCHY.length + 1) { - throw new RuntimeException( - "input key '" + keyString + "' deeper than supported hierarchy"); - } - if (parts[0].equals("data")) { - keyType = KeyType.DATA; - - // Parses country and language info. - if (parts.length > 1) { - String substr = Util.trimToNull(parts[1]); - if (substr.contains(DASH_DELIM)) { - String[] s = substr.split(DASH_DELIM); - if (s.length != 2) { - throw new RuntimeException( - "Wrong format: Substring should be country " - + "code--language code"); - } - substr = s[0]; - languageCode = s[1]; - } - this.nodes.put(HIERARCHY[0], substr); - } - - // Parses sub-country info. - if (parts.length > 2) { - for (int i = 2; i < parts.length; ++i) { - String substr = Util.trimToNull(parts[i]); - if (substr == null) { - break; - } - this.nodes.put(HIERARCHY[i - 1], substr); - } - } - } else if (parts[0].equals("examples")) { - keyType = KeyType.EXAMPLES; - - // Parses country info. - if (parts.length > 1) { - this.nodes.put(AddressField.COUNTRY, parts[1]); - } - - // Parses script types. - if (parts.length > 2) { - String scriptStr = parts[2]; - if (scriptStr.equals("local")) { - this.script = ScriptType.LOCAL; - } else if (scriptStr.equals("latin")) { - this.script = ScriptType.LATIN; - } else { - throw new RuntimeException("Script type has to be either latin or local."); - } - } - - // Parses language code. Example: "zh_Hant" in - // "examples/TW/local/zH_Hant". - if (parts.length > 3 && !parts[3].equals(DEFAULT_LANGUAGE)) { - languageCode = parts[3]; - } + // Parses sub-country info. + if (parts.length > 2) { + for (int i = 2; i < parts.length; ++i) { + String substr = Util.trimToNull(parts[i]); + if (substr == null) { + break; } + this.nodes.put(HIERARCHY[i - 1], substr); + } } + } else if (parts[0].equals("examples")) { + keyType = KeyType.EXAMPLES; - Builder setLanguageCode(String languageCode) { - this.languageCode = languageCode; - return this; + // Parses country info. + if (parts.length > 1) { + this.nodes.put(AddressField.COUNTRY, parts[1]); } - /** - * Sets key using {@link AddressData}. Notice that if any node in the hierarchy is empty, - * all the descendant nodes' values will be neglected. For example, the following address - * misses {@link AddressField#ADMIN_AREA}, thus its data key will be "data/US". - * - * <p> country: US<br> administrative area: null<br> locality: Mt. View </p> - */ - Builder setAddressData(AddressData data) { - languageCode = data.getLanguageCode(); - if (languageCode != null) { - if (Util.isExplicitLatinScript(languageCode)) { - script = ScriptType.LATIN; - } - } - - if (data.getPostalCountry() == null) { - return this; - } - this.nodes.put(AddressField.COUNTRY, data.getPostalCountry()); + // Parses script types. + if (parts.length > 2) { + String scriptStr = parts[2]; + if (scriptStr.equals("local")) { + this.script = ScriptType.LOCAL; + } else if (scriptStr.equals("latin")) { + this.script = ScriptType.LATIN; + } else { + throw new RuntimeException("Script type has to be either latin or local."); + } + } - if (data.getAdministrativeArea() == null) { - return this; - } - this.nodes.put(AddressField.ADMIN_AREA, data.getAdministrativeArea()); + // Parses language code. Example: "zh_Hant" in + // "examples/TW/local/zH_Hant". + if (parts.length > 3 && !parts[3].equals(DEFAULT_LANGUAGE)) { + languageCode = parts[3]; + } + } + } - if (data.getLocality() == null) { - return this; - } - this.nodes.put(AddressField.LOCALITY, data.getLocality()); + Builder setLanguageCode(String languageCode) { + this.languageCode = languageCode; + return this; + } - if (data.getDependentLocality() == null) { - return this; - } - this.nodes.put(AddressField.DEPENDENT_LOCALITY, data.getDependentLocality()); - return this; + /** + * Sets key using {@link AddressData}. Notice that if any node in the hierarchy is empty, + * all the descendant nodes' values will be neglected. For example, the following address + * misses {@link AddressField#ADMIN_AREA}, thus its data key will be "data/US". + * + * <p> country: US<br> administrative area: null<br> locality: Mt. View </p> + */ + Builder setAddressData(AddressData data) { + languageCode = data.getLanguageCode(); + if (languageCode != null) { + if (Util.isExplicitLatinScript(languageCode)) { + script = ScriptType.LATIN; } + } + + if (data.getPostalCountry() == null) { + return this; + } + this.nodes.put(AddressField.COUNTRY, data.getPostalCountry()); + + if (data.getAdministrativeArea() == null) { + return this; + } + this.nodes.put(AddressField.ADMIN_AREA, data.getAdministrativeArea()); + + if (data.getLocality() == null) { + return this; + } + this.nodes.put(AddressField.LOCALITY, data.getLocality()); + + if (data.getDependentLocality() == null) { + return this; + } + this.nodes.put(AddressField.DEPENDENT_LOCALITY, data.getDependentLocality()); + return this; + } - LookupKey build() { - return new LookupKey(this); - } + LookupKey build() { + return new LookupKey(this); } + } } |