19b19e1202dec7ddb9c43d9459c901da291030d2flararennie@google.com/* 29b19e1202dec7ddb9c43d9459c901da291030d2flararennie@google.com * Copyright (C) 2010 Google Inc. 39b19e1202dec7ddb9c43d9459c901da291030d2flararennie@google.com * 49b19e1202dec7ddb9c43d9459c901da291030d2flararennie@google.com * Licensed under the Apache License, Version 2.0 (the "License"); 59b19e1202dec7ddb9c43d9459c901da291030d2flararennie@google.com * you may not use this file except in compliance with the License. 69b19e1202dec7ddb9c43d9459c901da291030d2flararennie@google.com * You may obtain a copy of the License at 79b19e1202dec7ddb9c43d9459c901da291030d2flararennie@google.com * 89b19e1202dec7ddb9c43d9459c901da291030d2flararennie@google.com * http://www.apache.org/licenses/LICENSE-2.0 99b19e1202dec7ddb9c43d9459c901da291030d2flararennie@google.com * 109b19e1202dec7ddb9c43d9459c901da291030d2flararennie@google.com * Unless required by applicable law or agreed to in writing, software 119b19e1202dec7ddb9c43d9459c901da291030d2flararennie@google.com * distributed under the License is distributed on an "AS IS" BASIS, 129b19e1202dec7ddb9c43d9459c901da291030d2flararennie@google.com * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 139b19e1202dec7ddb9c43d9459c901da291030d2flararennie@google.com * See the License for the specific language governing permissions and 149b19e1202dec7ddb9c43d9459c901da291030d2flararennie@google.com * limitations under the License. 159b19e1202dec7ddb9c43d9459c901da291030d2flararennie@google.com */ 169b19e1202dec7ddb9c43d9459c901da291030d2flararennie@google.com 179b19e1202dec7ddb9c43d9459c901da291030d2flararennie@google.compackage com.android.i18n.addressinput; 189b19e1202dec7ddb9c43d9459c901da291030d2flararennie@google.com 199b19e1202dec7ddb9c43d9459c901da291030d2flararennie@google.comimport java.util.EnumMap; 209b19e1202dec7ddb9c43d9459c901da291030d2flararennie@google.comimport java.util.Map; 219b19e1202dec7ddb9c43d9459c901da291030d2flararennie@google.com 229b19e1202dec7ddb9c43d9459c901da291030d2flararennie@google.com/** 232c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com * A builder for creating keys that are used to lookup data in the local cache and fetch data from 242c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com * the server. There are two key types: {@code KeyType#DATA} or {@code KeyType#EXAMPLES}. 259b19e1202dec7ddb9c43d9459c901da291030d2flararennie@google.com * 262c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com * <p> The {@code KeyType#DATA} key is built based on a universal Address hierarchy, which is:<br> 279b19e1202dec7ddb9c43d9459c901da291030d2flararennie@google.com * 282c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com * {@code AddressField#Country} -> {@code AddressField#ADMIN_AREA} -> {@code AddressField#Locality} 292c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com * -> {@code AddressField#DEPENDENT_LOCALITY} </p> 309b19e1202dec7ddb9c43d9459c901da291030d2flararennie@google.com * 312c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com * <p> The {@code KeyType#EXAMPLES} key is built with the following format:<br> 329b19e1202dec7ddb9c43d9459c901da291030d2flararennie@google.com * 332c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com * {@code AddressField#Country} -> {@code ScriptType} -> language. </p> 349b19e1202dec7ddb9c43d9459c901da291030d2flararennie@google.com */ 35dc4cdad9dd71a57be66262d1d6d46a09c0973818lararennie@google.comfinal class LookupKey { 369b19e1202dec7ddb9c43d9459c901da291030d2flararennie@google.com 379b19e1202dec7ddb9c43d9459c901da291030d2flararennie@google.com /** 382c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com * Key types. Address Widget organizes address info based on key types. For example, if you want 392c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com * to know how to verify or format an US address, you need to use {@link KeyType#DATA} to get 402c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com * that info; if you want to get an example address, you use {@link KeyType#EXAMPLES} instead. 419b19e1202dec7ddb9c43d9459c901da291030d2flararennie@google.com */ 42dc4cdad9dd71a57be66262d1d6d46a09c0973818lararennie@google.com enum KeyType { 432c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com 442c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com /** 452c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com * Key type for getting address data. 462c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com */ 472c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com DATA, 482c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com /** 492c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com * Key type for getting examples. 502c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com */ 512c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com EXAMPLES 522c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com } 539b19e1202dec7ddb9c43d9459c901da291030d2flararennie@google.com 549b19e1202dec7ddb9c43d9459c901da291030d2flararennie@google.com /** 552c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com * Script types. This is used for countries that do not use Latin script, but accept it for 562c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com * transcribing their addresses. For example, you can write a Japanese address in Latin script 572c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com * instead of Japanese: 582c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com * 592c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com * <p> 7-2, Marunouchi 2-Chome, Chiyoda-ku, Tokyo 100-8799 </p> 602c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com * 612c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com * Notice that {@link ScriptType} is based on country/region, not language. 629b19e1202dec7ddb9c43d9459c901da291030d2flararennie@google.com */ 63dc4cdad9dd71a57be66262d1d6d46a09c0973818lararennie@google.com enum ScriptType { 642c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com 652c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com /** 662c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com * The script that uses Roman characters like ABC (as opposed to scripts like Cyrillic or 672c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com * Arabic). 682c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com */ 692c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com LATIN, 702c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com 712c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com /** 722c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com * Local scripts. For Japan, it's Japanese (including Hiragana, Katagana, and Kanji); For 732c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com * Saudi Arabia, it's Arabic. Notice that for US, the local script is actually Latin script 742c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com * (The same goes for other countries that use Latin script). For these countries, we do not 752c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com * provide two set of data (Latin and local) since they use only Latin script. You have to 762c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com * specify the {@link ScriptType} as local instead Latin. 772c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com */ 782c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com LOCAL 799b19e1202dec7ddb9c43d9459c901da291030d2flararennie@google.com } 809b19e1202dec7ddb9c43d9459c901da291030d2flararennie@google.com 812c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com /** 822c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com * The universal address hierarchy. Notice that sub-administrative area is neglected here since 832c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com * it is not required to fill out address form. 842c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com */ 850dbcfb4fae3e125550c534191627574ea69ec3aflararennie@google.com private static final AddressField[] HIERARCHY = { 862c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com AddressField.COUNTRY, 872c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com AddressField.ADMIN_AREA, 882c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com AddressField.LOCALITY, 892c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com AddressField.DEPENDENT_LOCALITY}; 909b19e1202dec7ddb9c43d9459c901da291030d2flararennie@google.com 910dbcfb4fae3e125550c534191627574ea69ec3aflararennie@google.com private static final String SLASH_DELIM = "/"; 929b19e1202dec7ddb9c43d9459c901da291030d2flararennie@google.com 930dbcfb4fae3e125550c534191627574ea69ec3aflararennie@google.com private static final String DASH_DELIM = "--"; 949b19e1202dec7ddb9c43d9459c901da291030d2flararennie@google.com 950dbcfb4fae3e125550c534191627574ea69ec3aflararennie@google.com private static final String DEFAULT_LANGUAGE = "_default"; 962c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com 9737ea1c8bb9bf0ee18a9ce7412ace03885098e348lararennie@google.com private final KeyType mKeyType; 982c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com 9937ea1c8bb9bf0ee18a9ce7412ace03885098e348lararennie@google.com private final ScriptType mScriptType; 1002c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com 1012c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com // Values for hierarchy address fields. 10237ea1c8bb9bf0ee18a9ce7412ace03885098e348lararennie@google.com private final Map<AddressField, String> mNodes; 1032c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com 10437ea1c8bb9bf0ee18a9ce7412ace03885098e348lararennie@google.com private final String mKeyString; 1059b19e1202dec7ddb9c43d9459c901da291030d2flararennie@google.com 10637ea1c8bb9bf0ee18a9ce7412ace03885098e348lararennie@google.com private final String mLanguageCode; 1072c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com 1082c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com private LookupKey(Builder builder) { 10937ea1c8bb9bf0ee18a9ce7412ace03885098e348lararennie@google.com this.mKeyType = builder.keyType; 11037ea1c8bb9bf0ee18a9ce7412ace03885098e348lararennie@google.com this.mScriptType = builder.script; 11137ea1c8bb9bf0ee18a9ce7412ace03885098e348lararennie@google.com this.mNodes = builder.nodes; 11237ea1c8bb9bf0ee18a9ce7412ace03885098e348lararennie@google.com this.mLanguageCode = builder.languageCode; 11337ea1c8bb9bf0ee18a9ce7412ace03885098e348lararennie@google.com this.mKeyString = getKeyString(); 1149b19e1202dec7ddb9c43d9459c901da291030d2flararennie@google.com } 1152c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com 1162c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com /** 1172c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com * Gets lookup key for the input address field. This method does not allow key with key type of 1182c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com * {@link KeyType#EXAMPLES}. 1192c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com * 1202c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com * @param field a field in the address hierarchy. 1212c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com * @return key of the specified address field. If address field is not in the hierarchy, or is 1222c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com * more granular than the current key has, returns null. For example, if your current 123d07313666e6455c4b63f965ac6a3697f7a9573e5lararennie@google.com * key is "data/US" (down to country level), and you want to get the key for Locality 1242c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com * (more granular than country), it will return null. 1252c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com */ 126dc4cdad9dd71a57be66262d1d6d46a09c0973818lararennie@google.com LookupKey getKeyForUpperLevelField(AddressField field) { 12737ea1c8bb9bf0ee18a9ce7412ace03885098e348lararennie@google.com if (mKeyType != KeyType.DATA) { 1282c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com // We only support getting the parent key for the data key type. 1292c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com throw new RuntimeException("Only support getting parent keys for the data key type."); 1309b19e1202dec7ddb9c43d9459c901da291030d2flararennie@google.com } 1312c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com Builder newKeyBuilder = new Builder(this); 1322c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com 1332c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com boolean removeNode = false; 1342c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com boolean fieldInHierarchy = false; 1350dbcfb4fae3e125550c534191627574ea69ec3aflararennie@google.com for (AddressField hierarchyField : HIERARCHY) { 1362c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com if (removeNode) { 1372c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com if (newKeyBuilder.nodes.containsKey(hierarchyField)) { 1382c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com newKeyBuilder.nodes.remove(hierarchyField); 1392c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com } 1402c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com } 1412c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com if (hierarchyField == field) { 1422c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com if (!newKeyBuilder.nodes.containsKey(hierarchyField)) { 1432c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com return null; 1442c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com } 1452c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com removeNode = true; 1462c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com fieldInHierarchy = true; 1472c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com } 1489b19e1202dec7ddb9c43d9459c901da291030d2flararennie@google.com } 1499b19e1202dec7ddb9c43d9459c901da291030d2flararennie@google.com 1502c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com if (!fieldInHierarchy) { 1512c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com return null; 1522c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com } 1539b19e1202dec7ddb9c43d9459c901da291030d2flararennie@google.com 15437ea1c8bb9bf0ee18a9ce7412ace03885098e348lararennie@google.com newKeyBuilder.languageCode = mLanguageCode; 15537ea1c8bb9bf0ee18a9ce7412ace03885098e348lararennie@google.com newKeyBuilder.script = mScriptType; 1569b19e1202dec7ddb9c43d9459c901da291030d2flararennie@google.com 1572c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com return newKeyBuilder.build(); 1589b19e1202dec7ddb9c43d9459c901da291030d2flararennie@google.com } 1599b19e1202dec7ddb9c43d9459c901da291030d2flararennie@google.com 1602c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com /** 161d07313666e6455c4b63f965ac6a3697f7a9573e5lararennie@google.com * Returns the string value of a field in a key for a particular 162d07313666e6455c4b63f965ac6a3697f7a9573e5lararennie@google.com * AddressField. For example, for the key "data/US/CA" and the address 163d07313666e6455c4b63f965ac6a3697f7a9573e5lararennie@google.com * field AddressField.COUNTRY, "US" would be returned. Returns an empty 164d07313666e6455c4b63f965ac6a3697f7a9573e5lararennie@google.com * string if the key does not have this field in it. 165d07313666e6455c4b63f965ac6a3697f7a9573e5lararennie@google.com */ 166d07313666e6455c4b63f965ac6a3697f7a9573e5lararennie@google.com String getValueForUpperLevelField(AddressField field) { 167d07313666e6455c4b63f965ac6a3697f7a9573e5lararennie@google.com // First, get the key for this field. 168d07313666e6455c4b63f965ac6a3697f7a9573e5lararennie@google.com LookupKey key = getKeyForUpperLevelField(field); 169d07313666e6455c4b63f965ac6a3697f7a9573e5lararennie@google.com // Now we know the last value in the string is the value for this field. 170d07313666e6455c4b63f965ac6a3697f7a9573e5lararennie@google.com if (key != null) { 171d07313666e6455c4b63f965ac6a3697f7a9573e5lararennie@google.com String keyString = key.toString(); 172d07313666e6455c4b63f965ac6a3697f7a9573e5lararennie@google.com int lastSlashPosition = keyString.lastIndexOf(SLASH_DELIM); 173d07313666e6455c4b63f965ac6a3697f7a9573e5lararennie@google.com if (lastSlashPosition > 0 && lastSlashPosition != keyString.length()) { 174d07313666e6455c4b63f965ac6a3697f7a9573e5lararennie@google.com return keyString.substring(lastSlashPosition + 1); 175d07313666e6455c4b63f965ac6a3697f7a9573e5lararennie@google.com } 176d07313666e6455c4b63f965ac6a3697f7a9573e5lararennie@google.com } 177d07313666e6455c4b63f965ac6a3697f7a9573e5lararennie@google.com return ""; 178d07313666e6455c4b63f965ac6a3697f7a9573e5lararennie@google.com } 179d07313666e6455c4b63f965ac6a3697f7a9573e5lararennie@google.com 180d07313666e6455c4b63f965ac6a3697f7a9573e5lararennie@google.com /** 1812c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com * Gets parent key for data key. For example, parent key for "data/US/CA" is "data/US". This 1822c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com * method does not allow key with key type of {@link KeyType#EXAMPLES}. 1832c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com */ 184dc4cdad9dd71a57be66262d1d6d46a09c0973818lararennie@google.com LookupKey getParentKey() { 18537ea1c8bb9bf0ee18a9ce7412ace03885098e348lararennie@google.com if (mKeyType != KeyType.DATA) { 1862c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com throw new RuntimeException("Only support getting parent keys for the data key type."); 1872c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com } 1882c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com // Root key's parent should be null. 18937ea1c8bb9bf0ee18a9ce7412ace03885098e348lararennie@google.com if (!mNodes.containsKey(AddressField.COUNTRY)) { 1902c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com return null; 1912c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com } 1929b19e1202dec7ddb9c43d9459c901da291030d2flararennie@google.com 1932c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com Builder parentKeyBuilder = new Builder(this); 1942c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com AddressField mostGranularField = AddressField.COUNTRY; 1959b19e1202dec7ddb9c43d9459c901da291030d2flararennie@google.com 1960dbcfb4fae3e125550c534191627574ea69ec3aflararennie@google.com for (AddressField hierarchyField : HIERARCHY) { 19737ea1c8bb9bf0ee18a9ce7412ace03885098e348lararennie@google.com if (!mNodes.containsKey(hierarchyField)) { 1982c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com break; 1992c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com } 2002c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com mostGranularField = hierarchyField; 2012c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com } 2022c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com parentKeyBuilder.nodes.remove(mostGranularField); 2032c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com return parentKeyBuilder.build(); 2042c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com } 2054846244b97f572c866738a8eef50e530cd73257ashaopengjia@google.com 206dc4cdad9dd71a57be66262d1d6d46a09c0973818lararennie@google.com KeyType getKeyType() { 20737ea1c8bb9bf0ee18a9ce7412ace03885098e348lararennie@google.com return mKeyType; 2082c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com } 2099b19e1202dec7ddb9c43d9459c901da291030d2flararennie@google.com 2109b19e1202dec7ddb9c43d9459c901da291030d2flararennie@google.com /** 2112c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com * Gets a key in string format. E.g., "data/US/CA". 2129b19e1202dec7ddb9c43d9459c901da291030d2flararennie@google.com */ 2132c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com private String getKeyString() { 21437ea1c8bb9bf0ee18a9ce7412ace03885098e348lararennie@google.com StringBuilder keyBuilder = new StringBuilder(mKeyType.name().toLowerCase()); 2152c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com 21637ea1c8bb9bf0ee18a9ce7412ace03885098e348lararennie@google.com if (mKeyType == KeyType.DATA) { 2170dbcfb4fae3e125550c534191627574ea69ec3aflararennie@google.com for (AddressField field : HIERARCHY) { 21837ea1c8bb9bf0ee18a9ce7412ace03885098e348lararennie@google.com if (!mNodes.containsKey(field)) { 2192c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com break; 2202c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com } 22137ea1c8bb9bf0ee18a9ce7412ace03885098e348lararennie@google.com if (field == AddressField.COUNTRY && mLanguageCode != null) { 2220dbcfb4fae3e125550c534191627574ea69ec3aflararennie@google.com keyBuilder.append(SLASH_DELIM) 2230dbcfb4fae3e125550c534191627574ea69ec3aflararennie@google.com .append(mNodes.get(field)).append(DASH_DELIM) 22437ea1c8bb9bf0ee18a9ce7412ace03885098e348lararennie@google.com .append(mLanguageCode); 2252c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com } else { 2260dbcfb4fae3e125550c534191627574ea69ec3aflararennie@google.com keyBuilder.append(SLASH_DELIM).append(mNodes.get(field)); 2272c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com } 2282c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com } 2292c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com } else { 23037ea1c8bb9bf0ee18a9ce7412ace03885098e348lararennie@google.com if (mNodes.containsKey(AddressField.COUNTRY)) { 2312c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com // Example key. E.g., "examples/TW/local/_default". 2320dbcfb4fae3e125550c534191627574ea69ec3aflararennie@google.com keyBuilder.append(SLASH_DELIM).append(mNodes.get(AddressField.COUNTRY)) 2330dbcfb4fae3e125550c534191627574ea69ec3aflararennie@google.com .append(SLASH_DELIM).append(mScriptType.name().toLowerCase()) 2340dbcfb4fae3e125550c534191627574ea69ec3aflararennie@google.com .append(SLASH_DELIM).append(DEFAULT_LANGUAGE); 2352c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com } 2362c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com } 2372c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com 2382c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com return keyBuilder.toString(); 2399b19e1202dec7ddb9c43d9459c901da291030d2flararennie@google.com } 2409b19e1202dec7ddb9c43d9459c901da291030d2flararennie@google.com 2419b19e1202dec7ddb9c43d9459c901da291030d2flararennie@google.com /** 2422c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com * Gets a lookup key as a plain text string., e.g., "data/US/CA". 2439b19e1202dec7ddb9c43d9459c901da291030d2flararennie@google.com */ 2441e17a681ee8e5566384ead1588f6e6c4c8aa333aroubert@google.com @Override 2452c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com public String toString() { 24637ea1c8bb9bf0ee18a9ce7412ace03885098e348lararennie@google.com return mKeyString; 2472c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com } 2482c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com 2491e17a681ee8e5566384ead1588f6e6c4c8aa333aroubert@google.com @Override 2502c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com public boolean equals(Object obj) { 2512c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com if (this == obj) { 2522c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com return true; 2532c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com } 2542c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com if ((obj == null) || (obj.getClass() != this.getClass())) { 2552c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com return false; 2569b19e1202dec7ddb9c43d9459c901da291030d2flararennie@google.com } 2572c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com 25837ea1c8bb9bf0ee18a9ce7412ace03885098e348lararennie@google.com return ((LookupKey) obj).toString().equals(mKeyString); 2592c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com } 2602c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com 2611e17a681ee8e5566384ead1588f6e6c4c8aa333aroubert@google.com @Override 2622c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com public int hashCode() { 26337ea1c8bb9bf0ee18a9ce7412ace03885098e348lararennie@google.com return mKeyString.hashCode(); 2649b19e1202dec7ddb9c43d9459c901da291030d2flararennie@google.com } 2659b19e1202dec7ddb9c43d9459c901da291030d2flararennie@google.com 266dc4cdad9dd71a57be66262d1d6d46a09c0973818lararennie@google.com static boolean hasValidKeyPrefix(String key) { 267f3a3b6c5a1dce4d0e718146724ecfa1070900dablararennie@google.com for (KeyType type : KeyType.values()) { 268f3a3b6c5a1dce4d0e718146724ecfa1070900dablararennie@google.com if (key.startsWith(type.name().toLowerCase())) { 269f3a3b6c5a1dce4d0e718146724ecfa1070900dablararennie@google.com return true; 270f3a3b6c5a1dce4d0e718146724ecfa1070900dablararennie@google.com } 271f3a3b6c5a1dce4d0e718146724ecfa1070900dablararennie@google.com } 272f3a3b6c5a1dce4d0e718146724ecfa1070900dablararennie@google.com return false; 273f3a3b6c5a1dce4d0e718146724ecfa1070900dablararennie@google.com } 274dc4cdad9dd71a57be66262d1d6d46a09c0973818lararennie@google.com 2759b19e1202dec7ddb9c43d9459c901da291030d2flararennie@google.com /** 2762c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com * Builds lookup keys. 2779b19e1202dec7ddb9c43d9459c901da291030d2flararennie@google.com */ 278dc4cdad9dd71a57be66262d1d6d46a09c0973818lararennie@google.com static class Builder { 2792c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com 2802c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com private KeyType keyType; 2812c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com 2822c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com // Default to LOCAL script. 2832c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com 2842c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com private ScriptType script = ScriptType.LOCAL; 2852c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com 2862c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com private Map<AddressField, String> nodes = new EnumMap<AddressField, String>( 2872c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com AddressField.class); 2882c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com 2892c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com private String languageCode; 2902c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com 2912c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com /** 2922c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com * Creates a new builder for the specified key type. keyType cannot be null. 2932c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com */ 294dc4cdad9dd71a57be66262d1d6d46a09c0973818lararennie@google.com Builder(KeyType keyType) { 2952c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com this.keyType = keyType; 2969b19e1202dec7ddb9c43d9459c901da291030d2flararennie@google.com } 2979b19e1202dec7ddb9c43d9459c901da291030d2flararennie@google.com 2982c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com /** 2992c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com * Creates a new builder for the specified key. oldKey cannot be null. 3002c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com */ 301dc4cdad9dd71a57be66262d1d6d46a09c0973818lararennie@google.com Builder(LookupKey oldKey) { 30237ea1c8bb9bf0ee18a9ce7412ace03885098e348lararennie@google.com this.keyType = oldKey.mKeyType; 30337ea1c8bb9bf0ee18a9ce7412ace03885098e348lararennie@google.com this.script = oldKey.mScriptType; 30437ea1c8bb9bf0ee18a9ce7412ace03885098e348lararennie@google.com this.languageCode = oldKey.mLanguageCode; 3050dbcfb4fae3e125550c534191627574ea69ec3aflararennie@google.com for (AddressField field : HIERARCHY) { 30637ea1c8bb9bf0ee18a9ce7412ace03885098e348lararennie@google.com if (!oldKey.mNodes.containsKey(field)) { 3072c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com break; 3082c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com } 30937ea1c8bb9bf0ee18a9ce7412ace03885098e348lararennie@google.com this.nodes.put(field, oldKey.mNodes.get(field)); 3109b19e1202dec7ddb9c43d9459c901da291030d2flararennie@google.com } 3119b19e1202dec7ddb9c43d9459c901da291030d2flararennie@google.com } 3129b19e1202dec7ddb9c43d9459c901da291030d2flararennie@google.com 3132c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com /** 3142c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com * Builds the {@link LookupKey} with the input key string. Input string has to represent 3152c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com * either a {@link KeyType#DATA} key or a {@link KeyType#EXAMPLES} key. Also, key hierarchy 3162c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com * deeper than {@link AddressField#DEPENDENT_LOCALITY} is not allowed. Notice that if any 3172c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com * node in the hierarchy is empty, all the descendant nodes' values will be neglected. For 3182c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com * example, input string "data/US//Mt View" will become "data/US". 3192c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com * 3202c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com * @param keyString e.g., "data/US/CA" 3212c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com */ 322dc4cdad9dd71a57be66262d1d6d46a09c0973818lararennie@google.com Builder(String keyString) { 3230dbcfb4fae3e125550c534191627574ea69ec3aflararennie@google.com String[] parts = keyString.split(SLASH_DELIM); 3242c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com // Check some pre-conditions. 3252c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com if (!parts[0].equals(KeyType.DATA.name().toLowerCase()) && 3262c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com !parts[0].equals(KeyType.EXAMPLES.name().toLowerCase())) { 3272c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com throw new RuntimeException("Wrong key type: " + parts[0]); 3282c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com } 3290dbcfb4fae3e125550c534191627574ea69ec3aflararennie@google.com if (parts.length > HIERARCHY.length + 1) { 3302c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com throw new RuntimeException( 3312c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com "input key '" + keyString + "' deeper than supported hierarchy"); 3322c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com } 3332c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com if (parts[0].equals("data")) { 3342c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com keyType = KeyType.DATA; 3352c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com 3362c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com // Parses country and language info. 3372c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com if (parts.length > 1) { 3382c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com String substr = Util.trimToNull(parts[1]); 3390dbcfb4fae3e125550c534191627574ea69ec3aflararennie@google.com if (substr.contains(DASH_DELIM)) { 3400dbcfb4fae3e125550c534191627574ea69ec3aflararennie@google.com String[] s = substr.split(DASH_DELIM); 3412c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com if (s.length != 2) { 3422c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com throw new RuntimeException( 3432c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com "Wrong format: Substring should be country " 3442c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com + "code--language code"); 3452c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com } 3462c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com substr = s[0]; 3472c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com languageCode = s[1]; 3482c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com } 3490dbcfb4fae3e125550c534191627574ea69ec3aflararennie@google.com this.nodes.put(HIERARCHY[0], substr); 3502c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com } 3512c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com 3522c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com // Parses sub-country info. 3532c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com if (parts.length > 2) { 3542c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com for (int i = 2; i < parts.length; ++i) { 3552c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com String substr = Util.trimToNull(parts[i]); 3562c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com if (substr == null) { 3572c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com break; 3582c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com } 3590dbcfb4fae3e125550c534191627574ea69ec3aflararennie@google.com this.nodes.put(HIERARCHY[i - 1], substr); 3602c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com } 3612c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com } 3622c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com } else if (parts[0].equals("examples")) { 3632c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com keyType = KeyType.EXAMPLES; 3642c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com 3652c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com // Parses country info. 3662c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com if (parts.length > 1) { 3672c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com this.nodes.put(AddressField.COUNTRY, parts[1]); 3682c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com } 3692c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com 3702c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com // Parses script types. 3712c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com if (parts.length > 2) { 3722c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com String scriptStr = parts[2]; 3732c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com if (scriptStr.equals("local")) { 3742c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com this.script = ScriptType.LOCAL; 3752c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com } else if (scriptStr.equals("latin")) { 3762c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com this.script = ScriptType.LATIN; 3772c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com } else { 3782c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com throw new RuntimeException("Script type has to be either latin or local."); 3792c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com } 3802c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com } 3812c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com 3822c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com // Parses language code. Example: "zh_Hant" in 3832c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com // "examples/TW/local/zH_Hant". 3840dbcfb4fae3e125550c534191627574ea69ec3aflararennie@google.com if (parts.length > 3 && !parts[3].equals(DEFAULT_LANGUAGE)) { 3852c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com languageCode = parts[3]; 3862c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com } 3872c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com } 3889b19e1202dec7ddb9c43d9459c901da291030d2flararennie@google.com } 3899b19e1202dec7ddb9c43d9459c901da291030d2flararennie@google.com 390dc4cdad9dd71a57be66262d1d6d46a09c0973818lararennie@google.com Builder setLanguageCode(String languageCode) { 3912c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com this.languageCode = languageCode; 3922c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com return this; 3939b19e1202dec7ddb9c43d9459c901da291030d2flararennie@google.com } 3949b19e1202dec7ddb9c43d9459c901da291030d2flararennie@google.com 3952c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com /** 3962c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com * Sets key using {@link AddressData}. Notice that if any node in the hierarchy is empty, 3972c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com * all the descendant nodes' values will be neglected. For example, the following address 3982c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com * misses {@link AddressField#ADMIN_AREA}, thus its data key will be "data/US". 3992c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com * 4002c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com * <p> country: US<br> administrative area: null<br> locality: Mt. View </p> 4012c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com */ 402dc4cdad9dd71a57be66262d1d6d46a09c0973818lararennie@google.com Builder setAddressData(AddressData data) { 4032c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com languageCode = data.getLanguageCode(); 4042c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com if (languageCode != null) { 4052c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com if (Util.isExplicitLatinScript(languageCode)) { 4062c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com script = ScriptType.LATIN; 4072c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com } 4082c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com } 4099b19e1202dec7ddb9c43d9459c901da291030d2flararennie@google.com 4102c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com if (data.getPostalCountry() == null) { 4112c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com return this; 4122c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com } 4132c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com this.nodes.put(AddressField.COUNTRY, data.getPostalCountry()); 4149b19e1202dec7ddb9c43d9459c901da291030d2flararennie@google.com 4152c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com if (data.getAdministrativeArea() == null) { 4162c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com return this; 4172c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com } 4182c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com this.nodes.put(AddressField.ADMIN_AREA, data.getAdministrativeArea()); 4192c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com 4202c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com if (data.getLocality() == null) { 4212c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com return this; 4222c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com } 4232c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com this.nodes.put(AddressField.LOCALITY, data.getLocality()); 4242c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com 4252c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com if (data.getDependentLocality() == null) { 4262c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com return this; 4272c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com } 4282c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com this.nodes.put(AddressField.DEPENDENT_LOCALITY, data.getDependentLocality()); 4292c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com return this; 4309b19e1202dec7ddb9c43d9459c901da291030d2flararennie@google.com } 4319b19e1202dec7ddb9c43d9459c901da291030d2flararennie@google.com 432dc4cdad9dd71a57be66262d1d6d46a09c0973818lararennie@google.com LookupKey build() { 4332c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com return new LookupKey(this); 4342c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com } 4359b19e1202dec7ddb9c43d9459c901da291030d2flararennie@google.com } 4369b19e1202dec7ddb9c43d9459c901da291030d2flararennie@google.com} 437