From 29761c802c0df839dfbfae7dd9c77f66278bab48 Mon Sep 17 00:00:00 2001 From: Lara Scheidegger Date: Wed, 22 Oct 2014 16:46:17 +0200 Subject: First version of code (tests error) --- .../com/android/i18n/addressinput/AddressData.java | 588 ++--- .../android/i18n/addressinput/AddressField.java | 100 +- .../i18n/addressinput/AddressProblemType.java | 82 +- .../android/i18n/addressinput/AddressProblems.java | 68 +- .../i18n/addressinput/AddressUiComponent.java | 222 +- .../i18n/addressinput/AddressVerificationData.java | 222 +- .../addressinput/AddressVerificationNodeData.java | 48 +- .../android/i18n/addressinput/AddressWidget.java | 1318 +++++----- .../AddressWidgetUiComponentProvider.java | 106 +- .../com/android/i18n/addressinput/CacheData.java | 688 +++--- .../i18n/addressinput/ClientCacheManager.java | 12 +- .../com/android/i18n/addressinput/ClientData.java | 450 ++-- .../i18n/addressinput/DataLoadListener.java | 6 +- .../com/android/i18n/addressinput/DataSource.java | 4 +- .../android/i18n/addressinput/FieldVerifier.java | 518 ++-- .../android/i18n/addressinput/FormController.java | 561 +++-- .../com/android/i18n/addressinput/FormOptions.java | 428 ++-- .../i18n/addressinput/FormatInterpreter.java | 500 ++-- java/src/com/android/i18n/addressinput/JsoMap.java | 438 ++-- .../i18n/addressinput/JsonpRequestBuilder.java | 174 +- .../com/android/i18n/addressinput/LookupKey.java | 694 +++--- .../i18n/addressinput/NotifyingListener.java | 48 +- .../com/android/i18n/addressinput/RegionData.java | 140 +- .../i18n/addressinput/RegionDataConstants.java | 2544 ++++++++++---------- .../addressinput/SimpleClientCacheManager.java | 26 +- .../i18n/addressinput/StandardAddressVerifier.java | 346 +-- .../android/i18n/addressinput/StandardChecks.java | 64 +- java/src/com/android/i18n/addressinput/Util.java | 348 +-- .../addressinput/testing/AddressDataMapLoader.java | 42 +- .../i18n/addressinput/testing/AsyncTestCase.java | 78 +- .../android/i18n/addressinput/AddressDataTest.java | 72 +- .../i18n/addressinput/AddressFieldTest.java | 12 +- .../i18n/addressinput/AddressProblemsTest.java | 22 +- .../addressinput/AddressVerificationDataTest.java | 144 +- .../AddressWidgetUiComponentProviderTest.java | 194 +- .../i18n/addressinput/AsyncTestCaseTest.java | 82 +- .../android/i18n/addressinput/CacheDataTest.java | 534 ++-- .../android/i18n/addressinput/ClientDataTest.java | 90 +- .../i18n/addressinput/FieldVerifierTest.java | 560 ++--- .../i18n/addressinput/FormControllerTest.java | 244 +- .../android/i18n/addressinput/FormOptionsTest.java | 34 +- .../i18n/addressinput/FormatInterpreterTest.java | 350 +-- .../com/android/i18n/addressinput/JsoMapTest.java | 376 +-- .../i18n/addressinput/JsonpRequestBuilderTest.java | 240 +- .../android/i18n/addressinput/LookupKeyTest.java | 386 +-- .../i18n/addressinput/RegionDataConstantsTest.java | 32 +- .../android/i18n/addressinput/RegionDataTest.java | 44 +- .../addressinput/StandardAddressVerifierTest.java | 462 ++-- .../com/android/i18n/addressinput/UtilTest.java | 230 +- 49 files changed, 7484 insertions(+), 7487 deletions(-) diff --git a/java/src/com/android/i18n/addressinput/AddressData.java b/java/src/com/android/i18n/addressinput/AddressData.java index fc039a2..7e53d10 100644 --- a/java/src/com/android/i18n/addressinput/AddressData.java +++ b/java/src/com/android/i18n/addressinput/AddressData.java @@ -54,341 +54,341 @@ import java.util.Map; * or a string consists of only spaces, it will not be set. */ public class AddressData { - // CLDR (Common Locale Data Repository) country code. - // For example, "US" for United States. - // (Note: Use "GB", not "UK", for Great Britain) - private final String mPostalCountry; - - // street street, line 1 - private final String mAddressLine1; - - // street street, line 2 - private final String mAddressLine2; - - // Top-level administrative subdivision of this country. - // Examples: US state, IT region, UK constituent nation, JP prefecture. - private final String mAdministrativeArea; - - // Locality. A fuzzy term, but it generally refers to - // the city/town portion of an address. In regions of the world where - // localities are not well defined or do not fit into this structure well - // (for example, Japan and China), leave locality empty and use - // addressLine1. - // Examples: US city, IT comune, UK post town. - private final String mLocality; - - // Dependent locality or sublocality. Used for UK dependent localities, - // or neighborhoods or boroughs in other locations. If trying to - // represent a UK double-dependent locality, include both the - // double-dependent locality and the dependent locality in this field, - // e.g. "Whaley, Langwith". - private final String mDependentLocality; - - // Postal Code. values are frequently alphanumeric. - // Examples: "94043", "94043-1351", "SW1W", "SW1W 9TQ". - private final String mPostalCode; - - // Sorting code - use is very country-specific. - // This corresponds to the SortingCode sub-element of the xAL - // PostalServiceElements element. - // Examples: FR CEDEX. - private final String mSortingCode; - - // The firm or organization. This goes at a finer granularity than - // address lines in the address. Omit if not needed. - private final String mOrganization; - - // The recipient. This goes at a finer granularity than address lines - // in the address. Not present in xAL. Omit if not needed. - private final String mRecipient; - - // Language code of the address. Can be set to null. See its getter and setter - // for more information. - private final String mLanguageCode; + // CLDR (Common Locale Data Repository) country code. + // For example, "US" for United States. + // (Note: Use "GB", not "UK", for Great Britain) + private final String postalCountry; + + // street street, line 1 + private final String addressLine1; + + // street street, line 2 + private final String addressLine2; + + // Top-level administrative subdivision of this country. + // Examples: US state, IT region, UK constituent nation, JP prefecture. + private final String administrativeArea; + + // Locality. A fuzzy term, but it generally refers to + // the city/town portion of an address. In regions of the world where + // localities are not well defined or do not fit into this structure well + // (for example, Japan and China), leave locality empty and use + // addressLine1. + // Examples: US city, IT comune, UK post town. + private final String locality; + + // Dependent locality or sublocality. Used for UK dependent localities, + // or neighborhoods or boroughs in other locations. If trying to + // represent a UK double-dependent locality, include both the + // double-dependent locality and the dependent locality in this field, + // e.g. "Whaley, Langwith". + private final String dependentLocality; + + // Postal Code. values are frequently alphanumeric. + // Examples: "94043", "94043-1351", "SW1W", "SW1W 9TQ". + private final String postalCode; + + // Sorting code - use is very country-specific. + // This corresponds to the SortingCode sub-element of the xAL + // PostalServiceElements element. + // Examples: FR CEDEX. + private final String sortingCode; + + // The firm or organization. This goes at a finer granularity than + // address lines in the address. Omit if not needed. + private final String organization; + + // The recipient. This goes at a finer granularity than address lines + // in the address. Not present in xAL. Omit if not needed. + private final String recipient; + + // Language code of the address. Can be set to null. See its getter and setter + // for more information. + private final String languageCode; + + /** + * Use {@link Builder} to create instances. + */ + private AddressData(Builder builder) { + postalCountry = builder.values.get(AddressField.COUNTRY); + administrativeArea = builder.values.get(AddressField.ADMIN_AREA); + locality = builder.values.get(AddressField.LOCALITY); + dependentLocality = builder.values.get(AddressField.DEPENDENT_LOCALITY); + postalCode = builder.values.get(AddressField.POSTAL_CODE); + sortingCode = builder.values.get(AddressField.SORTING_CODE); + organization = builder.values.get(AddressField.ORGANIZATION); + recipient = builder.values.get(AddressField.RECIPIENT); + addressLine1 = builder.values.get(AddressField.ADDRESS_LINE_1); + addressLine2 = builder.values.get(AddressField.ADDRESS_LINE_2); + languageCode = builder.language; + } + + /** + * Returns the postal country. + * + *

The returned value is not user-presentable. For example, {@code getPostalCountry()} may + * return {@code "GB"}, while addresses in Great Britain should be displayed using "UK". + */ + public String getPostalCountry() { + return postalCountry; + } + + public String getAddressLine1() { + return addressLine1; + } + + public String getAddressLine2() { + return addressLine2; + } + + /** + * Returns the top-level administrative subdivision of this country. Different postal countries + * use different names to refer to their administrative areas. For example, this is called + * "state" in the United States, "region" in Italy, "constituent nation" in Great Britain, or + * "prefecture" in Japan. + */ + public String getAdministrativeArea() { + return administrativeArea; + } + + /** + * Returns the locality. The usage of this field varies by region, but it generally refers to + * the "city" or "town" of the address. Some regions do not use this field; their address lines + * are sufficient to locate an address within a sub-administrative area. For example, this is + * called "city" in the United States, "comune" in Italy, or "post town" in Great Britain. + */ + public String getLocality() { + return locality; + } + + /** + * Returns the dependent locality. + * + *

This is used for Great Britain dependent localities, or neighborhoods or boroughs in other + * locations. + * + *

In cases such as Great Britain, this field may contain a double-dependent locality, such + * as "Whaley, Langwith". + */ + public String getDependentLocality() { + return dependentLocality; + } + + /** + * Returns the firm or organization. + */ + public String getOrganization() { + return organization; + } + + /** + * Returns the recipient. Examples: "Jesse Wilson" or "Jesse Wilson c/o Apurva Mathad". + */ + public String getRecipient() { + return recipient; + } + + /** + * Returns the country-specific postal code. Examples: "94043", "94043-1351", "SW1W", + * "SW1W 9TQ". + */ + public String getPostalCode() { + return postalCode; + } + + /** + * Returns the country-specific sorting code. For example, the + * French CEDEX + */ + public String getSortingCode() { + return sortingCode; + } + + public String getFieldValue(AddressField field) { + switch (field) { + case COUNTRY: + return postalCountry; + case ADMIN_AREA: + return administrativeArea; + case LOCALITY: + return locality; + case DEPENDENT_LOCALITY: + return dependentLocality; + case POSTAL_CODE: + return postalCode; + case SORTING_CODE: + return sortingCode; + case ADDRESS_LINE_1: + return addressLine1; + case ADDRESS_LINE_2: + return addressLine2; + case ORGANIZATION: + return organization; + case RECIPIENT: + return recipient; + default: + throw new IllegalArgumentException("unrecognized key: " + field); + } + } - /** - * Use {@link Builder} to create instances. - */ - private AddressData(Builder builder) { - mPostalCountry = builder.mValues.get(AddressField.COUNTRY); - mAdministrativeArea = builder.mValues.get(AddressField.ADMIN_AREA); - mLocality = builder.mValues.get(AddressField.LOCALITY); - mDependentLocality = builder.mValues.get(AddressField.DEPENDENT_LOCALITY); - mPostalCode = builder.mValues.get(AddressField.POSTAL_CODE); - mSortingCode = builder.mValues.get(AddressField.SORTING_CODE); - mOrganization = builder.mValues.get(AddressField.ORGANIZATION); - mRecipient = builder.mValues.get(AddressField.RECIPIENT); - mAddressLine1 = builder.mValues.get(AddressField.ADDRESS_LINE_1); - mAddressLine2 = builder.mValues.get(AddressField.ADDRESS_LINE_2); - mLanguageCode = builder.mLanguage; + /** + * Returns the language of the text of this address. Languages are used to guide how the address + * is formatted for + * display. The same address may have different {@link AddressData} representations in + * different languages. For example, the French name of "New Mexico" is "Nouveau-Mexique". + */ + public String getLanguageCode() { + return languageCode; + } + + /** + * Builder for AddressData + */ + public static class Builder { + + private final Map values; + + private String language = null; + + public Builder() { + values = new HashMap(); } /** - * Returns the postal country. - * - *

The returned value is not user-presentable. For example, {@code getPostalCountry()} may - * return {@code "GB"}, while addresses in Great Britain should be displayed using "UK". + * A constructor that sets address field with input data. Street fields will be normalized + * in the process. I.e., after copy, there will not be any empty street line in front of + * non-empty ones. For example, if input data's street line 1 is null but street line 2 + * has a value, this method will copy street line 2's value and set it to street line 1. */ - public String getPostalCountry() { - return mPostalCountry; + public Builder(AddressData addr) { + values = new HashMap(); + set(addr); } - public String getAddressLine1() { - return mAddressLine1; + public Builder setCountry(String value) { + return set(AddressField.COUNTRY, value); } - public String getAddressLine2() { - return mAddressLine2; + public Builder setAdminArea(String value) { + return set(AddressField.ADMIN_AREA, value); } - /** - * Returns the top-level administrative subdivision of this country. Different postal countries - * use different names to refer to their administrative areas. For example, this is called - * "state" in the United States, "region" in Italy, "constituent nation" in Great Britain, or - * "prefecture" in Japan. - */ - public String getAdministrativeArea() { - return mAdministrativeArea; + public Builder setLocality(String value) { + return set(AddressField.LOCALITY, value); + } + + public Builder setDependentLocality(String value) { + return set(AddressField.DEPENDENT_LOCALITY, value); + } + + public Builder setPostalCode(String value) { + return set(AddressField.POSTAL_CODE, value); + } + + public Builder setSortingCode(String value) { + return set(AddressField.SORTING_CODE, value); } /** - * Returns the locality. The usage of this field varies by region, but it generally refers to - * the "city" or "town" of the address. Some regions do not use this field; their address lines - * are sufficient to locate an address within a sub-administrative area. For example, this is - * called "city" in the United States, "comune" in Italy, or "post town" in Great Britain. + * Sets the language code. + * + * @param languageCode the language to use, or {@code null} for no specified language. */ - public String getLocality() { - return mLocality; + public Builder setLanguageCode(String languageCode) { + this.language = languageCode; + return this; } /** - * Returns the dependent locality. + * Sets address lines 1 and 2 (if necessary) from a string that may contain multiple lines. * - *

This is used for Great Britain dependent localities, or neighborhoods or boroughs in other - * locations. + *

Example: Input " \n \n1600 Amphitheatre Ave\n\nRoom 122" will set the following + * values:
line 1: 1600 Amphitheatre Ave
line 2: Room 122

* - *

In cases such as Great Britain, this field may contain a double-dependent locality, such - * as "Whaley, Langwith". + * @param value a street string */ - public String getDependentLocality() { - return mDependentLocality; + public Builder setAddress(String value) { + setAddressLine1(value); + return this; } /** - * Returns the firm or organization. + * Sets address by copying from input address data. Street fields will be normalized in the + * process. I.e., after copy, there will not be any empty street lines in front of non-empty + * ones. For example, if input data's street line 1 is null but street line 2 has a value, + * this method will copy street line 2's value and set it to street line 1. */ - public String getOrganization() { - return mOrganization; + public Builder set(AddressData data) { + values.clear(); + for (AddressField addressField : AddressField.values()) { + if (addressField == AddressField.STREET_ADDRESS) { + continue; // Do nothing. + } else { + set(addressField, data.getFieldValue(addressField)); + } + } + normalizeAddresses(); + setLanguageCode(data.getLanguageCode()); + return this; } - /** - * Returns the recipient. Examples: "Jesse Wilson" or "Jesse Wilson c/o Apurva Mathad". - */ - public String getRecipient() { - return mRecipient; + public Builder setAddressLine1(String value) { + return set(AddressField.ADDRESS_LINE_1, value); } - /** - * Returns the country-specific postal code. Examples: "94043", "94043-1351", "SW1W", - * "SW1W 9TQ". - */ - public String getPostalCode() { - return mPostalCode; + public Builder setAddressLine2(String value) { + return set(AddressField.ADDRESS_LINE_2, value); } - /** - * Returns the country-specific sorting code. For example, the - * French CEDEX - */ - public String getSortingCode() { - return mSortingCode; + public Builder setOrganization(String value) { + return set(AddressField.ORGANIZATION, value); } - public String getFieldValue(AddressField field) { - switch (field) { - case COUNTRY: - return mPostalCountry; - case ADMIN_AREA: - return mAdministrativeArea; - case LOCALITY: - return mLocality; - case DEPENDENT_LOCALITY: - return mDependentLocality; - case POSTAL_CODE: - return mPostalCode; - case SORTING_CODE: - return mSortingCode; - case ADDRESS_LINE_1: - return mAddressLine1; - case ADDRESS_LINE_2: - return mAddressLine2; - case ORGANIZATION: - return mOrganization; - case RECIPIENT: - return mRecipient; - default: - throw new IllegalArgumentException("unrecognized key: " + field); - } + public Builder setRecipient(String value) { + return set(AddressField.RECIPIENT, value); } /** - * Returns the language of the text of this address. Languages are used to guide how the address - * is formatted for - * display. The same address may have different {@link AddressData} representations in - * different languages. For example, the French name of "New Mexico" is "Nouveau-Mexique". + * Sets an address field with the specified value. If the value is empty (a null string, + * empty string, or a string that contains only spaces), the original value associated with + * the field will be removed. */ - public String getLanguageCode() { - return mLanguageCode; + public Builder set(AddressField field, String value) { + if (value == null || value.length() == 0) { + values.remove(field); + } else { + values.put(field, value.trim()); + } + normalizeAddresses(); + return this; + } + + public AddressData build() { + return new AddressData(this); } /** - * Builder for AddressData + * Parses content of address line fields. + * If address_line_1 is empty, address_line_2 will be used to populate address_line_1 if + * possible. If address_line_1 contains a new line, content after the new line will be + * saved in address_line_2. */ - public static class Builder { - - private final Map mValues; - - private String mLanguage = null; - - public Builder() { - mValues = new HashMap(); - } - - /** - * A constructor that sets address field with input data. Street fields will be normalized - * in the process. I.e., after copy, there will not be any empty street line in front of - * non-empty ones. For example, if input data's street line 1 is null but street line 2 - * has a value, this method will copy street line 2's value and set it to street line 1. - */ - public Builder(AddressData addr) { - mValues = new HashMap(); - set(addr); - } - - public Builder setCountry(String value) { - return set(AddressField.COUNTRY, value); - } - - public Builder setAdminArea(String value) { - return set(AddressField.ADMIN_AREA, value); - } - - public Builder setLocality(String value) { - return set(AddressField.LOCALITY, value); - } - - public Builder setDependentLocality(String value) { - return set(AddressField.DEPENDENT_LOCALITY, value); - } - - public Builder setPostalCode(String value) { - return set(AddressField.POSTAL_CODE, value); - } - - public Builder setSortingCode(String value) { - return set(AddressField.SORTING_CODE, value); - } - - /** - * Sets the language code. - * - * @param languageCode the language to use, or {@code null} for no specified language. - */ - public Builder setLanguageCode(String languageCode) { - this.mLanguage = languageCode; - return this; - } - - /** - * Sets address lines 1 and 2 (if necessary) from a string that may contain multiple lines. - * - *

Example: Input " \n \n1600 Amphitheatre Ave\n\nRoom 122" will set the following - * values:
line 1: 1600 Amphitheatre Ave
line 2: Room 122

- * - * @param value a street string - */ - public Builder setAddress(String value) { - setAddressLine1(value); - return this; - } - - /** - * Sets address by copying from input address data. Street fields will be normalized in the - * process. I.e., after copy, there will not be any empty street lines in front of non-empty - * ones. For example, if input data's street line 1 is null but street line 2 has a value, - * this method will copy street line 2's value and set it to street line 1. - */ - public Builder set(AddressData data) { - mValues.clear(); - for (AddressField addressField : AddressField.values()) { - if (addressField == AddressField.STREET_ADDRESS) { - continue; // Do nothing. - } else { - set(addressField, data.getFieldValue(addressField)); - } - } - normalizeAddresses(); - setLanguageCode(data.getLanguageCode()); - return this; - } - - public Builder setAddressLine1(String value) { - return set(AddressField.ADDRESS_LINE_1, value); - } - - public Builder setAddressLine2(String value) { - return set(AddressField.ADDRESS_LINE_2, value); - } - - public Builder setOrganization(String value) { - return set(AddressField.ORGANIZATION, value); - } - - public Builder setRecipient(String value) { - return set(AddressField.RECIPIENT, value); - } - - /** - * Sets an address field with the specified value. If the value is empty (a null string, - * empty string, or a string that contains only spaces), the original value associated with - * the field will be removed. - */ - public Builder set(AddressField field, String value) { - if (value == null || value.length() == 0) { - mValues.remove(field); - } else { - mValues.put(field, value.trim()); - } - normalizeAddresses(); - return this; - } - - public AddressData build() { - return new AddressData(this); - } - - /** - * Parses content of address line fields. - * If address_line_1 is empty, address_line_2 will be used to populate address_line_1 if - * possible. If address_line_1 contains a new line, content after the new line will be - * saved in address_line_2. - */ - private void normalizeAddresses() { - String address1 = mValues.get(AddressField.ADDRESS_LINE_1); - String address2 = mValues.get(AddressField.ADDRESS_LINE_2); - if (address1 == null || address1.trim().length() == 0) { - address1 = address2; - address2 = null; - } - if (address1 != null) { - String[] addressLines = address1.split("\n"); - if (addressLines.length > 1) { - address1 = addressLines[0]; - address2 = addressLines[1]; - } - } - mValues.put(AddressField.ADDRESS_LINE_1, address1); - mValues.put(AddressField.ADDRESS_LINE_2, address2); + private void normalizeAddresses() { + String address1 = values.get(AddressField.ADDRESS_LINE_1); + String address2 = values.get(AddressField.ADDRESS_LINE_2); + if (address1 == null || address1.trim().length() == 0) { + address1 = address2; + address2 = null; + } + if (address1 != null) { + String[] addressLines = address1.split("\n"); + if (addressLines.length > 1) { + address1 = addressLines[0]; + address2 = addressLines[1]; } + } + values.put(AddressField.ADDRESS_LINE_1, address1); + values.put(AddressField.ADDRESS_LINE_2, address2); } + } } diff --git a/java/src/com/android/i18n/addressinput/AddressField.java b/java/src/com/android/i18n/addressinput/AddressField.java index 17b1817..7d3dbf2 100644 --- a/java/src/com/android/i18n/addressinput/AddressField.java +++ b/java/src/com/android/i18n/addressinput/AddressField.java @@ -24,64 +24,64 @@ import java.util.Map; * formatting. Note that the metadata also has a character for newlines, which is not defined here. */ public enum AddressField { - ADMIN_AREA('S'), - LOCALITY('C'), - RECIPIENT('N'), - ORGANIZATION('O'), - // Deprecated - use A instead. - ADDRESS_LINE_1('1'), - // Deprecated - use A instead. - ADDRESS_LINE_2('2'), - DEPENDENT_LOCALITY('D'), - POSTAL_CODE('Z'), - SORTING_CODE('X'), - STREET_ADDRESS('A'), + ADMIN_AREA('S'), + LOCALITY('C'), + RECIPIENT('N'), + ORGANIZATION('O'), + // Deprecated - use A instead. + ADDRESS_LINE_1('1'), + // Deprecated - use A instead. + ADDRESS_LINE_2('2'), + DEPENDENT_LOCALITY('D'), + POSTAL_CODE('Z'), + SORTING_CODE('X'), + STREET_ADDRESS('A'), - COUNTRY('R'); + COUNTRY('R'); - /** - * Enum for width types of address input fields. - */ - public enum WidthType { - LONG, - SHORT; - } + /** + * Enum for width types of address input fields. + */ + public enum WidthType { + LONG, + SHORT; + } - private static final Map FIELD_MAPPING - = new HashMap(); + private static final Map FIELD_MAPPING + = new HashMap(); - static { - for (AddressField value : values()) { - FIELD_MAPPING.put(value.getChar(), value); - } + static { + for (AddressField value : values()) { + FIELD_MAPPING.put(value.getChar(), value); } + } - private final char mField; + private final char field; - private AddressField(char field) { - mField = field; - } + private AddressField(char field) { + this.field = field; + } - /** - * Gets the corresponding AddressField for the character code. Returns null if the character is - * not recognized. - */ - static AddressField of(char field) { - return FIELD_MAPPING.get(field); - } + /** + * Gets the corresponding AddressField for the character code. Returns null if the character is + * not recognized. + */ + static AddressField of(char field) { + return FIELD_MAPPING.get(field); + } - /** - * Gets the field's identification character, as used in the metadata. - * - * @return identification char. - */ - char getChar() { - return mField; - } + /** + * Gets the field's identification character, as used in the metadata. + * + * @return identification char. + */ + char getChar() { + return field; + } - /** Returns default width type of the address field. */ - WidthType getDefaulWidthType() { - return this.equals(POSTAL_CODE) || this.equals(SORTING_CODE) - ? WidthType.SHORT : WidthType.LONG; - } + /** Returns default width type of the address field. */ + WidthType getDefaulWidthType() { + return this.equals(POSTAL_CODE) || this.equals(SORTING_CODE) + ? WidthType.SHORT : WidthType.LONG; + } } diff --git a/java/src/com/android/i18n/addressinput/AddressProblemType.java b/java/src/com/android/i18n/addressinput/AddressProblemType.java index 4cab705..27d19f6 100644 --- a/java/src/com/android/i18n/addressinput/AddressProblemType.java +++ b/java/src/com/android/i18n/addressinput/AddressProblemType.java @@ -21,50 +21,50 @@ package com.android.i18n.addressinput; */ public enum AddressProblemType { - /** - * The field is not null and not whitespace, and the field should not be used for this country. - * - *

For example, in the U.S. the SORTING_CODE field is unused, so its presence is an error. - */ - USING_UNUSED_FIELD, + /** + * The field is not null and not whitespace, and the field should not be used for this country. + * + *

For example, in the U.S. the SORTING_CODE field is unused, so its presence is an error. + */ + USING_UNUSED_FIELD, - /** - * The field is null or whitespace, and the field is required. - * - *

For example, in the U.S. ADMIN_AREA is a required field. - */ - MISSING_REQUIRED_FIELD, + /** + * The field is null or whitespace, and the field is required. + * + *

For example, in the U.S. ADMIN_AREA is a required field. + */ + MISSING_REQUIRED_FIELD, - /** - * A list of values for the field is defined and the value does not occur in the list. Applies - * to hierarchical elements like REGION, ADMIN_AREA, LOCALITY, and DEPENDENT_LOCALITY. - * - *

For example, in the U.S. the only valid values for ADMIN_AREA are the two-letter state - * codes. - */ - UNKNOWN_VALUE, + /** + * A list of values for the field is defined and the value does not occur in the list. Applies + * to hierarchical elements like REGION, ADMIN_AREA, LOCALITY, and DEPENDENT_LOCALITY. + * + *

For example, in the U.S. the only valid values for ADMIN_AREA are the two-letter state + * codes. + */ + UNKNOWN_VALUE, - /** - * A format for the field is defined and the value does not match. This is used to match - * POSTAL_CODE against the the format pattern generally. - * - *

For example, in the U.S. postal codes are five digits with an optional hyphen followed by - * four digits. - */ - UNRECOGNIZED_FORMAT, + /** + * A format for the field is defined and the value does not match. This is used to match + * POSTAL_CODE against the the format pattern generally. + * + *

For example, in the U.S. postal codes are five digits with an optional hyphen followed by + * four digits. + */ + UNRECOGNIZED_FORMAT, - /** - * A pattern for the field is defined and the value does not match. This is used to match - * POSTAL_CODE against a regular expression. - * - *

For example, in the U.S. postal codes in the state of California start with '9'. - */ - MISMATCHING_VALUE; + /** + * A pattern for the field is defined and the value does not match. This is used to match + * POSTAL_CODE against a regular expression. + * + *

For example, in the U.S. postal codes in the state of California start with '9'. + */ + MISMATCHING_VALUE; - /** - * Returns a unique string identifying this problem (for use in a message catalog). - */ - public String keyname() { - return name().toLowerCase(); - } + /** + * Returns a unique string identifying this problem (for use in a message catalog). + */ + public String keyname() { + return name().toLowerCase(); + } } diff --git a/java/src/com/android/i18n/addressinput/AddressProblems.java b/java/src/com/android/i18n/addressinput/AddressProblems.java index 9371140..39a0457 100644 --- a/java/src/com/android/i18n/addressinput/AddressProblems.java +++ b/java/src/com/android/i18n/addressinput/AddressProblems.java @@ -24,44 +24,44 @@ import java.util.Map; */ public class AddressProblems { - private Map mProblems = - new HashMap(); + private Map problems = + new HashMap(); - /** - * Only one address problem type is saved per addressField. Address field as used here refers to - * the different data parts in the AddressData class. - */ - void add(AddressField addressField, AddressProblemType problem) { - mProblems.put(addressField, problem); - } + /** + * Only one address problem type is saved per addressField. Address field as used here refers to + * the different data parts in the AddressData class. + */ + void add(AddressField addressField, AddressProblemType problem) { + problems.put(addressField, problem); + } - /** - * Returns true if no problems have been added. - */ - public boolean isEmpty() { - return mProblems.isEmpty(); - } + /** + * Returns true if no problems have been added. + */ + public boolean isEmpty() { + return problems.isEmpty(); + } - @Override - public String toString() { - return mProblems.toString(); - } + @Override + public String toString() { + return problems.toString(); + } - public void clear() { - mProblems.clear(); - } + public void clear() { + problems.clear(); + } - /** - * Returns null if no problems exists. - */ - public AddressProblemType getProblem(AddressField addressField) { - return mProblems.get(addressField); - } + /** + * Returns null if no problems exists. + */ + public AddressProblemType getProblem(AddressField addressField) { + return problems.get(addressField); + } - /** - * This will return an empty map if there are no problems. - */ - public Map getProblems() { - return mProblems; - } + /** + * This will return an empty map if there are no problems. + */ + public Map getProblems() { + return problems; + } } diff --git a/java/src/com/android/i18n/addressinput/AddressUiComponent.java b/java/src/com/android/i18n/addressinput/AddressUiComponent.java index 3c2e937..d0aa4c8 100644 --- a/java/src/com/android/i18n/addressinput/AddressUiComponent.java +++ b/java/src/com/android/i18n/addressinput/AddressUiComponent.java @@ -28,129 +28,129 @@ import java.util.List; * candidate) or a spinner. */ class AddressUiComponent { - // The label for the UI component - private String mFieldName; - - // The type of the UI component - private UiComponent mUiType; - - // The list of elements in the UI component - private List mCandidatesList = new ArrayList(); - - // The id of this UI component - private AddressField mId; - - // The id of the parent UI component. When the parent UI component is updated, this UI - // component should be updated. - private AddressField mParentId; - - // The View representing the UI component - private View mView; - - /** - * Type of UI component. There are only EDIT (text-box) and SPINNER (drop-down) components. - */ - enum UiComponent { - EDIT, SPINNER, - } - - AddressUiComponent(AddressField id) { - mId = id; - // By default, an AddressUiComponent doesn't depend on anything else. - mParentId = null; - mUiType = UiComponent.EDIT; - } - - /** - * Initializes the candidatesList, and set the uiType and parentId. - * @param candidatesList - */ - void initializeCandidatesList(List candidatesList) { - mCandidatesList = candidatesList; - if (candidatesList.size() > 1) { - mUiType = UiComponent.SPINNER; - switch (mId) { - case DEPENDENT_LOCALITY: - mParentId = AddressField.LOCALITY; - break; - case LOCALITY: - mParentId = AddressField.ADMIN_AREA; - break; - case ADMIN_AREA: - mParentId = AddressField.COUNTRY; - break; - default: - // Ignore. - } - } - } - - /** - * Gets the value entered in the UI component. - */ - String getValue() { - if (mView == null) { - return (mCandidatesList.size() == 0) ? "" : mCandidatesList.get(0).getDisplayName(); - } - switch (mUiType) { - case SPINNER: - Object selectedItem = ((Spinner) mView).getSelectedItem(); - if (selectedItem == null) { - return ""; - } - return selectedItem.toString(); - case EDIT: - return ((EditText) mView).getText().toString(); - default: - return ""; + // The label for the UI component + private String fieldName; + + // The type of the UI component + private UiComponent uiType; + + // The list of elements in the UI component + private List candidatesList = new ArrayList(); + + // The id of this UI component + private AddressField id; + + // The id of the parent UI component. When the parent UI component is updated, this UI + // component should be updated. + private AddressField parentId; + + // The View representing the UI component + private View view; + + /** + * Type of UI component. There are only EDIT (text-box) and SPINNER (drop-down) components. + */ + enum UiComponent { + EDIT, SPINNER, + } + + AddressUiComponent(AddressField id) { + id = id; + // By default, an AddressUiComponent doesn't depend on anything else. + parentId = null; + uiType = UiComponent.EDIT; + } + + /** + * Initializes the candidatesList, and set the uiType and parentId. + * @param candidatesList + */ + void initializeCandidatesList(List candidatesList) { + candidatesList = candidatesList; + if (candidatesList.size() > 1) { + uiType = UiComponent.SPINNER; + switch (id) { + case DEPENDENT_LOCALITY: + parentId = AddressField.LOCALITY; + break; + case LOCALITY: + parentId = AddressField.ADMIN_AREA; + break; + case ADMIN_AREA: + parentId = AddressField.COUNTRY; + break; + default: + // Ignore. + } + } + } + + /** + * Gets the value entered in the UI component. + */ + String getValue() { + if (view == null) { + return (candidatesList.size() == 0) ? "" : candidatesList.get(0).getDisplayName(); + } + switch (uiType) { + case SPINNER: + Object selectedItem = ((Spinner) view).getSelectedItem(); + if (selectedItem == null) { + return ""; } + return selectedItem.toString(); + case EDIT: + return ((EditText) view).getText().toString(); + default: + return ""; } + } - String getFieldName() { - return mFieldName; - } + String getFieldName() { + return fieldName; + } - void setFieldName(String fieldName) { - mFieldName = fieldName; - } + void setFieldName(String fieldName) { + fieldName = fieldName; + } - UiComponent getUiType() { - return mUiType; - } + UiComponent getUiType() { + return uiType; + } - void setUiType(UiComponent uiType) { - mUiType = uiType; - } + void setUiType(UiComponent uiType) { + uiType = uiType; + } - List getCandidatesList() { - return mCandidatesList; - } + List getCandidatesList() { + return candidatesList; + } - void setCandidatesList(List candidatesList) { - mCandidatesList = candidatesList; - } + void setCandidatesList(List candidatesList) { + candidatesList = candidatesList; + } - AddressField getId() { - return mId; - } + AddressField getId() { + return id; + } - void setId(AddressField id) { - mId = id; - } + void setId(AddressField id) { + id = id; + } - AddressField getParentId() { - return mParentId; - } + AddressField getParentId() { + return parentId; + } - void setParentId(AddressField parentId) { - mParentId = parentId; - } + void setParentId(AddressField parentId) { + parentId = parentId; + } - void setView(View view) { - mView = view; - } + void setView(View view) { + view = view; + } - View getView() { - return mView; - } + View getView() { + return view; + } } diff --git a/java/src/com/android/i18n/addressinput/AddressVerificationData.java b/java/src/com/android/i18n/addressinput/AddressVerificationData.java index 58f4366..f5b9c05 100644 --- a/java/src/com/android/i18n/addressinput/AddressVerificationData.java +++ b/java/src/com/android/i18n/addressinput/AddressVerificationData.java @@ -29,129 +29,129 @@ import java.util.regex.Pattern; */ class AddressVerificationData implements DataSource { - private final Map mPropertiesMap; + private final Map propertiesMap; - private static final Pattern KEY_VALUES_PATTERN = Pattern.compile("\"([^\"]+)\":\"([^\"]*)\""); + private static final Pattern KEY_VALUES_PATTERN = Pattern.compile("\"([^\"]+)\":\"([^\"]*)\""); - private static final Pattern SEPARATOR_PATTERN = Pattern.compile("\",\""); + private static final Pattern SEPARATOR_PATTERN = Pattern.compile("\",\""); - /** - * Constructs from a map of address property data. This keeps a reference to the map. This - * does not mutate the map. The map should not be mutated subsequent to this call. - */ - AddressVerificationData(Map propertiesMap) { - mPropertiesMap = propertiesMap; - } + /** + * Constructs from a map of address property data. This keeps a reference to the map. This + * does not mutate the map. The map should not be mutated subsequent to this call. + */ + AddressVerificationData(Map propertiesMap) { + this.propertiesMap = propertiesMap; + } - @Override - public AddressVerificationNodeData get(String key) { - String json = mPropertiesMap.get(key); - if (json != null && isValidKey(key)) { - return createNodeData(json); - } - return null; + @Override + public AddressVerificationNodeData get(String key) { + String json = propertiesMap.get(key); + if (json != null && isValidKey(key)) { + return createNodeData(json); } - - /** - * Returns a set of the keys for which verification data is provided. The returned set is - * immutable. - */ - Set keys() { - Set result = new HashSet(); - for (String key : mPropertiesMap.keySet()) { - if (isValidKey(key)) { - result.add(key); + return null; + } + + /** + * Returns a set of the keys for which verification data is provided. The returned set is + * immutable. + */ + Set keys() { + Set result = new HashSet(); + for (String key : propertiesMap.keySet()) { + if (isValidKey(key)) { + result.add(key); + } + } + return Collections.unmodifiableSet(result); + } + + /** + * We can be initialized with the full set of address information, but validation only uses + * info prefixed with "data" (in particular, no info prefixed with "examples"). + */ + private boolean isValidKey(String key) { + return key.startsWith("data"); + } + + /** + * Returns the contents of the JSON-format string as a map. + */ + AddressVerificationNodeData createNodeData(String json) { + // Remove leading and trailing { and }. + json = json.substring(1, json.length() - 1); + Map map = + new EnumMap(AddressDataKey.class); + + // our objects are very simple so we parse manually + // - no double quotes within strings + // - no extra spaces + // can't use split "," since some data has commas in it. + Matcher sm = SEPARATOR_PATTERN.matcher(json); + int pos = 0; + while (pos < json.length()) { + String pair; + if (sm.find()) { + pair = json.substring(pos, sm.start() + 1); + pos = sm.start() + 2; + } else { + pair = json.substring(pos); + pos = json.length(); + } + + Matcher m = KEY_VALUES_PATTERN.matcher(pair); + if (m.matches()) { + String value = m.group(2); + + // Remove escaped backslashes. + // Java regex doesn't handle a replacement String consisting of + // a single backslash, and treats a replacement String consisting of + // two backslashes as two backslashes instead of one. So there's + // no way to use regex to replace a match with a single backslash, + // apparently. + if (value.length() > 0) { + char[] linechars = m.group(2).toCharArray(); + int w = 1; + for (int r = w; r < linechars.length; ++r) { + char c = linechars[r]; + if (c == '\\' && linechars[w - 1] == '\\') { + // don't increment w; + continue; } + linechars[w++] = c; + } + value = new String(linechars, 0, w); } - return Collections.unmodifiableSet(result); - } - /** - * We can be initialized with the full set of address information, but validation only uses - * info prefixed with "data" (in particular, no info prefixed with "examples"). - */ - private boolean isValidKey(String key) { - return key.startsWith("data"); + AddressDataKey df = AddressDataKey.get(m.group(1)); + if (df == null) { + // Skip this data - it isn't used in the Android version. + } else { + map.put(df, value); + } + } else { + // This is a runtime data sanity check. The data should be + // checked when the data is built. The JSON data string should + // be parsable into string pairs using SEP_PAT. + throw new RuntimeException("could not match '" + pair + "' in '" + json + "'"); + } } - /** - * Returns the contents of the JSON-format string as a map. - */ - AddressVerificationNodeData createNodeData(String json) { - // Remove leading and trailing { and }. - json = json.substring(1, json.length() - 1); - Map map = - new EnumMap(AddressDataKey.class); - - // our objects are very simple so we parse manually - // - no double quotes within strings - // - no extra spaces - // can't use split "," since some data has commas in it. - Matcher sm = SEPARATOR_PATTERN.matcher(json); - int pos = 0; - while (pos < json.length()) { - String pair; - if (sm.find()) { - pair = json.substring(pos, sm.start() + 1); - pos = sm.start() + 2; - } else { - pair = json.substring(pos); - pos = json.length(); - } + return new AddressVerificationNodeData(map); + } - Matcher m = KEY_VALUES_PATTERN.matcher(pair); - if (m.matches()) { - String value = m.group(2); - - // Remove escaped backslashes. - // Java regex doesn't handle a replacement String consisting of - // a single backslash, and treats a replacement String consisting of - // two backslashes as two backslashes instead of one. So there's - // no way to use regex to replace a match with a single backslash, - // apparently. - if (value.length() > 0) { - char[] linechars = m.group(2).toCharArray(); - int w = 1; - for (int r = w; r < linechars.length; ++r) { - char c = linechars[r]; - if (c == '\\' && linechars[w - 1] == '\\') { - // don't increment w; - continue; - } - linechars[w++] = c; - } - value = new String(linechars, 0, w); - } - - AddressDataKey df = AddressDataKey.get(m.group(1)); - if (df == null) { - // Skip this data - it isn't used in the Android version. - } else { - map.put(df, value); - } - } else { - // This is a runtime data sanity check. The data should be - // checked when the data is built. The JSON data string should - // be parsable into string pairs using SEP_PAT. - throw new RuntimeException("could not match '" + pair + "' in '" + json + "'"); - } - } - - return new AddressVerificationNodeData(map); + @Override + public AddressVerificationNodeData getDefaultData(String key) { + // gets country key + if (key.split("/").length > 1) { + String[] parts = key.split("/"); + key = parts[0] + "/" + parts[1]; } - @Override - public AddressVerificationNodeData getDefaultData(String key) { - // gets country key - if (key.split("/").length > 1) { - String[] parts = key.split("/"); - key = parts[0] + "/" + parts[1]; - } - - AddressVerificationNodeData data = get(key); - if (data == null) { - throw new RuntimeException("failed to get default data with key " + key); - } - return data; + AddressVerificationNodeData data = get(key); + if (data == null) { + throw new RuntimeException("failed to get default data with key " + key); } + return data; + } } diff --git a/java/src/com/android/i18n/addressinput/AddressVerificationNodeData.java b/java/src/com/android/i18n/addressinput/AddressVerificationNodeData.java index bb291d9..8082c07 100644 --- a/java/src/com/android/i18n/addressinput/AddressVerificationNodeData.java +++ b/java/src/com/android/i18n/addressinput/AddressVerificationNodeData.java @@ -28,28 +28,28 @@ import java.util.Map; */ public class AddressVerificationNodeData { - private final Map mMap; - - public AddressVerificationNodeData(Map map) { - Util.checkNotNull("Cannot construct StandardNodeData with null map"); - mMap = map; - } - - /** - * Iterates through the map. - */ - public Iterator iterator() { - return mMap.keySet().iterator(); - } - - public boolean containsKey(AddressDataKey key) { - return mMap.containsKey(key); - } - - /** - * Gets the value for a particular key in the map. - */ - public String get(AddressDataKey key) { - return mMap.get(key); - } + private final Map map; + + public AddressVerificationNodeData(Map map) { + Util.checkNotNull("Cannot construct StandardNodeData with null map"); + this.map = map; + } + + /** + * Iterates through the map. + */ + public Iterator iterator() { + return map.keySet().iterator(); + } + + public boolean containsKey(AddressDataKey key) { + return map.containsKey(key); + } + + /** + * Gets the value for a particular key in the map. + */ + public String get(AddressDataKey key) { + return map.get(key); + } } diff --git a/java/src/com/android/i18n/addressinput/AddressWidget.java b/java/src/com/android/i18n/addressinput/AddressWidget.java index 8a598ff..8c6b7d4 100644 --- a/java/src/com/android/i18n/addressinput/AddressWidget.java +++ b/java/src/com/android/i18n/addressinput/AddressWidget.java @@ -51,731 +51,731 @@ import java.util.Map; * customs. */ public class AddressWidget implements AdapterView.OnItemSelectedListener { - private Context mContext; + private Context context; - private ViewGroup mRootView; + private ViewGroup rootView; - private LayoutInflater mInflater; + private LayoutInflater inflater; - private CacheData mCacheData; + private CacheData cacheData; - // A map for all address fields. - private final EnumMap mInputWidgets = - new EnumMap(AddressField.class); + // A map for all address fields. + private final EnumMap inputWidgets = + new EnumMap(AddressField.class); - private FormController mFormController; + private FormController formController; - private FormatInterpreter mFormatInterpreter; + private FormatInterpreter formatInterpreter; - private FormOptions mFormOptions; + private FormOptions formOptions; - private StandardAddressVerifier mVerifier; + private StandardAddressVerifier verifier; - private ProgressDialog mProgressDialog; + private ProgressDialog progressDialog; - private String mCurrentRegion; + private String currentRegion; - // The current language the widget uses in BCP47 format. It differs from the default locale of - // the phone in that it contains information on the script to use. - private String mWidgetLocale; + // The current language the widget uses in BCP47 format. It differs from the default locale of + // the phone in that it contains information on the script to use. + private String widgetLocale; - private ScriptType mScript; + private ScriptType script; - // Possible labels that could be applied to the admin area field of the current country. - // Examples include "state", "province", "emirate", etc. - private static final Map ADMIN_LABELS; - // Possible labels that could be applied to the locality (city) field of the current country. - // Examples include "city" or "district". - private static final Map LOCALITY_LABELS; - // Possible labels that could be applied to the sublocality field of the current country. - // Examples include "suburb" or "neighborhood". - private static final Map SUBLOCALITY_LABELS; + // Possible labels that could be applied to the admin area field of the current country. + // Examples include "state", "province", "emirate", etc. + private static final Map ADMIN_LABELS; + // Possible labels that could be applied to the locality (city) field of the current country. + // Examples include "city" or "district". + private static final Map LOCALITY_LABELS; + // Possible labels that could be applied to the sublocality field of the current country. + // Examples include "suburb" or "neighborhood". + private static final Map SUBLOCALITY_LABELS; - private static final FormOptions SHOW_ALL_FIELDS = new FormOptions.Builder().build(); + private static final FormOptions SHOW_ALL_FIELDS = new FormOptions.Builder().build(); - // The appropriate label that should be applied to the zip code field of the current country. - private enum ZipLabel { - ZIP, - POSTAL - } - - private ZipLabel mZipLabel; - - static { - Map adminLabelMap = new HashMap(15); - adminLabelMap.put("area", R.string.i18n_area); - adminLabelMap.put("county", R.string.i18n_county); - adminLabelMap.put("department", R.string.i18n_department); - adminLabelMap.put("district", R.string.i18n_district); - adminLabelMap.put("do_si", R.string.i18n_do_si); - adminLabelMap.put("emirate", R.string.i18n_emirate); - adminLabelMap.put("island", R.string.i18n_island); - adminLabelMap.put("oblast", R.string.i18n_oblast); - adminLabelMap.put("parish", R.string.i18n_parish); - adminLabelMap.put("prefecture", R.string.i18n_prefecture); - adminLabelMap.put("province", R.string.i18n_province); - adminLabelMap.put("state", R.string.i18n_state); - ADMIN_LABELS = Collections.unmodifiableMap(adminLabelMap); + // The appropriate label that should be applied to the zip code field of the current country. + private enum ZipLabel { + ZIP, + POSTAL + } - Map localityLabelMap = new HashMap(2); - localityLabelMap.put("city", R.string.i18n_locality_label); - localityLabelMap.put("district", R.string.i18n_district); - localityLabelMap.put("post_town", R.string.i18n_post_town); - LOCALITY_LABELS = Collections.unmodifiableMap(localityLabelMap); + private ZipLabel zipLabel; - Map sublocalityLabelMap = new HashMap(2); - sublocalityLabelMap.put("suburb", R.string.i18n_suburb); - sublocalityLabelMap.put("district", R.string.i18n_district); - sublocalityLabelMap.put("neighborhood", R.string.i18n_neighborhood); - sublocalityLabelMap.put("village_township", R.string.i18n_village_township); - SUBLOCALITY_LABELS = Collections.unmodifiableMap(sublocalityLabelMap); - } + static { + Map adminLabelMap = new HashMap(15); + adminLabelMap.put("area", R.string.i18n_area); + adminLabelMap.put("county", R.string.i18n_county); + adminLabelMap.put("department", R.string.i18n_department); + adminLabelMap.put("district", R.string.i18n_district); + adminLabelMap.put("do_si", R.string.i18n_do_si); + adminLabelMap.put("emirate", R.string.i18n_emirate); + adminLabelMap.put("island", R.string.i18n_island); + adminLabelMap.put("oblast", R.string.i18n_oblast); + adminLabelMap.put("parish", R.string.i18n_parish); + adminLabelMap.put("prefecture", R.string.i18n_prefecture); + adminLabelMap.put("province", R.string.i18n_province); + adminLabelMap.put("state", R.string.i18n_state); + ADMIN_LABELS = Collections.unmodifiableMap(adminLabelMap); - // Need handler for callbacks to the UI thread - final Handler mHandler = new Handler(); + Map localityLabelMap = new HashMap(2); + localityLabelMap.put("city", R.string.i18n_locality_label); + localityLabelMap.put("district", R.string.i18n_district); + localityLabelMap.put("post_town", R.string.i18n_post_town); + LOCALITY_LABELS = Collections.unmodifiableMap(localityLabelMap); - final Runnable mUpdateMultipleFields = new Runnable() { - @Override - public void run() { - updateFields(); - } - }; + Map sublocalityLabelMap = new HashMap(2); + sublocalityLabelMap.put("suburb", R.string.i18n_suburb); + sublocalityLabelMap.put("district", R.string.i18n_district); + sublocalityLabelMap.put("neighborhood", R.string.i18n_neighborhood); + sublocalityLabelMap.put("village_township", R.string.i18n_village_township); + SUBLOCALITY_LABELS = Collections.unmodifiableMap(sublocalityLabelMap); + } - private class UpdateRunnable implements Runnable { - private AddressField myId; + // Need handler for callbacks to the UI thread + final Handler handler = new Handler(); - public UpdateRunnable(AddressField id) { - myId = id; - } - - @Override - public void run() { - updateInputWidget(myId); - } + final Runnable updateMultipleFields = new Runnable() { + @Override + public void run() { + updateFields(); } + }; - private static class AddressSpinnerInfo { - private Spinner mView; + private class UpdateRunnable implements Runnable { + private AddressField myId; - private AddressField mId; + public UpdateRunnable(AddressField id) { + myId = id; + } - private AddressField mParentId; + @Override + public void run() { + updateInputWidget(myId); + } + } - private ArrayAdapter mAdapter; + private static class AddressSpinnerInfo { + private Spinner view; - private List mCurrentRegions; + private AddressField id; - @SuppressWarnings("unchecked") - public AddressSpinnerInfo(Spinner view, AddressField id, AddressField parentId) { - mView = view; - mId = id; - mParentId = parentId; - mAdapter = (ArrayAdapter) view.getAdapter(); - } + private AddressField parentId; - public void setSpinnerList(List list, String defaultKey) { - mCurrentRegions = list; - mAdapter.clear(); - for (RegionData item : list) { - mAdapter.add(item.getDisplayName()); - } - mAdapter.sort(Collator.getInstance(Locale.getDefault())); - if (defaultKey.length() == 0) { - mView.setSelection(0); - } else { - int position = mAdapter.getPosition(defaultKey); - mView.setSelection(position); - } - } + private ArrayAdapter adapter; - // Returns the region key of the currently selected region in the Spinner. - public String getRegionCode(int position) { - if (mAdapter.getCount() <= position) { - return ""; - } - String value = mAdapter.getItem(position); - return getRegionDataKeyForValue(value); - } + private List currentRegions; - // Returns the region key for the region value. - public String getRegionDataKeyForValue(String value) { - for (RegionData data : mCurrentRegions) { - if (data.getDisplayName().endsWith(value)) { - return data.getKey(); - } - } - return ""; - } + @SuppressWarnings("unchecked") + public AddressSpinnerInfo(Spinner view, AddressField id, AddressField parentId) { + view = view; + id = id; + parentId = parentId; + adapter = (ArrayAdapter) view.getAdapter(); } - private final ArrayList mSpinners = new ArrayList(); - - private AddressWidgetUiComponentProvider mComponentProvider; - - /** TODO: Add region-dependent width types for address fields. */ - private WidthType getFieldWidthType(AddressUiComponent field) { - return field.getId().getDefaulWidthType(); + public void setSpinnerList(List list, String defaultKey) { + currentRegions = list; + adapter.clear(); + for (RegionData item : list) { + adapter.add(item.getDisplayName()); + } + adapter.sort(Collator.getInstance(Locale.getDefault())); + if (defaultKey.length() == 0) { + view.setSelection(0); + } else { + int position = adapter.getPosition(defaultKey); + view.setSelection(position); + } } - private void createView(ViewGroup rootView, AddressUiComponent field, String defaultKey, - boolean readOnly) { - @SuppressWarnings("deprecation") // FILL_PARENT renamed MATCH_PARENT in API Level 8. - LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(LayoutParams.FILL_PARENT, - LayoutParams.WRAP_CONTENT); - String fieldText = field.getFieldName(); - WidthType widthType = getFieldWidthType(field); - - if (fieldText.length() > 0) { - TextView textView = mComponentProvider.createUiLabel(fieldText, widthType); - rootView.addView(textView, lp); - } - if (field.getUiType().equals(UiComponent.EDIT)) { - EditText editText = mComponentProvider.createUiTextField(widthType); - field.setView(editText); - editText.setEnabled(!readOnly); - rootView.addView(editText, lp); - } else if (field.getUiType().equals(UiComponent.SPINNER)) { - ArrayAdapter adapter = mComponentProvider.createUiPickerAdapter(widthType); - Spinner spinner = mComponentProvider.createUiPickerSpinner(widthType); - - field.setView(spinner); - rootView.addView(spinner, lp); - spinner.setAdapter(adapter); - AddressSpinnerInfo spinnerInfo = - new AddressSpinnerInfo(spinner, field.getId(), field.getParentId()); - spinnerInfo.setSpinnerList(field.getCandidatesList(), defaultKey); - - if (fieldText.length() > 0) { - spinner.setPrompt(fieldText); - } - spinner.setOnItemSelectedListener(this); - mSpinners.add(spinnerInfo); - } + // Returns the region key of the currently selected region in the Spinner. + public String getRegionCode(int position) { + if (adapter.getCount() <= position) { + return ""; + } + String value = adapter.getItem(position); + return getRegionDataKeyForValue(value); } - /** - * Associates each field with its corresponding AddressUiComponent. - */ - private void buildFieldWidgets() { - AddressData data = new AddressData.Builder().setCountry(mCurrentRegion).build(); - LookupKey key = new LookupKey.Builder(LookupKey.KeyType.DATA).setAddressData(data).build(); - AddressVerificationNodeData countryNode = - (new ClientData(mCacheData)).getDefaultData(key.toString()); - - // Set up AddressField.ADMIN_AREA - AddressUiComponent adminAreaUi = new AddressUiComponent(AddressField.ADMIN_AREA); - adminAreaUi.setFieldName(getAdminAreaFieldName(countryNode)); - mInputWidgets.put(AddressField.ADMIN_AREA, adminAreaUi); - - // Set up AddressField.LOCALITY - AddressUiComponent localityUi = new AddressUiComponent(AddressField.LOCALITY); - localityUi.setFieldName(getLocalityFieldName(countryNode)); - mInputWidgets.put(AddressField.LOCALITY, localityUi); - - // Set up AddressField.DEPENDENT_LOCALITY - AddressUiComponent subLocalityUi = new AddressUiComponent(AddressField.DEPENDENT_LOCALITY); - subLocalityUi.setFieldName(getSublocalityFieldName(countryNode)); - mInputWidgets.put(AddressField.DEPENDENT_LOCALITY, subLocalityUi); - - // Set up AddressField.ADDRESS_LINE_1 - AddressUiComponent addressLine1Ui = new AddressUiComponent(AddressField.ADDRESS_LINE_1); - addressLine1Ui.setFieldName(mContext.getString(R.string.i18n_address_line1_label)); - mInputWidgets.put(AddressField.ADDRESS_LINE_1, addressLine1Ui); - - // Set up AddressField.ADDRESS_LINE_2 - AddressUiComponent addressLine2Ui = new AddressUiComponent(AddressField.ADDRESS_LINE_2); - addressLine2Ui.setFieldName(""); - mInputWidgets.put(AddressField.ADDRESS_LINE_2, addressLine2Ui); - - // Set up AddressField.ORGANIZATION - AddressUiComponent organizationUi = new AddressUiComponent(AddressField.ORGANIZATION); - organizationUi.setFieldName(mContext.getString(R.string.i18n_organization_label)); - mInputWidgets.put(AddressField.ORGANIZATION, organizationUi); - - // Set up AddressField.RECIPIENT - AddressUiComponent recipientUi = new AddressUiComponent(AddressField.RECIPIENT); - recipientUi.setFieldName(mContext.getString(R.string.i18n_recipient_label)); - mInputWidgets.put(AddressField.RECIPIENT, recipientUi); - - // Set up AddressField.POSTAL_CODE - AddressUiComponent postalCodeUi = new AddressUiComponent(AddressField.POSTAL_CODE); - postalCodeUi.setFieldName(getZipFieldName(countryNode)); - mInputWidgets.put(AddressField.POSTAL_CODE, postalCodeUi); - - // Set up AddressField.SORTING_CODE - AddressUiComponent sortingCodeUi = new AddressUiComponent(AddressField.SORTING_CODE); - sortingCodeUi.setFieldName("CEDEX"); - mInputWidgets.put(AddressField.SORTING_CODE, sortingCodeUi); - } - - private void initializeDropDowns() { - AddressUiComponent adminAreaUi = mInputWidgets.get(AddressField.ADMIN_AREA); - List adminAreaList = getRegionData(AddressField.COUNTRY); - adminAreaUi.initializeCandidatesList(adminAreaList); - - AddressUiComponent localityUi = mInputWidgets.get(AddressField.LOCALITY); - List localityList = getRegionData(AddressField.ADMIN_AREA); - localityUi.initializeCandidatesList(localityList); - } - - // ZIP code is called postal code in some countries. This method returns the appropriate name - // for the given countryNode. - private String getZipFieldName(AddressVerificationNodeData countryNode) { - String zipName; - String zipType = countryNode.get(AddressDataKey.ZIP_NAME_TYPE); - if (zipType == null) { - mZipLabel = ZipLabel.POSTAL; - zipName = mContext.getString(R.string.i18n_postal_code_label); - } else { - mZipLabel = ZipLabel.ZIP; - zipName = mContext.getString(R.string.i18n_zip_code_label); + // Returns the region key for the region value. + public String getRegionDataKeyForValue(String value) { + for (RegionData data : currentRegions) { + if (data.getDisplayName().endsWith(value)) { + return data.getKey(); } - return zipName; + } + return ""; } + } - private String getLocalityFieldName(AddressVerificationNodeData countryNode) { - String localityLabelType = countryNode.get(AddressDataKey.LOCALITY_NAME_TYPE); - Integer result = LOCALITY_LABELS.get(localityLabelType); - if (result == null) { - // Fallback to city. - result = R.string.i18n_locality_label; - } - return mContext.getString(result); - } + private final ArrayList spinners = new ArrayList(); - private String getSublocalityFieldName(AddressVerificationNodeData countryNode) { - String sublocalityLabelType = countryNode.get(AddressDataKey.SUBLOCALITY_NAME_TYPE); - Integer result = SUBLOCALITY_LABELS.get(sublocalityLabelType); - if (result == null) { - // Fallback to suburb. - result = R.string.i18n_suburb; - } - return mContext.getString(result); - } + private AddressWidgetUiComponentProvider componentProvider; - private String getAdminAreaFieldName(AddressVerificationNodeData countryNode) { - String adminLabelType = countryNode.get(AddressDataKey.STATE_NAME_TYPE); - Integer result = ADMIN_LABELS.get(adminLabelType); - if (result == null) { - // Fallback to province. - result = R.string.i18n_province; - } - return mContext.getString(result); - } - - private void buildCountryListBox() { - // Set up AddressField.COUNTRY - AddressUiComponent countryUi = new AddressUiComponent(AddressField.COUNTRY); - countryUi.setFieldName(mContext.getString(R.string.i18n_country_or_region_label)); - ArrayList countries = new ArrayList(); - for (RegionData regionData : mFormController.getRegionData(new LookupKey.Builder( - KeyType.DATA).build())) { - String regionKey = regionData.getKey(); - // ZZ represents an unknown region code. - if (!regionKey.equals("ZZ")) { - String localCountryName = getLocalCountryName(regionKey); - RegionData country = new RegionData.Builder().setKey(regionKey).setName( - localCountryName).build(); - countries.add(country); - } - } - countryUi.initializeCandidatesList(countries); - mInputWidgets.put(AddressField.COUNTRY, countryUi); - } + /** TODO: Add region-dependent width types for address fields. */ + private WidthType getFieldWidthType(AddressUiComponent field) { + return field.getId().getDefaulWidthType(); + } - private String getLocalCountryName(String regionCode) { - return (new Locale("", regionCode)).getDisplayCountry(Locale.getDefault()); + private void createView(ViewGroup rootView, AddressUiComponent field, String defaultKey, + boolean readOnly) { + @SuppressWarnings("deprecation") // FILL_PARENT renamed MATCH_PARENT in API Level 8. + LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(LayoutParams.FILL_PARENT, + LayoutParams.WRAP_CONTENT); + String fieldText = field.getFieldName(); + WidthType widthType = getFieldWidthType(field); + + if (fieldText.length() > 0) { + TextView textView = componentProvider.createUiLabel(fieldText, widthType); + rootView.addView(textView, lp); + } + if (field.getUiType().equals(UiComponent.EDIT)) { + EditText editText = componentProvider.createUiTextField(widthType); + field.setView(editText); + editText.setEnabled(!readOnly); + rootView.addView(editText, lp); + } else if (field.getUiType().equals(UiComponent.SPINNER)) { + ArrayAdapter adapter = componentProvider.createUiPickerAdapter(widthType); + Spinner spinner = componentProvider.createUiPickerSpinner(widthType); + + field.setView(spinner); + rootView.addView(spinner, lp); + spinner.setAdapter(adapter); + AddressSpinnerInfo spinnerInfo = + new AddressSpinnerInfo(spinner, field.getId(), field.getParentId()); + spinnerInfo.setSpinnerList(field.getCandidatesList(), defaultKey); + + if (fieldText.length() > 0) { + spinner.setPrompt(fieldText); + } + spinner.setOnItemSelectedListener(this); + spinners.add(spinnerInfo); + } + } + + /** + * Associates each field with its corresponding AddressUiComponent. + */ + private void buildFieldWidgets() { + AddressData data = new AddressData.Builder().setCountry(currentRegion).build(); + LookupKey key = new LookupKey.Builder(LookupKey.KeyType.DATA).setAddressData(data).build(); + AddressVerificationNodeData countryNode = + (new ClientData(cacheData)).getDefaultData(key.toString()); + + // Set up AddressField.ADMIN_AREA + AddressUiComponent adminAreaUi = new AddressUiComponent(AddressField.ADMIN_AREA); + adminAreaUi.setFieldName(getAdminAreaFieldName(countryNode)); + inputWidgets.put(AddressField.ADMIN_AREA, adminAreaUi); + + // Set up AddressField.LOCALITY + AddressUiComponent localityUi = new AddressUiComponent(AddressField.LOCALITY); + localityUi.setFieldName(getLocalityFieldName(countryNode)); + inputWidgets.put(AddressField.LOCALITY, localityUi); + + // Set up AddressField.DEPENDENT_LOCALITY + AddressUiComponent subLocalityUi = new AddressUiComponent(AddressField.DEPENDENT_LOCALITY); + subLocalityUi.setFieldName(getSublocalityFieldName(countryNode)); + inputWidgets.put(AddressField.DEPENDENT_LOCALITY, subLocalityUi); + + // Set up AddressField.ADDRESS_LINE_1 + AddressUiComponent addressLine1Ui = new AddressUiComponent(AddressField.ADDRESS_LINE_1); + addressLine1Ui.setFieldName(context.getString(R.string.i18n_address_line1_label)); + inputWidgets.put(AddressField.ADDRESS_LINE_1, addressLine1Ui); + + // Set up AddressField.ADDRESS_LINE_2 + AddressUiComponent addressLine2Ui = new AddressUiComponent(AddressField.ADDRESS_LINE_2); + addressLine2Ui.setFieldName(""); + inputWidgets.put(AddressField.ADDRESS_LINE_2, addressLine2Ui); + + // Set up AddressField.ORGANIZATION + AddressUiComponent organizationUi = new AddressUiComponent(AddressField.ORGANIZATION); + organizationUi.setFieldName(context.getString(R.string.i18n_organization_label)); + inputWidgets.put(AddressField.ORGANIZATION, organizationUi); + + // Set up AddressField.RECIPIENT + AddressUiComponent recipientUi = new AddressUiComponent(AddressField.RECIPIENT); + recipientUi.setFieldName(context.getString(R.string.i18n_recipient_label)); + inputWidgets.put(AddressField.RECIPIENT, recipientUi); + + // Set up AddressField.POSTAL_CODE + AddressUiComponent postalCodeUi = new AddressUiComponent(AddressField.POSTAL_CODE); + postalCodeUi.setFieldName(getZipFieldName(countryNode)); + inputWidgets.put(AddressField.POSTAL_CODE, postalCodeUi); + + // Set up AddressField.SORTING_CODE + AddressUiComponent sortingCodeUi = new AddressUiComponent(AddressField.SORTING_CODE); + sortingCodeUi.setFieldName("CEDEX"); + inputWidgets.put(AddressField.SORTING_CODE, sortingCodeUi); + } + + private void initializeDropDowns() { + AddressUiComponent adminAreaUi = inputWidgets.get(AddressField.ADMIN_AREA); + List adminAreaList = getRegionData(AddressField.COUNTRY); + adminAreaUi.initializeCandidatesList(adminAreaList); + + AddressUiComponent localityUi = inputWidgets.get(AddressField.LOCALITY); + List localityList = getRegionData(AddressField.ADMIN_AREA); + localityUi.initializeCandidatesList(localityList); + } + + // ZIP code is called postal code in some countries. This method returns the appropriate name + // for the given countryNode. + private String getZipFieldName(AddressVerificationNodeData countryNode) { + String zipName; + String zipType = countryNode.get(AddressDataKey.ZIP_NAME_TYPE); + if (zipType == null) { + zipLabel = ZipLabel.POSTAL; + zipName = context.getString(R.string.i18n_postal_code_label); + } else { + zipLabel = ZipLabel.ZIP; + zipName = context.getString(R.string.i18n_zip_code_label); + } + return zipName; + } + + private String getLocalityFieldName(AddressVerificationNodeData countryNode) { + String localityLabelType = countryNode.get(AddressDataKey.LOCALITY_NAME_TYPE); + Integer result = LOCALITY_LABELS.get(localityLabelType); + if (result == null) { + // Fallback to city. + result = R.string.i18n_locality_label; + } + return context.getString(result); + } + + private String getSublocalityFieldName(AddressVerificationNodeData countryNode) { + String sublocalityLabelType = countryNode.get(AddressDataKey.SUBLOCALITY_NAME_TYPE); + Integer result = SUBLOCALITY_LABELS.get(sublocalityLabelType); + if (result == null) { + // Fallback to suburb. + result = R.string.i18n_suburb; + } + return context.getString(result); + } + + private String getAdminAreaFieldName(AddressVerificationNodeData countryNode) { + String adminLabelType = countryNode.get(AddressDataKey.STATE_NAME_TYPE); + Integer result = ADMIN_LABELS.get(adminLabelType); + if (result == null) { + // Fallback to province. + result = R.string.i18n_province; + } + return context.getString(result); + } + + private void buildCountryListBox() { + // Set up AddressField.COUNTRY + AddressUiComponent countryUi = new AddressUiComponent(AddressField.COUNTRY); + countryUi.setFieldName(context.getString(R.string.i18n_country_or_region_label)); + ArrayList countries = new ArrayList(); + for (RegionData regionData : formController.getRegionData(new LookupKey.Builder( + KeyType.DATA).build())) { + String regionKey = regionData.getKey(); + // ZZ represents an unknown region code. + if (!regionKey.equals("ZZ")) { + String localCountryName = getLocalCountryName(regionKey); + RegionData country = new RegionData.Builder().setKey(regionKey).setName( + localCountryName).build(); + countries.add(country); + } } + countryUi.initializeCandidatesList(countries); + inputWidgets.put(AddressField.COUNTRY, countryUi); + } - private AddressSpinnerInfo findSpinnerByView(View view) { - for (AddressSpinnerInfo spinnerInfo : mSpinners) { - if (spinnerInfo.mView == view) { - return spinnerInfo; - } - } - return null; - } + private String getLocalCountryName(String regionCode) { + return (new Locale("", regionCode)).getDisplayCountry(Locale.getDefault()); + } - private void updateFields() { - removePreviousViews(); - buildFieldWidgets(); - initializeDropDowns(); - layoutAddressFields(); + private AddressSpinnerInfo findSpinnerByView(View view) { + for (AddressSpinnerInfo spinnerInfo : spinners) { + if (spinnerInfo.view == view) { + return spinnerInfo; + } } + return null; + } - private void removePreviousViews() { - if (mRootView == null) { - return; - } - int childCount = mRootView.getChildCount(); - if (mFormOptions.isHidden(AddressField.COUNTRY)) { - if (childCount > 0) { - mRootView.removeAllViews(); - } - } else if (childCount > 2) { - // Keep the TextView and Spinner for Country and remove everything else. - mRootView.removeViews(2, mRootView.getChildCount() - 2); - } - } + private void updateFields() { + removePreviousViews(); + buildFieldWidgets(); + initializeDropDowns(); + layoutAddressFields(); + } - private void layoutAddressFields() { - for (AddressField field : mFormatInterpreter.getAddressFieldOrder(mScript, - mCurrentRegion)) { - if (!mFormOptions.isHidden(field)) { - createView(mRootView, mInputWidgets.get(field), "", mFormOptions.isReadonly(field)); - } - } + private void removePreviousViews() { + if (rootView == null) { + return; } + int childCount = rootView.getChildCount(); + if (formOptions.isHidden(AddressField.COUNTRY)) { + if (childCount > 0) { + rootView.removeAllViews(); + } + } else if (childCount > 2) { + // Keep the TextView and Spinner for Country and remove everything else. + rootView.removeViews(2, rootView.getChildCount() - 2); + } + } - private void updateChildNodes(AdapterView parent, int position) { - AddressSpinnerInfo spinnerInfo = findSpinnerByView(parent); - if (spinnerInfo == null) { - return; - } - - // Find all the child spinners, if any, that depend on this one. - final AddressField myId = spinnerInfo.mId; - if (myId != AddressField.COUNTRY && myId != AddressField.ADMIN_AREA - && myId != AddressField.LOCALITY) { - // Only a change in the three AddressFields above will trigger a change in other - // AddressFields. Therefore, for all other AddressFields, we return immediately. - return; - } - - String regionCode = spinnerInfo.getRegionCode(position); - if (myId == AddressField.COUNTRY) { - updateWidgetOnCountryChange(regionCode); - return; - } - - mFormController.requestDataForAddress(getAddressData(), new DataLoadListener() { - @Override - public void dataLoadingBegin(){ - } + private void layoutAddressFields() { + for (AddressField field : formatInterpreter.getAddressFieldOrder(script, + currentRegion)) { + if (!formOptions.isHidden(field)) { + createView(rootView, inputWidgets.get(field), "", formOptions.isReadonly(field)); + } + } + } - @Override - public void dataLoadingEnd() { - Runnable updateChild = new UpdateRunnable(myId); - mHandler.post(updateChild); - } - }); + private void updateChildNodes(AdapterView parent, int position) { + AddressSpinnerInfo spinnerInfo = findSpinnerByView(parent); + if (spinnerInfo == null) { + return; } - public void updateWidgetOnCountryChange(String regionCode) { - if (mCurrentRegion.equalsIgnoreCase(regionCode)) { - return; - } - mCurrentRegion = regionCode; - mFormController.setCurrentCountry(mCurrentRegion); - renderForm(); + // Find all the child spinners, if any, that depend on this one. + final AddressField myId = spinnerInfo.id; + if (myId != AddressField.COUNTRY && myId != AddressField.ADMIN_AREA + && myId != AddressField.LOCALITY) { + // Only a change in the three AddressFields above will trigger a change in other + // AddressFields. Therefore, for all other AddressFields, we return immediately. + return; } - private void updateInputWidget(AddressField myId) { - for (AddressSpinnerInfo child : mSpinners) { - if (child.mParentId == myId) { - List candidates = getRegionData(child.mParentId); - child.setSpinnerList(candidates, ""); - } - } + String regionCode = spinnerInfo.getRegionCode(position); + if (myId == AddressField.COUNTRY) { + updateWidgetOnCountryChange(regionCode); + return; } - public void renderForm() { - setWidgetLocaleAndScript(); - AddressData data = new AddressData.Builder().setCountry(mCurrentRegion) - .setLanguageCode(mWidgetLocale).build(); - mFormController.requestDataForAddress(data, new DataLoadListener() { - @Override - public void dataLoadingBegin() { - mProgressDialog = mComponentProvider.getUiActivityIndicatorView(); - mProgressDialog.setMessage(mContext.getString(R.string.address_data_loading)); - Log.d(this.toString(), "Progress dialog started."); - } - @Override - public void dataLoadingEnd() { - Log.d(this.toString(), "Data loading completed."); - mProgressDialog.dismiss(); - Log.d(this.toString(), "Progress dialog stopped."); - mHandler.post(mUpdateMultipleFields); - } - }); - } - - private void setWidgetLocaleAndScript() { - mWidgetLocale = Util.getWidgetCompatibleLanguageCode(Locale.getDefault(), mCurrentRegion); - mFormController.setLanguageCode(mWidgetLocale); - mScript = Util.isExplicitLatinScript(mWidgetLocale) - ? ScriptType.LATIN - : ScriptType.LOCAL; - } - - private List getRegionData(AddressField parentField) { - AddressData address = getAddressData(); - - // Removes language code from address if it is default. This address is used to build - // lookup key, which neglects default language. For example, instead of "data/US--en/CA", - // the right lookup key is "data/US/CA". - if (mFormController.isDefaultLanguage(address.getLanguageCode())) { - address = new AddressData.Builder(address).setLanguageCode(null).build(); - } + formController.requestDataForAddress(getAddressData(), new DataLoadListener() { + @Override + public void dataLoadingBegin(){ + } - LookupKey parentKey = mFormController.getDataKeyFor(address).getKeyForUpperLevelField( - parentField); - List candidates; - // Can't build a key with parent field, quit. - if (parentKey == null) { - Log.w(this.toString(), "Can't build key with parent field " + parentField + ". One of" - + " the ancestor fields might be empty"); - - // Removes candidates that exist from previous settings. For example, data/US has a - // list of candidates AB, BC, CA, etc, that list should be cleaned up when user updates - // the address by changing country to Channel Islands. - candidates = new ArrayList(1); - } else { - candidates = mFormController.getRegionData(parentKey); - } - return candidates; - } - - /** - * Creates an AddressWidget to be attached to rootView for the specific context using the - * default UI component provider. - */ - public AddressWidget(Context context, ViewGroup rootView, FormOptions formOptions, - ClientCacheManager cacheManager) { - this(context, rootView, formOptions, cacheManager, - new AddressWidgetUiComponentProvider(context)); - } - - /** - * Creates an AddressWidget to be attached to rootView for the specific context using UI - * component provided by the provider. - */ - public AddressWidget(Context context, ViewGroup rootView, FormOptions formOptions, - ClientCacheManager cacheManager, AddressWidgetUiComponentProvider provider) { - mComponentProvider = provider; - mCurrentRegion = - ((TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE)) - .getSimCountryIso().toUpperCase(Locale.US); - if (mCurrentRegion.length() == 0) { - mCurrentRegion = "US"; - } - init(context, rootView, formOptions, cacheManager); - renderForm(); - } - - /** - * Creates an AddressWidget to be attached to rootView for the specific context using the - * default UI component provider, and fill out the address form with savedAddress. - */ - public AddressWidget(Context context, ViewGroup rootView, FormOptions formOptions, - ClientCacheManager cacheManager, AddressData savedAddress) { - this(context, rootView, formOptions, cacheManager, savedAddress, - new AddressWidgetUiComponentProvider(context)); - } - - /** - * Creates an AddressWidget to be attached to rootView for the specific context using UI - * component provided by the provider, and fill out the address form with savedAddress. - */ - public AddressWidget(Context context, ViewGroup rootView, FormOptions formOptions, - ClientCacheManager cacheManager, AddressData savedAddress, - AddressWidgetUiComponentProvider provider) { - mComponentProvider = provider; - mCurrentRegion = savedAddress.getPostalCountry(); - // Postal country must be 2 letter country code. Otherwise default to US. - if (mCurrentRegion == null || mCurrentRegion.length() != 2) { - mCurrentRegion = "US"; - } - init(context, rootView, formOptions, cacheManager); - renderFormWithSavedAddress(savedAddress); - } - - public void renderFormWithSavedAddress(AddressData savedAddress) { - setWidgetLocaleAndScript(); - removePreviousViews(); - buildFieldWidgets(); - layoutAddressFields(); - initializeFieldsWithAddress(savedAddress); - } - - private void initializeFieldsWithAddress(AddressData savedAddress) { - for (AddressField field : mFormatInterpreter.getAddressFieldOrder(mScript, - mCurrentRegion)) { - String value = savedAddress.getFieldValue(field); - if (value == null) { - value = ""; - } - AddressUiComponent uiComponent = mInputWidgets.get(field); - EditText view = (EditText) uiComponent.getView(); - if (view != null) { - view.setText(value); - } - } + @Override + public void dataLoadingEnd() { + Runnable updateChild = new UpdateRunnable(myId); + handler.post(updateChild); + } + }); + } + + public void updateWidgetOnCountryChange(String regionCode) { + if (currentRegion.equalsIgnoreCase(regionCode)) { + return; + } + currentRegion = regionCode; + formController.setCurrentCountry(currentRegion); + renderForm(); + } + + private void updateInputWidget(AddressField myId) { + for (AddressSpinnerInfo child : spinners) { + if (child.parentId == myId) { + List candidates = getRegionData(child.parentId); + child.setSpinnerList(candidates, ""); + } } - - private void init(Context context, ViewGroup rootView, FormOptions formOptions, - ClientCacheManager cacheManager) { - mContext = context; - mRootView = rootView; - mFormOptions = formOptions; - mCacheData = new CacheData(cacheManager); - mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); - mFormController = - new FormController(new ClientData(mCacheData), - mWidgetLocale, mCurrentRegion); - mFormatInterpreter = new FormatInterpreter(mFormOptions); - mVerifier = new StandardAddressVerifier( - new FieldVerifier(new ClientData(mCacheData))); - if (!formOptions.isHidden(AddressField.COUNTRY)) { - buildCountryListBox(); - createView(mRootView, mInputWidgets.get(AddressField.COUNTRY), - getLocalCountryName(mCurrentRegion), - formOptions.isReadonly(AddressField.COUNTRY)); - } + } + + public void renderForm() { + setWidgetLocaleAndScript(); + AddressData data = new AddressData.Builder().setCountry(currentRegion) + .setLanguageCode(widgetLocale).build(); + formController.requestDataForAddress(data, new DataLoadListener() { + @Override + public void dataLoadingBegin() { + progressDialog = componentProvider.getUiActivityIndicatorView(); + progressDialog.setMessage(context.getString(R.string.address_data_loading)); + Log.d(this.toString(), "Progress dialog started."); + } + @Override + public void dataLoadingEnd() { + Log.d(this.toString(), "Data loading completed."); + progressDialog.dismiss(); + Log.d(this.toString(), "Progress dialog stopped."); + handler.post(updateMultipleFields); + } + }); + } + + private void setWidgetLocaleAndScript() { + widgetLocale = Util.getWidgetCompatibleLanguageCode(Locale.getDefault(), currentRegion); + formController.setLanguageCode(widgetLocale); + script = Util.isExplicitLatinScript(widgetLocale) + ? ScriptType.LATIN + : ScriptType.LOCAL; + } + + private List getRegionData(AddressField parentField) { + AddressData address = getAddressData(); + + // Removes language code from address if it is default. This address is used to build + // lookup key, which neglects default language. For example, instead of "data/US--en/CA", + // the right lookup key is "data/US/CA". + if (formController.isDefaultLanguage(address.getLanguageCode())) { + address = new AddressData.Builder(address).setLanguageCode(null).build(); + } + + LookupKey parentKey = formController.getDataKeyFor(address).getKeyForUpperLevelField( + parentField); + List candidates; + // Can't build a key with parent field, quit. + if (parentKey == null) { + Log.w(this.toString(), "Can't build key with parent field " + parentField + ". One of" + + " the ancestor fields might be empty"); + + // Removes candidates that exist from previous settings. For example, data/US has a + // list of candidates AB, BC, CA, etc, that list should be cleaned up when user updates + // the address by changing country to Channel Islands. + candidates = new ArrayList(1); + } else { + candidates = formController.getRegionData(parentKey); + } + return candidates; + } + + /** + * Creates an AddressWidget to be attached to rootView for the specific context using the + * default UI component provider. + */ + public AddressWidget(Context context, ViewGroup rootView, FormOptions formOptions, + ClientCacheManager cacheManager) { + this(context, rootView, formOptions, cacheManager, + new AddressWidgetUiComponentProvider(context)); + } + + /** + * Creates an AddressWidget to be attached to rootView for the specific context using UI + * component provided by the provider. + */ + public AddressWidget(Context context, ViewGroup rootView, FormOptions formOptions, + ClientCacheManager cacheManager, AddressWidgetUiComponentProvider provider) { + componentProvider = provider; + currentRegion = + ((TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE)) + .getSimCountryIso().toUpperCase(Locale.US); + if (currentRegion.length() == 0) { + currentRegion = "US"; + } + init(context, rootView, formOptions, cacheManager); + renderForm(); + } + + /** + * Creates an AddressWidget to be attached to rootView for the specific context using the + * default UI component provider, and fill out the address form with savedAddress. + */ + public AddressWidget(Context context, ViewGroup rootView, FormOptions formOptions, + ClientCacheManager cacheManager, AddressData savedAddress) { + this(context, rootView, formOptions, cacheManager, savedAddress, + new AddressWidgetUiComponentProvider(context)); + } + + /** + * Creates an AddressWidget to be attached to rootView for the specific context using UI + * component provided by the provider, and fill out the address form with savedAddress. + */ + public AddressWidget(Context context, ViewGroup rootView, FormOptions formOptions, + ClientCacheManager cacheManager, AddressData savedAddress, + AddressWidgetUiComponentProvider provider) { + componentProvider = provider; + currentRegion = savedAddress.getPostalCountry(); + // Postal country must be 2 letter country code. Otherwise default to US. + if (currentRegion == null || currentRegion.length() != 2) { + currentRegion = "US"; + } + init(context, rootView, formOptions, cacheManager); + renderFormWithSavedAddress(savedAddress); + } + + public void renderFormWithSavedAddress(AddressData savedAddress) { + setWidgetLocaleAndScript(); + removePreviousViews(); + buildFieldWidgets(); + layoutAddressFields(); + initializeFieldsWithAddress(savedAddress); + } + + private void initializeFieldsWithAddress(AddressData savedAddress) { + for (AddressField field : formatInterpreter.getAddressFieldOrder(script, + currentRegion)) { + String value = savedAddress.getFieldValue(field); + if (value == null) { + value = ""; + } + AddressUiComponent uiComponent = inputWidgets.get(field); + EditText view = (EditText) uiComponent.getView(); + if (view != null) { + view.setText(value); + } } - - /** - * Sets address data server URL. Input URL cannot be null. - * - * @param url The service URL. - */ - public void setUrl(String url) { - mCacheData.setUrl(url); - } - - /** - * Gets user input address in AddressData format. - */ - public AddressData getAddressData() { - AddressData.Builder builder = new AddressData.Builder(); - builder.setCountry(mCurrentRegion); - for (AddressField field : mFormatInterpreter.getAddressFieldOrder(mScript, - mCurrentRegion)) { - AddressUiComponent addressUiComponent = mInputWidgets.get(field); - if (addressUiComponent != null) { - String value = addressUiComponent.getValue(); - if (addressUiComponent.getUiType() == UiComponent.SPINNER) { - // For drop-downs, return the key of the region selected instead of the value. - View view = getViewForField(field); - AddressSpinnerInfo spinnerInfo = findSpinnerByView(view); - if (spinnerInfo != null) { - value = spinnerInfo.getRegionDataKeyForValue(value); - } - } - builder.set(field, value); - } - } - builder.setLanguageCode(mWidgetLocale); - return builder.build(); - } - - /** - * Gets the formatted address. - * - * This method does not validate addresses. Also, it will "normalize" the result strings by - * removing redundant spaces and empty lines. - * - * @return the formatted address - */ - public List getEnvelopeAddress() { - return mFormatInterpreter.getEnvelopeAddress(getAddressData()); - } - - /** - * Gets the formatted address based on the AddressData passed in. - */ - public List getEnvelopeAddress(AddressData address) { - return mFormatInterpreter.getEnvelopeAddress(address); - } - - /** - * Gets the formatted address based on the AddressData passed in with none of the relevant - * fields hidden. - */ - public static List getFullEnvelopeAddress(AddressData address) { - return new FormatInterpreter(SHOW_ALL_FIELDS).getEnvelopeAddress(address); - } - - /** - * Get problems found in the address data entered by the user. - */ - public AddressProblems getAddressProblems() { - AddressProblems problems = new AddressProblems(); - AddressData addressData = getAddressData(); - mVerifier.verify(addressData, problems); - return problems; - } - - /** - * Displays an appropriate error message for an AddressField with a problem. - * - * @return the View object representing the AddressField. - */ - public View displayErrorMessageForField(AddressData address, - AddressField field, AddressProblemType problem) { - Log.d(this.toString(), "Display error message for the field: " + field.toString()); - AddressUiComponent addressUiComponent = mInputWidgets.get(field); - if (addressUiComponent != null && addressUiComponent.getUiType() == UiComponent.EDIT) { - EditText view = (EditText) addressUiComponent.getView(); - view.setError(getErrorMessageForInvalidEntry(address, field, problem)); - return view; - } - return null; - } - - private String getErrorMessageForInvalidEntry(AddressData address, AddressField field, - AddressProblemType problem) { - switch (problem) { - case MISSING_REQUIRED_FIELD: - return mContext.getString(R.string.i18n_missing_required_field); - case UNKNOWN_VALUE: - String currentValue = address.getFieldValue(field); - return String.format(mContext.getString(R.string.unknown_entry), currentValue); - case UNRECOGNIZED_FORMAT: - // We only support this error type for the Postal Code field. - return (mZipLabel == ZipLabel.POSTAL - ? mContext.getString(R.string.unrecognized_format_postal_code) - : mContext.getString(R.string.unrecognized_format_zip_code)); - case MISMATCHING_VALUE: - // We only support this error type for the Postal Code field. - return (mZipLabel == ZipLabel.POSTAL - ? mContext.getString(R.string.mismatching_value_postal_code) - : mContext.getString(R.string.mismatching_value_zip_code)); - } - return ""; + } + + private void init(Context context, ViewGroup rootView, FormOptions formOptions, + ClientCacheManager cacheManager) { + context = context; + rootView = rootView; + formOptions = formOptions; + cacheData = new CacheData(cacheManager); + inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); + formController = + new FormController(new ClientData(cacheData), + widgetLocale, currentRegion); + formatInterpreter = new FormatInterpreter(formOptions); + verifier = new StandardAddressVerifier( + new FieldVerifier(new ClientData(cacheData))); + if (!formOptions.isHidden(AddressField.COUNTRY)) { + buildCountryListBox(); + createView(rootView, inputWidgets.get(AddressField.COUNTRY), + getLocalCountryName(currentRegion), + formOptions.isReadonly(AddressField.COUNTRY)); + } + } + + /** + * Sets address data server URL. Input URL cannot be null. + * + * @param url The service URL. + */ + public void setUrl(String url) { + cacheData.setUrl(url); + } + + /** + * Gets user input address in AddressData format. + */ + public AddressData getAddressData() { + AddressData.Builder builder = new AddressData.Builder(); + builder.setCountry(currentRegion); + for (AddressField field : formatInterpreter.getAddressFieldOrder(script, + currentRegion)) { + AddressUiComponent addressUiComponent = inputWidgets.get(field); + if (addressUiComponent != null) { + String value = addressUiComponent.getValue(); + if (addressUiComponent.getUiType() == UiComponent.SPINNER) { + // For drop-downs, return the key of the region selected instead of the value. + View view = getViewForField(field); + AddressSpinnerInfo spinnerInfo = findSpinnerByView(view); + if (spinnerInfo != null) { + value = spinnerInfo.getRegionDataKeyForValue(value); + } + } + builder.set(field, value); + } } - - /** - * Clears all error messages in the UI. - */ - public void clearErrorMessage() { - for (AddressField field : mFormatInterpreter.getAddressFieldOrder(mScript, - mCurrentRegion)) { - AddressUiComponent addressUiComponent = mInputWidgets.get(field); - - if (addressUiComponent != null && addressUiComponent.getUiType() == UiComponent.EDIT) { - EditText view = (EditText) addressUiComponent.getView(); - if (view != null) { - view.setError(null); - } - } + builder.setLanguageCode(widgetLocale); + return builder.build(); + } + + /** + * Gets the formatted address. + * + * This method does not validate addresses. Also, it will "normalize" the result strings by + * removing redundant spaces and empty lines. + * + * @return the formatted address + */ + public List getEnvelopeAddress() { + return formatInterpreter.getEnvelopeAddress(getAddressData()); + } + + /** + * Gets the formatted address based on the AddressData passed in. + */ + public List getEnvelopeAddress(AddressData address) { + return formatInterpreter.getEnvelopeAddress(address); + } + + /** + * Gets the formatted address based on the AddressData passed in with none of the relevant + * fields hidden. + */ + public static List getFullEnvelopeAddress(AddressData address) { + return new FormatInterpreter(SHOW_ALL_FIELDS).getEnvelopeAddress(address); + } + + /** + * Get problems found in the address data entered by the user. + */ + public AddressProblems getAddressProblems() { + AddressProblems problems = new AddressProblems(); + AddressData addressData = getAddressData(); + verifier.verify(addressData, problems); + return problems; + } + + /** + * Displays an appropriate error message for an AddressField with a problem. + * + * @return the View object representing the AddressField. + */ + public View displayErrorMessageForField(AddressData address, + AddressField field, AddressProblemType problem) { + Log.d(this.toString(), "Display error message for the field: " + field.toString()); + AddressUiComponent addressUiComponent = inputWidgets.get(field); + if (addressUiComponent != null && addressUiComponent.getUiType() == UiComponent.EDIT) { + EditText view = (EditText) addressUiComponent.getView(); + view.setError(getErrorMessageForInvalidEntry(address, field, problem)); + return view; + } + return null; + } + + private String getErrorMessageForInvalidEntry(AddressData address, AddressField field, + AddressProblemType problem) { + switch (problem) { + case MISSING_REQUIRED_FIELD: + return context.getString(R.string.i18n_missing_required_field); + case UNKNOWN_VALUE: + String currentValue = address.getFieldValue(field); + return String.format(context.getString(R.string.unknown_entry), currentValue); + case UNRECOGNIZED_FORMAT: + // We only support this error type for the Postal Code field. + return (zipLabel == ZipLabel.POSTAL + ? context.getString(R.string.unrecognized_format_postal_code) + : context.getString(R.string.unrecognized_format_zip_code)); + case MISMATCHING_VALUE: + // We only support this error type for the Postal Code field. + return (zipLabel == ZipLabel.POSTAL + ? context.getString(R.string.mismatching_value_postal_code) + : context.getString(R.string.mismatching_value_zip_code)); + } + return ""; + } + + /** + * Clears all error messages in the UI. + */ + public void clearErrorMessage() { + for (AddressField field : formatInterpreter.getAddressFieldOrder(script, + currentRegion)) { + AddressUiComponent addressUiComponent = inputWidgets.get(field); + + if (addressUiComponent != null && addressUiComponent.getUiType() == UiComponent.EDIT) { + EditText view = (EditText) addressUiComponent.getView(); + if (view != null) { + view.setError(null); } - } - - public View getViewForField(AddressField field) { - AddressUiComponent component = mInputWidgets.get(field); - if (component == null) { - return null; } - return component.getView(); } + } - @Override - public void onNothingSelected(AdapterView arg0) { + public View getViewForField(AddressField field) { + AddressUiComponent component = inputWidgets.get(field); + if (component == null) { + return null; } + return component.getView(); + } - @Override - public void onItemSelected(AdapterView parent, View view, int position, long id) { - updateChildNodes(parent, position); - } + @Override + public void onNothingSelected(AdapterView arg0) { + } + + @Override + public void onItemSelected(AdapterView parent, View view, int position, long id) { + updateChildNodes(parent, position); + } } diff --git a/java/src/com/android/i18n/addressinput/AddressWidgetUiComponentProvider.java b/java/src/com/android/i18n/addressinput/AddressWidgetUiComponentProvider.java index 9f5a350..670c6c6 100644 --- a/java/src/com/android/i18n/addressinput/AddressWidgetUiComponentProvider.java +++ b/java/src/com/android/i18n/addressinput/AddressWidgetUiComponentProvider.java @@ -37,63 +37,63 @@ import com.android.i18n.addressinput.AddressField.WidthType; * alongside the address widget. */ public class AddressWidgetUiComponentProvider { - protected Context mContext; - protected LayoutInflater mInflater; + protected Context context; + protected LayoutInflater inflater; - public AddressWidgetUiComponentProvider(Context context) { - mContext = context; - mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); - } + public AddressWidgetUiComponentProvider(Context context) { + context = context; + inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); + } - /** - * Creates a label, e.g. "State", for an address input field. - * - * @param label the label of the address input field - * @param widthType {@link WidthType} of the field - * @return a custom {@link TextView} created for the field - */ - protected TextView createUiLabel(CharSequence label, WidthType widthType) { - TextView textView = (TextView) mInflater.inflate(R.layout.address_textview, null, false); - textView.setText(label); - return textView; - } + /** + * Creates a label, e.g. "State", for an address input field. + * + * @param label the label of the address input field + * @param widthType {@link WidthType} of the field + * @return a custom {@link TextView} created for the field + */ + protected TextView createUiLabel(CharSequence label, WidthType widthType) { + TextView textView = (TextView) inflater.inflate(R.layout.address_textview, null, false); + textView.setText(label); + return textView; + } - /** - * Creates a text input view for an address input field. - * - * @param widthType {@link WidthType} of the field - * @return a custom {@link EditText} created for the field - */ - protected EditText createUiTextField(WidthType widthType) { - return (EditText) mInflater.inflate(R.layout.address_edittext, null, false); - } + /** + * Creates a text input view for an address input field. + * + * @param widthType {@link WidthType} of the field + * @return a custom {@link EditText} created for the field + */ + protected EditText createUiTextField(WidthType widthType) { + return (EditText) inflater.inflate(R.layout.address_edittext, null, false); + } - /** - * Creates a {@link Spinner} for a input field that uses UI picker. - * - * @param widthType {@link WidthType} of the field - * @return a custom {@link Spinner} created for the field - */ - protected Spinner createUiPickerSpinner(WidthType widthType) { - return (Spinner) mInflater.inflate(R.layout.address_spinner, null, false); - } + /** + * Creates a {@link Spinner} for a input field that uses UI picker. + * + * @param widthType {@link WidthType} of the field + * @return a custom {@link Spinner} created for the field + */ + protected Spinner createUiPickerSpinner(WidthType widthType) { + return (Spinner) inflater.inflate(R.layout.address_spinner, null, false); + } - /** - * Creates an {@link ArrayAdapter} to work with the custom {@link Spinner} of a input field that - * uses UI picker. - * - * @param widthType {@link WidthType} of the field - * @return a custom {@link ArrayAdapter} for the field - */ - protected ArrayAdapter createUiPickerAdapter(WidthType widthType) { - ArrayAdapter adapter = - new ArrayAdapter(mContext, android.R.layout.simple_spinner_item); - adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); - return adapter; - } + /** + * Creates an {@link ArrayAdapter} to work with the custom {@link Spinner} of a input field that + * uses UI picker. + * + * @param widthType {@link WidthType} of the field + * @return a custom {@link ArrayAdapter} for the field + */ + protected ArrayAdapter createUiPickerAdapter(WidthType widthType) { + ArrayAdapter adapter = + new ArrayAdapter(context, android.R.layout.simple_spinner_item); + adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); + return adapter; + } - /** Gets an activity indicator to show that a task is in progress. */ - protected ProgressDialog getUiActivityIndicatorView() { - return new ProgressDialog(mContext); - } + /** Gets an activity indicator to show that a task is in progress. */ + protected ProgressDialog getUiActivityIndicatorView() { + return new ProgressDialog(context); + } } diff --git a/java/src/com/android/i18n/addressinput/CacheData.java b/java/src/com/android/i18n/addressinput/CacheData.java index 4f98e6f..39942c9 100644 --- a/java/src/com/android/i18n/addressinput/CacheData.java +++ b/java/src/com/android/i18n/addressinput/CacheData.java @@ -34,385 +34,385 @@ import java.util.HashSet; */ public final class CacheData { - /** - * Used to identify the source of a log message. - */ - private static final String TAG = "CacheData"; - - /** - * Time out value for the server to respond in millisecond. - */ - private static final int TIMEOUT = 5000; - - /** - * URL to get address data. You can also reset it by calling {@link #setUrl(String)}. - */ - private String mServiceUrl; - - /** - * Storage for all dynamically retrieved data. - */ - private final JsoMap mCache; - - /** - * CacheManager that handles caching that is needed by the client of the Address Widget. - */ - private final ClientCacheManager mClientCacheManager; - - /** - * All requests that have been sent. - */ - private final HashSet mRequestedKeys = new HashSet(); - - /** - * All invalid requested keys. For example, if we request a random string "asdfsdf9o", and the - * server responds by saying this key is invalid, it will be stored here. - */ - private final HashSet mBadKeys = new HashSet(); - - /** - * Temporary store for {@code CacheListener}s. When a key is requested and still waiting for - * server's response, the listeners for the same key will be temporary stored here. When the - * server responded, these listeners will be triggered and then removed. - */ - private final HashMap> mTemporaryListenerStore = - new HashMap>(); - - /** - * Creates an instance of CacheData with an empty cache, and uses no caching that is external - * to the AddressWidget. - */ - public CacheData() { - this(new SimpleClientCacheManager()); + /** + * Used to identify the source of a log message. + */ + private static final String TAG = "CacheData"; + + /** + * Time out value for the server to respond in millisecond. + */ + private static final int TIMEOUT = 5000; + + /** + * URL to get address data. You can also reset it by calling {@link #setUrl(String)}. + */ + private String serviceUrl; + + /** + * Storage for all dynamically retrieved data. + */ + private final JsoMap cache; + + /** + * CacheManager that handles caching that is needed by the client of the Address Widget. + */ + private final ClientCacheManager clientCacheManager; + + /** + * All requests that have been sent. + */ + private final HashSet requestedKeys = new HashSet(); + + /** + * All invalid requested keys. For example, if we request a random string "asdfsdf9o", and the + * server responds by saying this key is invalid, it will be stored here. + */ + private final HashSet badKeys = new HashSet(); + + /** + * Temporary store for {@code CacheListener}s. When a key is requested and still waiting for + * server's response, the listeners for the same key will be temporary stored here. When the + * server responded, these listeners will be triggered and then removed. + */ + private final HashMap> temporaryListenerStore = + new HashMap>(); + + /** + * Creates an instance of CacheData with an empty cache, and uses no caching that is external + * to the AddressWidget. + */ + public CacheData() { + this(new SimpleClientCacheManager()); + } + + /** + * Creates an instance of CacheData with an empty cache, and uses additional caching (external + * to the AddressWidget) specified by clientCacheManager. + */ + public CacheData(ClientCacheManager clientCacheManager) { + this.clientCacheManager = clientCacheManager; + setUrl(clientCacheManager.getAddressServerUrl()); + cache = JsoMap.createEmptyJsoMap(); + } + + /** + * This constructor is meant to be used together with external caching. + * + * Use case: + * + * After having finished using the address widget: + * String allCachedData = getJsonString(); + * Cache (save) allCachedData wherever makes sense for your service / activity + * + * Before using it next time: + * Get the saved allCachedData string + * new ClientData(new CacheData(allCachedData)) + * + * If you don't have any saved data you can either just pass an empty string to + * this constructor or use the other constructor. + * + * @param jsonString cached data from last time the class was used + */ + public CacheData(String jsonString) { + clientCacheManager = new SimpleClientCacheManager(); + setUrl(clientCacheManager.getAddressServerUrl()); + JsoMap tempMap = null; + try { + tempMap = JsoMap.buildJsoMap(jsonString); + } catch (JSONException jsonE) { + // If parsing the JSON string throws an exception, default to + // starting with an empty cache. + Log.w(TAG, "Could not parse json string, creating empty cache instead."); + tempMap = JsoMap.createEmptyJsoMap(); + } finally { + cache = tempMap; } + } - /** - * Creates an instance of CacheData with an empty cache, and uses additional caching (external - * to the AddressWidget) specified by clientCacheManager. - */ - public CacheData(ClientCacheManager clientCacheManager) { - mClientCacheManager = clientCacheManager; - setUrl(mClientCacheManager.getAddressServerUrl()); - mCache = JsoMap.createEmptyJsoMap(); - } + /** + * Interface for all listeners to {@link CacheData} change. This is only used when multiple + * requests of the same key is dispatched and server has not responded yet. + */ + private static interface CacheListener extends EventListener { /** - * This constructor is meant to be used together with external caching. - * - * Use case: - * - * After having finished using the address widget: - * String allCachedData = getJsonString(); - * Cache (save) allCachedData wherever makes sense for your service / activity - * - * Before using it next time: - * Get the saved allCachedData string - * new ClientData(new CacheData(allCachedData)) - * - * If you don't have any saved data you can either just pass an empty string to - * this constructor or use the other constructor. + * The function that will be called when valid data is about to be put in the cache. * - * @param jsonString cached data from last time the class was used + * @param key the key for newly arrived data. */ - public CacheData(String jsonString) { - mClientCacheManager = new SimpleClientCacheManager(); - setUrl(mClientCacheManager.getAddressServerUrl()); - JsoMap tempMap = null; - try { - tempMap = JsoMap.buildJsoMap(jsonString); - } catch (JSONException jsonE) { - // If parsing the JSON string throws an exception, default to - // starting with an empty cache. - Log.w(TAG, "Could not parse json string, creating empty cache instead."); - tempMap = JsoMap.createEmptyJsoMap(); - } finally { - mCache = tempMap; - } - } + void onAdd(String key); + } - /** - * Interface for all listeners to {@link CacheData} change. This is only used when multiple - * requests of the same key is dispatched and server has not responded yet. - */ - private static interface CacheListener extends EventListener { - - /** - * The function that will be called when valid data is about to be put in the cache. - * - * @param key the key for newly arrived data. - */ - void onAdd(String key); - } + /** + * Class to handle JSON response. + */ + private class JsonHandler { /** - * Class to handle JSON response. + * Key for the requested data. */ - private class JsonHandler { - - /** - * Key for the requested data. - */ - private final String mKey; - - /** - * Pre-existing data for the requested key. Null is allowed. - */ - private final JSONObject mExistingJso; - - private final DataLoadListener mListener; - - /** - * Constructs a JsonHandler instance. - * - * @param key The key for requested data. - * @param oldJso Pre-existing data for this key or null. - */ - private JsonHandler(String key, JSONObject oldJso, DataLoadListener listener) { - checkNotNull(key); - mKey = key; - mExistingJso = oldJso; - mListener = listener; - } - - /** - * Saves valid responded data to the cache once data arrives, or if the key is invalid, - * saves it in the invalid cache. If there is pre-existing data for the key, it will merge - * the new data will the old one. It also triggers {@link DataLoadListener#dataLoadingEnd()} - * method before it returns (even when the key is invalid, or input jso is null). This is - * called from a background thread. - * - * @param map The received JSON data as a map. - */ - private void handleJson(JsoMap map) { - // Can this ever happen? - if (map == null) { - Log.w(TAG, "server returns null for key:" + mKey); - mBadKeys.add(mKey); - notifyListenersAfterJobDone(mKey); - triggerDataLoadingEndIfNotNull(mListener); - return; - } - - JSONObject json = map; - String idKey = AddressDataKey.ID.name().toLowerCase(); - if (!json.has(idKey)) { - Log.w(TAG, "invalid or empty data returned for key: " + mKey); - mBadKeys.add(mKey); - notifyListenersAfterJobDone(mKey); - triggerDataLoadingEndIfNotNull(mListener); - return; - } - - if (mExistingJso != null) { - map.mergeData((JsoMap) mExistingJso); - } - - mCache.putObj(mKey, map); - notifyListenersAfterJobDone(mKey); - triggerDataLoadingEndIfNotNull(mListener); - } - } + private final String key; /** - * Sets address data server URL. Input URL cannot be null. - * - * @param url The service URL. + * Pre-existing data for the requested key. Null is allowed. */ - public void setUrl(String url) { - checkNotNull(url, "Cannot set URL of address data server to null."); - mServiceUrl = url; - } + private final JSONObject existingJso; - /** - * Gets address data server URL. - */ - public String getUrl() { - return mServiceUrl; - } + private final DataLoadListener listener; /** - * Returns a JSON string representing the data currently stored in this cache. It can be used - * to later create a new CacheData object containing the same cached data. + * Constructs a JsonHandler instance. * - * @return a JSON string representing the data stored in this cache + * @param key The key for requested data. + * @param oldJso Pre-existing data for this key or null. */ - public String getJsonString() { - return mCache.toString(); - } - - /** - * Checks if key and its value is cached (Note that only valid ones are cached). - */ - public boolean containsKey(String key) { - return mCache.containsKey(key); - } - - // This method is called from a background thread. - private void triggerDataLoadingEndIfNotNull(DataLoadListener listener) { - if (listener != null) { - listener.dataLoadingEnd(); - } + private JsonHandler(String key, JSONObject oldJso, DataLoadListener listener) { + checkNotNull(key); + this.key = key; + this.existingJso = oldJso; + this.listener = listener; } /** - * Fetches data from server, or returns if the data is already cached. If the fetched data is - * valid, it will be added to the cache. This method also triggers {@link - * DataLoadListener#dataLoadingEnd()} method before it returns. + * Saves valid responded data to the cache once data arrives, or if the key is invalid, + * saves it in the invalid cache. If there is pre-existing data for the key, it will merge + * the new data will the old one. It also triggers {@link DataLoadListener#dataLoadingEnd()} + * method before it returns (even when the key is invalid, or input jso is null). This is + * called from a background thread. * - * @param existingJso Pre-existing data for this key or null if none. - * @param listener An optional listener to call when done. + * @param map The received JSON data as a map. */ - void fetchDynamicData(final LookupKey key, JSONObject existingJso, - final DataLoadListener listener) { - checkNotNull(key, "null key not allowed."); - - if (listener != null) { - listener.dataLoadingBegin(); - } - - // Key is valid and cached. - if (mCache.containsKey(key.toString())) { - triggerDataLoadingEndIfNotNull(listener); - return; - } - - // Key is invalid and cached. - if (mBadKeys.contains(key.toString())) { - triggerDataLoadingEndIfNotNull(listener); - return; - } - - // Already requested the key, and is still waiting for server's response. - if (!mRequestedKeys.add(key.toString())) { - Log.d(TAG, "data for key " + key + " requested but not cached yet"); - addListenerToTempStore(key, new CacheListener() { - @Override - public void onAdd(String myKey) { - triggerDataLoadingEndIfNotNull(listener); - } - }); - return; - } - - // Key is in the cache maintained by the client of the AddressWidget. - String dataFromClientCache = mClientCacheManager.get(key.toString()); - if (dataFromClientCache != null && dataFromClientCache.length() > 0) { - final JsonHandler handler = new JsonHandler(key.toString(), - existingJso, listener); - try { - handler.handleJson(JsoMap.buildJsoMap(dataFromClientCache)); - return; - } catch (JSONException e) { - Log.w(TAG, "Data from client's cache is in the wrong format: " - + dataFromClientCache); - } - } - - // Key is not cached yet, now sending the request to the server. - JsonpRequestBuilder jsonp = new JsonpRequestBuilder(); - jsonp.setTimeout(TIMEOUT); - final JsonHandler handler = new JsonHandler(key.toString(), - existingJso, listener); - jsonp.requestObject(mServiceUrl + "/" + key.toString(), - new AsyncCallback() { - @Override - public void onFailure(Throwable caught) { - Log.w(TAG, "Request for key " + key + " failed"); - mRequestedKeys.remove(key.toString()); - notifyListenersAfterJobDone(key.toString()); - triggerDataLoadingEndIfNotNull(listener); - } - - @Override - public void onSuccess(JsoMap result) { - handler.handleJson(result); - // Put metadata into the cache maintained by the client of the - // AddressWidget. - String dataRetrieved = result.toString(); - mClientCacheManager.put(key.toString(), dataRetrieved); - } - }); + private void handleJson(JsoMap map) { + // Can this ever happen? + if (map == null) { + Log.w(TAG, "server returns null for key:" + key); + badKeys.add(key); + notifyListenersAfterJobDone(key); + triggerDataLoadingEndIfNotNull(listener); + return; + } + + JSONObject json = map; + String idKey = AddressDataKey.ID.name().toLowerCase(); + if (!json.has(idKey)) { + Log.w(TAG, "invalid or empty data returned for key: " + key); + badKeys.add(key); + notifyListenersAfterJobDone(key); + triggerDataLoadingEndIfNotNull(listener); + return; + } + + if (existingJso != null) { + map.mergeData((JsoMap) existingJso); + } + + cache.putObj(key, map); + notifyListenersAfterJobDone(key); + triggerDataLoadingEndIfNotNull(listener); } - - /** - * Gets region data from our compiled-in java file and stores it in the - * cache. This is only called when data cannot be obtained from the server, - * so there will be no pre-existing data for this key. - */ - void getFromRegionDataConstants(final LookupKey key) { - checkNotNull(key, "null key not allowed."); - String data = RegionDataConstants.getCountryFormatMap().get( - key.getValueForUpperLevelField(AddressField.COUNTRY)); - if (data != null) { - try { - mCache.putObj(key.toString(), JsoMap.buildJsoMap(data)); - } catch (JSONException e) { - Log.w(TAG, "Failed to parse data for key " + key + - " from RegionDataConstants"); - } - } + } + + /** + * Sets address data server URL. Input URL cannot be null. + * + * @param url The service URL. + */ + public void setUrl(String url) { + checkNotNull(url, "Cannot set URL of address data server to null."); + serviceUrl = url; + } + + /** + * Gets address data server URL. + */ + public String getUrl() { + return serviceUrl; + } + + /** + * Returns a JSON string representing the data currently stored in this cache. It can be used + * to later create a new CacheData object containing the same cached data. + * + * @return a JSON string representing the data stored in this cache + */ + public String getJsonString() { + return cache.toString(); + } + + /** + * Checks if key and its value is cached (Note that only valid ones are cached). + */ + public boolean containsKey(String key) { + return cache.containsKey(key); + } + + // This method is called from a background thread. + private void triggerDataLoadingEndIfNotNull(DataLoadListener listener) { + if (listener != null) { + listener.dataLoadingEnd(); } - - /** - * Retrieves string data identified by key. - * - * @param key Non-null key. E.g., "data/US/CA". - * @return String value for specified key. - */ - public String get(String key) { - checkNotNull(key, "null key not allowed"); - return mCache.get(key); + } + + /** + * Fetches data from server, or returns if the data is already cached. If the fetched data is + * valid, it will be added to the cache. This method also triggers {@link + * DataLoadListener#dataLoadingEnd()} method before it returns. + * + * @param existingJso Pre-existing data for this key or null if none. + * @param listener An optional listener to call when done. + */ + void fetchDynamicData(final LookupKey key, JSONObject existingJso, + final DataLoadListener listener) { + checkNotNull(key, "null key not allowed."); + + if (listener != null) { + listener.dataLoadingBegin(); } - /** - * Retrieves JsoMap data identified by key. - * - * @param key Non-null key. E.g., "data/US/CA". - * @return String value for specified key. - */ - public JsoMap getObj(String key) { - checkNotNull(key, "null key not allowed"); - return mCache.getObj(key); + // Key is valid and cached. + if (cache.containsKey(key.toString())) { + triggerDataLoadingEndIfNotNull(listener); + return; } - private void notifyListenersAfterJobDone(String key) { - LookupKey lookupKey = new LookupKey.Builder(key).build(); - HashSet listeners = mTemporaryListenerStore.get(lookupKey); - if (listeners != null) { - for (CacheListener listener : listeners) { - listener.onAdd(key.toString()); - } - listeners.clear(); - } + // Key is invalid and cached. + if (badKeys.contains(key.toString())) { + triggerDataLoadingEndIfNotNull(listener); + return; } - private void addListenerToTempStore(LookupKey key, CacheListener listener) { - checkNotNull(key); - checkNotNull(listener); - HashSet listeners = mTemporaryListenerStore.get(key); - if (listeners == null) { - listeners = new HashSet(); - mTemporaryListenerStore.put(key, listeners); + // Already requested the key, and is still waiting for server's response. + if (!requestedKeys.add(key.toString())) { + Log.d(TAG, "data for key " + key + " requested but not cached yet"); + addListenerToTempStore(key, new CacheListener() { + @Override + public void onAdd(String myKey) { + triggerDataLoadingEndIfNotNull(listener); } - listeners.add(listener); + }); + return; } - /** - * Added for testing purposes. - * Adds a new object into the cache. - * @param id string of the format "data/country/.." ie. "data/US/CA" - * @param object The JSONObject to be put into cache. - */ - void addToJsoMap(String id, JSONObject object) { - mCache.putObj(id, object); + // Key is in the cache maintained by the client of the AddressWidget. + String dataFromClientCache = clientCacheManager.get(key.toString()); + if (dataFromClientCache != null && dataFromClientCache.length() > 0) { + final JsonHandler handler = new JsonHandler(key.toString(), + existingJso, listener); + try { + handler.handleJson(JsoMap.buildJsoMap(dataFromClientCache)); + return; + } catch (JSONException e) { + Log.w(TAG, "Data from client's cache is in the wrong format: " + + dataFromClientCache); + } } - /** - * Added for testing purposes. - * Checks to see if the cache is empty, - * @return true if the internal cache is empty - */ - boolean isEmpty() { - return mCache.length() == 0; + // Key is not cached yet, now sending the request to the server. + JsonpRequestBuilder jsonp = new JsonpRequestBuilder(); + jsonp.setTimeout(TIMEOUT); + final JsonHandler handler = new JsonHandler(key.toString(), + existingJso, listener); + jsonp.requestObject(serviceUrl + "/" + key.toString(), + new AsyncCallback() { + @Override + public void onFailure(Throwable caught) { + Log.w(TAG, "Request for key " + key + " failed"); + requestedKeys.remove(key.toString()); + notifyListenersAfterJobDone(key.toString()); + triggerDataLoadingEndIfNotNull(listener); + } + + @Override + public void onSuccess(JsoMap result) { + handler.handleJson(result); + // Put metadata into the cache maintained by the client of the + // AddressWidget. + String dataRetrieved = result.toString(); + clientCacheManager.put(key.toString(), dataRetrieved); + } + }); + } + + /** + * Gets region data from our compiled-in java file and stores it in the + * cache. This is only called when data cannot be obtained from the server, + * so there will be no pre-existing data for this key. + */ + void getFromRegionDataConstants(final LookupKey key) { + checkNotNull(key, "null key not allowed."); + String data = RegionDataConstants.getCountryFormatMap().get( + key.getValueForUpperLevelField(AddressField.COUNTRY)); + if (data != null) { + try { + cache.putObj(key.toString(), JsoMap.buildJsoMap(data)); + } catch (JSONException e) { + Log.w(TAG, "Failed to parse data for key " + key + + " from RegionDataConstants"); + } + } + } + + /** + * Retrieves string data identified by key. + * + * @param key Non-null key. E.g., "data/US/CA". + * @return String value for specified key. + */ + public String get(String key) { + checkNotNull(key, "null key not allowed"); + return cache.get(key); + } + + /** + * Retrieves JsoMap data identified by key. + * + * @param key Non-null key. E.g., "data/US/CA". + * @return String value for specified key. + */ + public JsoMap getObj(String key) { + checkNotNull(key, "null key not allowed"); + return cache.getObj(key); + } + + private void notifyListenersAfterJobDone(String key) { + LookupKey lookupKey = new LookupKey.Builder(key).build(); + HashSet listeners = temporaryListenerStore.get(lookupKey); + if (listeners != null) { + for (CacheListener listener : listeners) { + listener.onAdd(key.toString()); + } + listeners.clear(); + } + } + + private void addListenerToTempStore(LookupKey key, CacheListener listener) { + checkNotNull(key); + checkNotNull(listener); + HashSet listeners = temporaryListenerStore.get(key); + if (listeners == null) { + listeners = new HashSet(); + temporaryListenerStore.put(key, listeners); } + listeners.add(listener); + } + + /** + * Added for testing purposes. + * Adds a new object into the cache. + * @param id string of the format "data/country/.." ie. "data/US/CA" + * @param object The JSONObject to be put into cache. + */ + void addToJsoMap(String id, JSONObject object) { + cache.putObj(id, object); + } + + /** + * Added for testing purposes. + * Checks to see if the cache is empty, + * @return true if the internal cache is empty + */ + boolean isEmpty() { + return cache.length() == 0; + } } diff --git a/java/src/com/android/i18n/addressinput/ClientCacheManager.java b/java/src/com/android/i18n/addressinput/ClientCacheManager.java index 0ee1816..8c2c312 100644 --- a/java/src/com/android/i18n/addressinput/ClientCacheManager.java +++ b/java/src/com/android/i18n/addressinput/ClientCacheManager.java @@ -20,10 +20,10 @@ package com.android.i18n.addressinput; * Used by AddressWidget to handle caching in client-specific ways. */ public interface ClientCacheManager { - /** Get the data that is cached for the given key. */ - public String get(String key); - /** Put the data for the given key into the cache. */ - public void put(String key, String data); - /** Get the Url of the server that serves address metadata. */ - public String getAddressServerUrl(); + /** Get the data that is cached for the given key. */ + public String get(String key); + /** Put the data for the given key into the cache. */ + public void put(String key, String data); + /** Get the Url of the server that serves address metadata. */ + public String getAddressServerUrl(); } diff --git a/java/src/com/android/i18n/addressinput/ClientData.java b/java/src/com/android/i18n/addressinput/ClientData.java index f0b2fc0..8e23f3a 100644 --- a/java/src/com/android/i18n/addressinput/ClientData.java +++ b/java/src/com/android/i18n/addressinput/ClientData.java @@ -35,264 +35,264 @@ import java.util.Set; */ public class ClientData implements DataSource { - private static final String TAG = "ClientData"; - - /** - * Data to bootstrap the process. The data are all regional (country level) - * data. Keys are like "data/US/CA" - */ - private final Map mBootstrapMap = new HashMap(); - - private CacheData mCacheData; - - public ClientData(CacheData cacheData) { - this.mCacheData = cacheData; - buildRegionalData(); + private static final String TAG = "ClientData"; + + /** + * Data to bootstrap the process. The data are all regional (country level) + * data. Keys are like "data/US/CA" + */ + private final Map bootstrapMap = new HashMap(); + + private CacheData cacheData; + + public ClientData(CacheData cacheData) { + this.cacheData = cacheData; + buildRegionalData(); + } + + @Override + public AddressVerificationNodeData get(String key) { + JsoMap jso = cacheData.getObj(key); + if (jso == null) { // Not cached. + fetchDataIfNotAvailable(key); + jso = cacheData.getObj(key); } - - @Override - public AddressVerificationNodeData get(String key) { - JsoMap jso = mCacheData.getObj(key); - if (jso == null) { // Not cached. - fetchDataIfNotAvailable(key); - jso = mCacheData.getObj(key); - } - if (jso != null && isValidDataKey(key)) { - return createNodeData(jso); - } - return null; + if (jso != null && isValidDataKey(key)) { + return createNodeData(jso); + } + return null; + } + + @Override + public AddressVerificationNodeData getDefaultData(String key) { + // root data + if (key.split("/").length == 1) { + JsoMap jso = bootstrapMap.get(key); + if (jso == null || !isValidDataKey(key)) { + throw new RuntimeException("key " + key + " does not have bootstrap data"); + } + return createNodeData(jso); } - @Override - public AddressVerificationNodeData getDefaultData(String key) { - // root data - if (key.split("/").length == 1) { - JsoMap jso = mBootstrapMap.get(key); - if (jso == null || !isValidDataKey(key)) { - throw new RuntimeException("key " + key + " does not have bootstrap data"); - } - return createNodeData(jso); - } + key = getCountryKey(key); + JsoMap jso = bootstrapMap.get(key); + if (jso == null || !isValidDataKey(key)) { + throw new RuntimeException("key " + key + " does not have bootstrap data"); + } + return createNodeData(jso); + } - key = getCountryKey(key); - JsoMap jso = mBootstrapMap.get(key); - if (jso == null || !isValidDataKey(key)) { - throw new RuntimeException("key " + key + " does not have bootstrap data"); - } - return createNodeData(jso); + private String getCountryKey(String hierarchyKey) { + if (hierarchyKey.split("/").length <= 1) { + throw new RuntimeException("Cannot get country key with key '" + hierarchyKey + "'"); + } + if (isCountryKey(hierarchyKey)) { + return hierarchyKey; } - private String getCountryKey(String hierarchyKey) { - if (hierarchyKey.split("/").length <= 1) { - throw new RuntimeException("Cannot get country key with key '" + hierarchyKey + "'"); - } - if (isCountryKey(hierarchyKey)) { - return hierarchyKey; - } + String[] parts = hierarchyKey.split("/"); - String[] parts = hierarchyKey.split("/"); + return new StringBuilder().append(parts[0]) + .append("/") + .append(parts[1]) + .toString(); + } - return new StringBuilder().append(parts[0]) - .append("/") - .append(parts[1]) - .toString(); - } + private boolean isCountryKey(String hierarchyKey) { + Util.checkNotNull(hierarchyKey, "Cannot use null as a key"); + return hierarchyKey.split("/").length == 2; + } - private boolean isCountryKey(String hierarchyKey) { - Util.checkNotNull(hierarchyKey, "Cannot use null as a key"); - return hierarchyKey.split("/").length == 2; - } + /** + * Returns the contents of the JSON-format string as a map. + */ + protected AddressVerificationNodeData createNodeData(JsoMap jso) { + Map map = + new EnumMap(AddressDataKey.class); - /** - * Returns the contents of the JSON-format string as a map. - */ - protected AddressVerificationNodeData createNodeData(JsoMap jso) { - Map map = - new EnumMap(AddressDataKey.class); - - JSONArray arr = jso.getKeys(); - for (int i = 0; i < arr.length(); i++) { - try { - AddressDataKey key = AddressDataKey.get(arr.getString(i)); - - if (key == null) { - // Not all keys are supported by Android, so we continue if we encounter one - // that is not used. - continue; - } - - String value = jso.get(key.toString().toLowerCase()); - map.put(key, value); - } catch (JSONException e) { - // This should not happen - we should not be fetching a key from outside the bounds - // of the array. - } + JSONArray arr = jso.getKeys(); + for (int i = 0; i < arr.length(); i++) { + try { + AddressDataKey key = AddressDataKey.get(arr.getString(i)); + + if (key == null) { + // Not all keys are supported by Android, so we continue if we encounter one + // that is not used. + continue; } - return new AddressVerificationNodeData(map); + String value = jso.get(key.toString().toLowerCase()); + map.put(key, value); + } catch (JSONException e) { + // This should not happen - we should not be fetching a key from outside the bounds + // of the array. + } } - /** - * We can be initialized with the full set of address information, but validation only uses info - * prefixed with "data" (in particular, no info prefixed with "examples"). - */ - private boolean isValidDataKey(String key) { - return key.startsWith("data"); + return new AddressVerificationNodeData(map); + } + + /** + * We can be initialized with the full set of address information, but validation only uses info + * prefixed with "data" (in particular, no info prefixed with "examples"). + */ + private boolean isValidDataKey(String key) { + return key.startsWith("data"); + } + + /** + * Initializes regionalData structure based on property file. + */ + private void buildRegionalData() { + StringBuilder countries = new StringBuilder(); + + for (String countryCode : RegionDataConstants.getCountryFormatMap().keySet()) { + countries.append(countryCode + "~"); + String json = RegionDataConstants.getCountryFormatMap().get(countryCode); + JsoMap jso = null; + try { + jso = JsoMap.buildJsoMap(json); + } catch (JSONException e) { + // Ignore. + } + + AddressData data = new AddressData.Builder().setCountry(countryCode).build(); + LookupKey key = new LookupKey.Builder(KeyType.DATA).setAddressData(data).build(); + bootstrapMap.put(key.toString(), jso); } + countries.setLength(countries.length() - 1); - /** - * Initializes regionalData structure based on property file. + // TODO: this is messy. do we have better ways to do it? + /* Creates verification data for key="data". This will be used for the + * root FieldVerifier. */ - private void buildRegionalData() { - StringBuilder countries = new StringBuilder(); - - for (String countryCode : RegionDataConstants.getCountryFormatMap().keySet()) { - countries.append(countryCode + "~"); - String json = RegionDataConstants.getCountryFormatMap().get(countryCode); - JsoMap jso = null; - try { - jso = JsoMap.buildJsoMap(json); - } catch (JSONException e) { - // Ignore. - } - - AddressData data = new AddressData.Builder().setCountry(countryCode).build(); - LookupKey key = new LookupKey.Builder(KeyType.DATA).setAddressData(data).build(); - mBootstrapMap.put(key.toString(), jso); - } - countries.setLength(countries.length() - 1); - - // TODO: this is messy. do we have better ways to do it? - /* Creates verification data for key="data". This will be used for the - * root FieldVerifier. - */ - String str = "{\"id\":\"data\",\"" + - AddressDataKey.COUNTRIES.toString().toLowerCase() + - "\": \"" + countries.toString() + "\"}"; - JsoMap jsoData = null; - try { - jsoData = JsoMap.buildJsoMap(str); - } catch (JSONException e) { - // Ignore. - } - mBootstrapMap.put("data", jsoData); + String str = "{\"id\":\"data\",\"" + + AddressDataKey.COUNTRIES.toString().toLowerCase() + + "\": \"" + countries.toString() + "\"}"; + JsoMap jsoData = null; + try { + jsoData = JsoMap.buildJsoMap(str); + } catch (JSONException e) { + // Ignore. } - - /** - * Fetches data from remote server if it is not cached yet. - * - * @param key The key for data that being requested. Key can be either a data key (starts with - * "data") or example key (starts with "examples") - */ - private void fetchDataIfNotAvailable(String key) { - JsoMap jso = mCacheData.getObj(key); - if (jso == null) { - // If there is bootstrap data for the key, pass the data to fetchDynamicData - JsoMap regionalData = mBootstrapMap.get(key); - NotifyingListener listener = new NotifyingListener(this); - // If the key was invalid, we don't want to attempt to fetch it. - if (LookupKey.hasValidKeyPrefix(key)) { - LookupKey lookupKey = new LookupKey.Builder(key).build(); - mCacheData.fetchDynamicData(lookupKey, regionalData, listener); - try { - listener.waitLoadingEnd(); - // Check to see if there is data for this key now. - if (mCacheData.getObj(key) == null && isCountryKey(key)) { - // If not, see if there is data in RegionDataConstants. - Log.i(TAG, "Server failure: looking up key in region data constants."); - mCacheData.getFromRegionDataConstants(lookupKey); - } - } catch (InterruptedException e) { - throw new RuntimeException(e); - } - } + bootstrapMap.put("data", jsoData); + } + + /** + * Fetches data from remote server if it is not cached yet. + * + * @param key The key for data that being requested. Key can be either a data key (starts with + * "data") or example key (starts with "examples") + */ + private void fetchDataIfNotAvailable(String key) { + JsoMap jso = cacheData.getObj(key); + if (jso == null) { + // If there is bootstrap data for the key, pass the data to fetchDynamicData + JsoMap regionalData = bootstrapMap.get(key); + NotifyingListener listener = new NotifyingListener(this); + // If the key was invalid, we don't want to attempt to fetch it. + if (LookupKey.hasValidKeyPrefix(key)) { + LookupKey lookupKey = new LookupKey.Builder(key).build(); + cacheData.fetchDynamicData(lookupKey, regionalData, listener); + try { + listener.waitLoadingEnd(); + // Check to see if there is data for this key now. + if (cacheData.getObj(key) == null && isCountryKey(key)) { + // If not, see if there is data in RegionDataConstants. + Log.i(TAG, "Server failure: looking up key in region data constants."); + cacheData.getFromRegionDataConstants(lookupKey); + } + } catch (InterruptedException e) { + throw new RuntimeException(e); } + } } - - public void requestData(LookupKey key, DataLoadListener listener) { - Util.checkNotNull(key, "Null lookup key not allowed"); - JsoMap regionalData = mBootstrapMap.get(key.toString()); - mCacheData.fetchDynamicData(key, regionalData, listener); + } + + public void requestData(LookupKey key, DataLoadListener listener) { + Util.checkNotNull(key, "Null lookup key not allowed"); + JsoMap regionalData = bootstrapMap.get(key.toString()); + cacheData.fetchDynamicData(key, regionalData, listener); + } + + /** + * Fetches all data for the specified country from the remote server. + */ + public void prefetchCountry(String country, DataLoadListener listener) { + String key = "data/" + country; + Set loaders = new HashSet(); + listener.dataLoadingBegin(); + cacheData.fetchDynamicData( + new LookupKey.Builder(key).build(), + null, + new RecursiveLoader(key, loaders, listener)); + } + + /** + * A helper class to recursively load all sub keys using fetchDynamicData(). + */ + private class RecursiveLoader implements DataLoadListener { + + private final String key; + + private final Set loaders; + + private final DataLoadListener listener; + + public RecursiveLoader(String key, Set loaders, + DataLoadListener listener) { + this.key = key; + this.loaders = loaders; + this.listener = listener; + + synchronized (loaders) { + loaders.add(this); + } } - /** - * Fetches all data for the specified country from the remote server. - */ - public void prefetchCountry(String country, DataLoadListener listener) { - String key = "data/" + country; - Set loaders = new HashSet(); - listener.dataLoadingBegin(); - mCacheData.fetchDynamicData( - new LookupKey.Builder(key).build(), - null, - new RecursiveLoader(key, loaders, listener)); + @Override + public void dataLoadingBegin() { } - /** - * A helper class to recursively load all sub keys using fetchDynamicData(). - */ - private class RecursiveLoader implements DataLoadListener { - - private final String key; + @Override + public void dataLoadingEnd() { + final String subKeys = AddressDataKey.SUB_KEYS.name().toLowerCase(); + final String subMores = AddressDataKey.SUB_MORES.name().toLowerCase(); - private final Set loaders; + JsoMap map = cacheData.getObj(key); - private final DataLoadListener listener; + if (map.containsKey(subMores)) { + // This key could have sub keys. + String[] mores = map.get(subMores).split("~"); + String[] keys = {}; - public RecursiveLoader(String key, Set loaders, - DataLoadListener listener) { - this.key = key; - this.loaders = loaders; - this.listener = listener; + if (map.containsKey(subKeys)) { + keys = map.get(subKeys).split("~"); + } - synchronized (loaders) { - loaders.add(this); - } + if (mores.length != keys.length) { // This should never happen. + throw new IndexOutOfBoundsException("mores.length != keys.length"); } - @Override - public void dataLoadingBegin() { + for (int i = 0; i < mores.length; i++) { + if (mores[i].equalsIgnoreCase("true")) { + // This key should have sub keys. + String subKey = key + "/" + keys[i]; + cacheData.fetchDynamicData( + new LookupKey.Builder(subKey).build(), + null, + new RecursiveLoader(subKey, loaders, listener)); + } } + } - @Override - public void dataLoadingEnd() { - final String subKeys = AddressDataKey.SUB_KEYS.name().toLowerCase(); - final String subMores = AddressDataKey.SUB_MORES.name().toLowerCase(); - - JsoMap map = mCacheData.getObj(key); - - if (map.containsKey(subMores)) { - // This key could have sub keys. - String[] mores = map.get(subMores).split("~"); - String[] keys = {}; - - if (map.containsKey(subKeys)) { - keys = map.get(subKeys).split("~"); - } - - if (mores.length != keys.length) { // This should never happen. - throw new IndexOutOfBoundsException("mores.length != keys.length"); - } - - for (int i = 0; i < mores.length; i++) { - if (mores[i].equalsIgnoreCase("true")) { - // This key should have sub keys. - String subKey = key + "/" + keys[i]; - mCacheData.fetchDynamicData( - new LookupKey.Builder(subKey).build(), - null, - new RecursiveLoader(subKey, loaders, listener)); - } - } - } - - synchronized (loaders) { - loaders.remove(this); - if (loaders.isEmpty()) { - listener.dataLoadingEnd(); - } - } + synchronized (loaders) { + loaders.remove(this); + if (loaders.isEmpty()) { + listener.dataLoadingEnd(); } + } } + } } diff --git a/java/src/com/android/i18n/addressinput/DataLoadListener.java b/java/src/com/android/i18n/addressinput/DataLoadListener.java index fc7782c..4e6fbee 100644 --- a/java/src/com/android/i18n/addressinput/DataLoadListener.java +++ b/java/src/com/android/i18n/addressinput/DataLoadListener.java @@ -20,7 +20,7 @@ package com.android.i18n.addressinput; * Invoked when the data is fetched from the server or the cache. */ public interface DataLoadListener { - // These callbacks are invoked from a background thread. - void dataLoadingBegin(); - void dataLoadingEnd(); + // These callbacks are invoked from a background thread. + void dataLoadingBegin(); + void dataLoadingEnd(); } diff --git a/java/src/com/android/i18n/addressinput/DataSource.java b/java/src/com/android/i18n/addressinput/DataSource.java index d77f27f..605ae2a 100644 --- a/java/src/com/android/i18n/addressinput/DataSource.java +++ b/java/src/com/android/i18n/addressinput/DataSource.java @@ -20,6 +20,6 @@ package com.android.i18n.addressinput; // removed when we have created code for static loading of data without using the // AddressVerificationData class. public interface DataSource { - AddressVerificationNodeData getDefaultData(String key); - AddressVerificationNodeData get(String key); + AddressVerificationNodeData getDefaultData(String key); + AddressVerificationNodeData get(String key); } diff --git a/java/src/com/android/i18n/addressinput/FieldVerifier.java b/java/src/com/android/i18n/addressinput/FieldVerifier.java index 2375c0e..17a71e0 100644 --- a/java/src/com/android/i18n/addressinput/FieldVerifier.java +++ b/java/src/com/android/i18n/addressinput/FieldVerifier.java @@ -32,295 +32,295 @@ import java.util.regex.Pattern; * and only provides format and match verification for the postal code field. */ public class FieldVerifier { - // Node data values are delimited by this symbol. - private static final String DATA_DELIMITER = "~"; - // Keys are built up using this delimiter: eg data/US, data/US/CA. - private static final String KEY_DELIMITER = "/"; + // Node data values are delimited by this symbol. + private static final String DATA_DELIMITER = "~"; + // Keys are built up using this delimiter: eg data/US, data/US/CA. + private static final String KEY_DELIMITER = "/"; - private static final FormatInterpreter FORMAT_INTERPRETER = - new FormatInterpreter(new FormOptions.Builder().build()); + private static final FormatInterpreter FORMAT_INTERPRETER = + new FormatInterpreter(new FormOptions.Builder().build()); - // Package-private so it can be accessed by tests. - String mId; - private DataSource mDataSource; + // Package-private so it can be accessed by tests. + String id; + private DataSource dataSource; - // Package-private so they can be accessed by tests. - Set mPossiblyUsedFields; - Set mRequired; - // Known values. Can be either a key, a name in Latin, or a name in native script. - private Map mCandidateValues; + // Package-private so they can be accessed by tests. + Set possiblyUsedFields; + Set required; + // Known values. Can be either a key, a name in Latin, or a name in native script. + private Map candidateValues; - // Keys for the subnodes of this verifier. For example, a key for the US would be CA, since - // there is a sub-verifier with the ID "data/US/CA". Keys may be the local names of the - // locations in the next level of the hierarchy, or the abbreviations if suitable abbreviations - // exist. Package-private so it can be accessed by tests. - String[] mKeys; - // Names in Latin. These are only populated if the native/local names are in a script other than - // latin. - private String[] mLatinNames; - // Names in native script. - private String[] mLocalNames; + // Keys for the subnodes of this verifier. For example, a key for the US would be CA, since + // there is a sub-verifier with the ID "data/US/CA". Keys may be the local names of the + // locations in the next level of the hierarchy, or the abbreviations if suitable abbreviations + // exist. Package-private so it can be accessed by tests. + String[] keys; + // Names in Latin. These are only populated if the native/local names are in a script other than + // latin. + private String[] latinNames; + // Names in native script. + private String[] localNames; - // Pattern representing the format of a postal code number. - private Pattern mFormat; - // Defines the valid range of a postal code number. - private Pattern mMatch; + // Pattern representing the format of a postal code number. + private Pattern format; + // Defines the valid range of a postal code number. + private Pattern match; - /** - * Creates the root field verifier for a particular data source. - */ - public FieldVerifier(DataSource dataSource) { - mDataSource = dataSource; - populateRootVerifier(); - } + /** + * Creates the root field verifier for a particular data source. + */ + public FieldVerifier(DataSource dataSource) { + dataSource = dataSource; + populateRootVerifier(); + } - /** - * Creates a field verifier based on its parent and on the new data for this node supplied by - * nodeData (which may be null). - * - * Package-private so it can be accessed by tests. - */ - FieldVerifier(FieldVerifier parent, AddressVerificationNodeData nodeData) { - // Most information is inherited from the parent. - mPossiblyUsedFields = parent.mPossiblyUsedFields; - mRequired = parent.mRequired; - mDataSource = parent.mDataSource; - mFormat = parent.mFormat; - mMatch = parent.mMatch; - // Here we add in any overrides from this particular node as well as information such as - // localNames, latinNames and keys. - populate(nodeData); - // candidateValues should never be inherited from the parent, but built up from the - // localNames in this node. - mCandidateValues = Util.buildNameToKeyMap(mKeys, mLocalNames, mLatinNames); - } + /** + * Creates a field verifier based on its parent and on the new data for this node supplied by + * nodeData (which may be null). + * + * Package-private so it can be accessed by tests. + */ + FieldVerifier(FieldVerifier parent, AddressVerificationNodeData nodeData) { + // Most information is inherited from the parent. + possiblyUsedFields = parent.possiblyUsedFields; + required = parent.required; + dataSource = parent.dataSource; + format = parent.format; + match = parent.match; + // Here we add in any overrides from this particular node as well as information such as + // localNames, latinNames and keys. + populate(nodeData); + // candidateValues should never be inherited from the parent, but built up from the + // localNames in this node. + candidateValues = Util.buildNameToKeyMap(keys, localNames, latinNames); + } - /** - * Sets possiblyUsedFields, required, keys and candidateValues for the root field verifier. - */ - private void populateRootVerifier() { - mId = "data"; - // Keys come from the countries under "data". - AddressVerificationNodeData rootNode = mDataSource.getDefaultData("data"); - if (rootNode.containsKey(AddressDataKey.COUNTRIES)) { - mKeys = rootNode.get(AddressDataKey.COUNTRIES).split(DATA_DELIMITER); - } - // candidateValues is just the set of keys. - mCandidateValues = Util.buildNameToKeyMap(mKeys, null, null); - - // TODO: Investigate if these need to be set here. The country level population already - // handles the fallback, the question is if validation can be done without a country level - // validator being created. - // Copy "possiblyUsedFields" and "required" from the defaults here for bootstrapping. - mPossiblyUsedFields = new HashSet(); - mRequired = new HashSet(); - populatePossibleAndRequired("ZZ"); + /** + * Sets possiblyUsedFields, required, keys and candidateValues for the root field verifier. + */ + private void populateRootVerifier() { + id = "data"; + // Keys come from the countries under "data". + AddressVerificationNodeData rootNode = dataSource.getDefaultData("data"); + if (rootNode.containsKey(AddressDataKey.COUNTRIES)) { + keys = rootNode.get(AddressDataKey.COUNTRIES).split(DATA_DELIMITER); } + // candidateValues is just the set of keys. + candidateValues = Util.buildNameToKeyMap(keys, null, null); - /** - * Populates this verifier with data from the node data passed in and from RegionDataConstants. - * The node data may be null. - */ - private void populate(AddressVerificationNodeData nodeData) { - if (nodeData == null) { - return; - } - if (nodeData.containsKey(AddressDataKey.ID)) { - mId = nodeData.get(AddressDataKey.ID); - } - if (nodeData.containsKey(AddressDataKey.SUB_KEYS)) { - mKeys = nodeData.get(AddressDataKey.SUB_KEYS).split(DATA_DELIMITER); - } - if (nodeData.containsKey(AddressDataKey.SUB_LNAMES)) { - mLatinNames = nodeData.get(AddressDataKey.SUB_LNAMES).split(DATA_DELIMITER); - } - if (nodeData.containsKey(AddressDataKey.SUB_NAMES)) { - mLocalNames = nodeData.get(AddressDataKey.SUB_NAMES).split(DATA_DELIMITER); - } - if (nodeData.containsKey(AddressDataKey.XZIP)) { - mFormat = Pattern.compile(nodeData.get(AddressDataKey.XZIP), Pattern.CASE_INSENSITIVE); - } - if (nodeData.containsKey(AddressDataKey.ZIP)) { - // This key has two different meanings, depending on whether this is a country-level key - // or not. - if (isCountryKey()) { - mFormat = Pattern.compile(nodeData.get(AddressDataKey.ZIP), - Pattern.CASE_INSENSITIVE); - } else { - mMatch = Pattern.compile(nodeData.get(AddressDataKey.ZIP), - Pattern.CASE_INSENSITIVE); - } - } - // If there are latin names but no local names, and there are the same number of latin names - // as there are keys, then we assume the local names are the same as the keys. - if (mKeys != null && mLocalNames == null && mLatinNames != null && - mKeys.length == mLatinNames.length) { - mLocalNames = mKeys; - } + // TODO: Investigate if these need to be set here. The country level population already + // handles the fallback, the question is if validation can be done without a country level + // validator being created. + // Copy "possiblyUsedFields" and "required" from the defaults here for bootstrapping. + possiblyUsedFields = new HashSet(); + required = new HashSet(); + populatePossibleAndRequired("ZZ"); + } - // These fields are populated from RegionDataConstants so that the metadata server can be - // updated without needing to be in sync with clients. - if (isCountryKey()) { - populatePossibleAndRequired(mId.split(KEY_DELIMITER)[1]); - } + /** + * Populates this verifier with data from the node data passed in and from RegionDataConstants. + * The node data may be null. + */ + private void populate(AddressVerificationNodeData nodeData) { + if (nodeData == null) { + return; + } + if (nodeData.containsKey(AddressDataKey.ID)) { + id = nodeData.get(AddressDataKey.ID); + } + if (nodeData.containsKey(AddressDataKey.SUB_KEYS)) { + keys = nodeData.get(AddressDataKey.SUB_KEYS).split(DATA_DELIMITER); + } + if (nodeData.containsKey(AddressDataKey.SUB_LNAMES)) { + latinNames = nodeData.get(AddressDataKey.SUB_LNAMES).split(DATA_DELIMITER); + } + if (nodeData.containsKey(AddressDataKey.SUB_NAMES)) { + localNames = nodeData.get(AddressDataKey.SUB_NAMES).split(DATA_DELIMITER); + } + if (nodeData.containsKey(AddressDataKey.XZIP)) { + format = Pattern.compile(nodeData.get(AddressDataKey.XZIP), Pattern.CASE_INSENSITIVE); + } + if (nodeData.containsKey(AddressDataKey.ZIP)) { + // This key has two different meanings, depending on whether this is a country-level key + // or not. + if (isCountryKey()) { + format = Pattern.compile(nodeData.get(AddressDataKey.ZIP), + Pattern.CASE_INSENSITIVE); + } else { + match = Pattern.compile(nodeData.get(AddressDataKey.ZIP), + Pattern.CASE_INSENSITIVE); + } + } + // If there are latin names but no local names, and there are the same number of latin names + // as there are keys, then we assume the local names are the same as the keys. + if (keys != null && localNames == null && latinNames != null && + keys.length == latinNames.length) { + localNames = keys; } - private void populatePossibleAndRequired(String regionCode) { - List possible = FORMAT_INTERPRETER.getAddressFieldOrder(regionCode); - mPossiblyUsedFields = convertAddressFieldsToPossiblyUsedSet(possible); - mRequired = FormatInterpreter.getRequiredFields(regionCode); + // These fields are populated from RegionDataConstants so that the metadata server can be + // updated without needing to be in sync with clients. + if (isCountryKey()) { + populatePossibleAndRequired(id.split(KEY_DELIMITER)[1]); } + } - FieldVerifier refineVerifier(String sublevel) { - if (Util.trimToNull(sublevel) == null) { - return new FieldVerifier(this, null); - } - // If the parent node didn't exist, then the subLevelName will start with "null". - String subLevelName = mId + KEY_DELIMITER + sublevel; - // For names with no Latin equivalent, we can look up the sublevel name directly. - AddressVerificationNodeData nodeData = mDataSource.get(subLevelName); + private void populatePossibleAndRequired(String regionCode) { + List possible = FORMAT_INTERPRETER.getAddressFieldOrder(regionCode); + possiblyUsedFields = convertAddressFieldsToPossiblyUsedSet(possible); + required = FormatInterpreter.getRequiredFields(regionCode); + } + + FieldVerifier refineVerifier(String sublevel) { + if (Util.trimToNull(sublevel) == null) { + return new FieldVerifier(this, null); + } + // If the parent node didn't exist, then the subLevelName will start with "null". + String subLevelName = id + KEY_DELIMITER + sublevel; + // For names with no Latin equivalent, we can look up the sublevel name directly. + AddressVerificationNodeData nodeData = dataSource.get(subLevelName); + if (nodeData != null) { + return new FieldVerifier(this, nodeData); + } + // If that failed, then we try to look up the local name equivalent of this latin name. + // First check these exist. + if (latinNames == null) { + return new FieldVerifier(this, null); + } + for (int n = 0; n < latinNames.length; n++) { + if (latinNames[n].equalsIgnoreCase(sublevel)) { + // We found a match - we should try looking up a key with the local name at the same + // index. + subLevelName = id + KEY_DELIMITER + localNames[n]; + nodeData = dataSource.get(subLevelName); if (nodeData != null) { - return new FieldVerifier(this, nodeData); + return new FieldVerifier(this, nodeData); } - // If that failed, then we try to look up the local name equivalent of this latin name. - // First check these exist. - if (mLatinNames == null) { - return new FieldVerifier(this, null); - } - for (int n = 0; n < mLatinNames.length; n++) { - if (mLatinNames[n].equalsIgnoreCase(sublevel)) { - // We found a match - we should try looking up a key with the local name at the same - // index. - subLevelName = mId + KEY_DELIMITER + mLocalNames[n]; - nodeData = mDataSource.get(subLevelName); - if (nodeData != null) { - return new FieldVerifier(this, nodeData); - } - } - } - // No sub-verifiers were found. - return new FieldVerifier(this, null); + } } + // No sub-verifiers were found. + return new FieldVerifier(this, null); + } - /** - * Returns the ID of this verifier. - */ - @Override - public String toString() { - return mId; - } + /** + * Returns the ID of this verifier. + */ + @Override + public String toString() { + return id; + } - /** - * Checks a value in a particular script for a particular field to see if it causes the problem - * specified. If so, this problem is added to the AddressProblems collection passed in. Returns - * true if no problem was found. - */ - protected boolean check(ScriptType script, AddressProblemType problem, AddressField field, - String value, AddressProblems problems) { - boolean problemFound = false; + /** + * Checks a value in a particular script for a particular field to see if it causes the problem + * specified. If so, this problem is added to the AddressProblems collection passed in. Returns + * true if no problem was found. + */ + protected boolean check(ScriptType script, AddressProblemType problem, AddressField field, + String value, AddressProblems problems) { + boolean problemFound = false; - String trimmedValue = Util.trimToNull(value); - switch (problem) { - case USING_UNUSED_FIELD: - if (trimmedValue != null && !mPossiblyUsedFields.contains(field)) { - problemFound = true; - } - break; - case MISSING_REQUIRED_FIELD: - if (mRequired.contains(field) && trimmedValue == null) { - problemFound = true; - } - break; - case UNKNOWN_VALUE: - // An empty string will never be an UNKNOWN_VALUE. It is invalid - // only when it appears in a required field (In that case it will - // be reported as MISSING_REQUIRED_FIELD). - if (trimmedValue == null) { - break; - } - problemFound = !isKnownInScript(script, trimmedValue); - break; - case UNRECOGNIZED_FORMAT: - if (trimmedValue != null && mFormat != null && - !mFormat.matcher(trimmedValue).matches()) { - problemFound = true; - } - break; - case MISMATCHING_VALUE: - if (trimmedValue != null && mMatch != null && - !mMatch.matcher(trimmedValue).lookingAt()) { - problemFound = true; - } - break; - default: - throw new RuntimeException("Unknown problem: " + problem); + String trimmedValue = Util.trimToNull(value); + switch (problem) { + case USING_UNUSED_FIELD: + if (trimmedValue != null && !possiblyUsedFields.contains(field)) { + problemFound = true; } - if (problemFound) { - problems.add(field, problem); + break; + case MISSING_REQUIRED_FIELD: + if (required.contains(field) && trimmedValue == null) { + problemFound = true; } - return !problemFound; - } - - /** - * Checks the value of a particular field in a particular script against the known values for - * this field. If script is null, it checks both the local and the latin values. Otherwise it - * checks only the values in the script specified. - */ - private boolean isKnownInScript(ScriptType script, String value) { - String trimmedValue = Util.trimToNull(value); - Util.checkNotNull(trimmedValue); - if (script == null) { - return (mCandidateValues == null || - mCandidateValues.containsKey(trimmedValue.toLowerCase())); + break; + case UNKNOWN_VALUE: + // An empty string will never be an UNKNOWN_VALUE. It is invalid + // only when it appears in a required field (In that case it will + // be reported as MISSING_REQUIRED_FIELD). + if (trimmedValue == null) { + break; } - // Otherwise, if we know the script, we want to restrict the candidates to only names in - // that script. - String[] namesToConsider = (script == ScriptType.LATIN) ? mLatinNames : mLocalNames; - Set candidates = new HashSet(); - if (namesToConsider != null) { - for (String name : namesToConsider) { - candidates.add(name.toLowerCase()); - } + problemFound = !isKnownInScript(script, trimmedValue); + break; + case UNRECOGNIZED_FORMAT: + if (trimmedValue != null && format != null && + !format.matcher(trimmedValue).matches()) { + problemFound = true; } - if (mKeys != null) { - for (String name : mKeys) { - candidates.add(name.toLowerCase()); - } - } - - if (candidates.size() == 0 || trimmedValue == null) { - return true; + break; + case MISMATCHING_VALUE: + if (trimmedValue != null && match != null && + !match.matcher(trimmedValue).lookingAt()) { + problemFound = true; } + break; + default: + throw new RuntimeException("Unknown problem: " + problem); + } + if (problemFound) { + problems.add(field, problem); + } + return !problemFound; + } - return candidates.contains(value.toLowerCase()); + /** + * Checks the value of a particular field in a particular script against the known values for + * this field. If script is null, it checks both the local and the latin values. Otherwise it + * checks only the values in the script specified. + */ + private boolean isKnownInScript(ScriptType script, String value) { + String trimmedValue = Util.trimToNull(value); + Util.checkNotNull(trimmedValue); + if (script == null) { + return (candidateValues == null || + candidateValues.containsKey(trimmedValue.toLowerCase())); + } + // Otherwise, if we know the script, we want to restrict the candidates to only names in + // that script. + String[] namesToConsider = (script == ScriptType.LATIN) ? latinNames : localNames; + Set candidates = new HashSet(); + if (namesToConsider != null) { + for (String name : namesToConsider) { + candidates.add(name.toLowerCase()); + } + } + if (keys != null) { + for (String name : keys) { + candidates.add(name.toLowerCase()); + } } - /** - * Converts a list of address fields to a set of possibly used fields. Adds country and handles - * street address. - */ - private static Set convertAddressFieldsToPossiblyUsedSet( - List fields) { - // COUNTRY is never unexpected. - EnumSet result = EnumSet.of(AddressField.COUNTRY); - for (AddressField field : fields) { - // Replace ADDRESS_LINE with STREET_ADDRESS because that's what the validation expects. - if (field == AddressField.ADDRESS_LINE_1 || - field == AddressField.ADDRESS_LINE_2) { - result.add(AddressField.STREET_ADDRESS); - } else { - result.add(field); - } - } - return result; + if (candidates.size() == 0 || trimmedValue == null) { + return true; } - /** - * Returns true if this key represents a country. We assume all keys with only one delimiter are - * at the country level (such as "data/US"). - */ - private boolean isCountryKey() { - Util.checkNotNull(mId, "Cannot use null as key"); - return mId.split(KEY_DELIMITER).length == 2; + return candidates.contains(value.toLowerCase()); + } + + /** + * Converts a list of address fields to a set of possibly used fields. Adds country and handles + * street address. + */ + private static Set convertAddressFieldsToPossiblyUsedSet( + List fields) { + // COUNTRY is never unexpected. + EnumSet result = EnumSet.of(AddressField.COUNTRY); + for (AddressField field : fields) { + // Replace ADDRESS_LINE with STREET_ADDRESS because that's what the validation expects. + if (field == AddressField.ADDRESS_LINE_1 || + field == AddressField.ADDRESS_LINE_2) { + result.add(AddressField.STREET_ADDRESS); + } else { + result.add(field); + } } + return result; + } + + /** + * Returns true if this key represents a country. We assume all keys with only one delimiter are + * at the country level (such as "data/US"). + */ + private boolean isCountryKey() { + Util.checkNotNull(id, "Cannot use null as key"); + return id.split(KEY_DELIMITER).length == 2; + } } diff --git a/java/src/com/android/i18n/addressinput/FormController.java b/java/src/com/android/i18n/addressinput/FormController.java index c8c5953..68deed7 100644 --- a/java/src/com/android/i18n/addressinput/FormController.java +++ b/java/src/com/android/i18n/addressinput/FormController.java @@ -29,306 +29,305 @@ import java.util.Queue; * values for the next level down in the address hierarchy, if these are known. */ class FormController { - // For address hierarchy in lookup key. - private static final String SLASH_DELIM = "/"; - // For joined values. - private static final String TILDE_DELIM = "~"; - // For language code info in lookup key (E.g., data/CA--fr). - private static final String DASH_DELIM = "--"; - private static final LookupKey ROOT_KEY = FormController.getDataKeyForRoot(); - private static final String DEFAULT_REGION_CODE = "ZZ"; - private static final AddressField[] ADDRESS_HIERARCHY = { - AddressField.COUNTRY, - AddressField.ADMIN_AREA, - AddressField.LOCALITY, - AddressField.DEPENDENT_LOCALITY - }; - - // Current user language. - private String mLanguageCode; - private ClientData mIntegratedData; - private String mCurrentCountry; - - /** - * Constructor that populates this with data. languageCode should be a BCP language code (such - * as "en" or "zh-Hant") and currentCountry should be an ISO 2-letter region code (such as "GB" - * or "US"). - */ - FormController(ClientData integratedData, String languageCode, String currentCountry) { - Util.checkNotNull(integratedData, "null data not allowed"); - mLanguageCode = languageCode; - this.mCurrentCountry = currentCountry; - - AddressData address = new AddressData.Builder().setCountry(DEFAULT_REGION_CODE).build(); - LookupKey defaultCountryKey = getDataKeyFor(address); - - AddressVerificationNodeData defaultCountryData = - integratedData.getDefaultData(defaultCountryKey.toString()); - Util.checkNotNull(defaultCountryData, - "require data for default country key: " + defaultCountryKey); - this.mIntegratedData = integratedData; + // For address hierarchy in lookup key. + private static final String SLASH_DELIM = "/"; + // For joined values. + private static final String TILDE_DELIM = "~"; + // For language code info in lookup key (E.g., data/CA--fr). + private static final String DASH_DELIM = "--"; + private static final LookupKey ROOT_KEY = FormController.getDataKeyForRoot(); + private static final String DEFAULT_REGION_CODE = "ZZ"; + private static final AddressField[] ADDRESS_HIERARCHY = { + AddressField.COUNTRY, + AddressField.ADMIN_AREA, + AddressField.LOCALITY, + AddressField.DEPENDENT_LOCALITY + }; + + // Current user language. + private String languageCode; + private ClientData integratedData; + private String currentCountry; + + /** + * Constructor that populates this with data. languageCode should be a BCP language code (such + * as "en" or "zh-Hant") and currentCountry should be an ISO 2-letter region code (such as "GB" + * or "US"). + */ + FormController(ClientData integratedData, String languageCode, String currentCountry) { + Util.checkNotNull(integratedData, "null data not allowed"); + languageCode = languageCode; + this.currentCountry = currentCountry; + + AddressData address = new AddressData.Builder().setCountry(DEFAULT_REGION_CODE).build(); + LookupKey defaultCountryKey = getDataKeyFor(address); + + AddressVerificationNodeData defaultCountryData = + integratedData.getDefaultData(defaultCountryKey.toString()); + Util.checkNotNull(defaultCountryData, + "require data for default country key: " + defaultCountryKey); + this.integratedData = integratedData; + } + + void setLanguageCode(String languageCode) { + languageCode = languageCode; + } + + void setCurrentCountry(String currentCountry) { + currentCountry = currentCountry; + } + + private ScriptType getScriptType() { + if (languageCode != null && Util.isExplicitLatinScript(languageCode)) { + return ScriptType.LATIN; } - - void setLanguageCode(String languageCode) { - mLanguageCode = languageCode; - } - - void setCurrentCountry(String currentCountry) { - mCurrentCountry = currentCountry; + return ScriptType.LOCAL; + } + + private static LookupKey getDataKeyForRoot() { + AddressData address = new AddressData.Builder().build(); + return new LookupKey.Builder(KeyType.DATA).setAddressData(address).build(); + } + + LookupKey getDataKeyFor(AddressData address) { + return new LookupKey.Builder(KeyType.DATA).setAddressData(address).build(); + } + + /** + * Requests data for the input address. This method chains multiple requests together. For + * example, an address for Mt View, California needs data from "data/US", "data/US/CA", and + * "data/US/CA/Mt View" to support it. This method will request them one by one (from top level + * key down to the most granular) and evokes {@link DataLoadListener#dataLoadingEnd} method when + * all data is collected. If the address is invalid, it will request the first valid child key + * instead. For example, a request for "data/US/Foo" will end up requesting data for "data/US", + * "data/US/AL". + * + * @param address the current address. + * @param listener triggered when requested data for the address is returned. + */ + void requestDataForAddress(AddressData address, DataLoadListener listener) { + Util.checkNotNull(address.getPostalCountry(), "null country not allowed"); + + // Gets the key for deepest available node. + Queue subkeys = new LinkedList(); + + for (AddressField field : ADDRESS_HIERARCHY) { + String value = address.getFieldValue(field); + if (value == null) { + break; + } + subkeys.add(value); } - - private ScriptType getScriptType() { - if (mLanguageCode != null && Util.isExplicitLatinScript(mLanguageCode)) { - return ScriptType.LATIN; - } - return ScriptType.LOCAL; + if (subkeys.size() == 0) { + throw new RuntimeException("Need at least country level info"); } - private static LookupKey getDataKeyForRoot() { - AddressData address = new AddressData.Builder().build(); - return new LookupKey.Builder(KeyType.DATA).setAddressData(address).build(); + if (listener != null) { + listener.dataLoadingBegin(); } - - LookupKey getDataKeyFor(AddressData address) { - return new LookupKey.Builder(KeyType.DATA).setAddressData(address).build(); - } - - /** - * Requests data for the input address. This method chains multiple requests together. For - * example, an address for Mt View, California needs data from "data/US", "data/US/CA", and - * "data/US/CA/Mt View" to support it. This method will request them one by one (from top level - * key down to the most granular) and evokes {@link DataLoadListener#dataLoadingEnd} method when - * all data is collected. If the address is invalid, it will request the first valid child key - * instead. For example, a request for "data/US/Foo" will end up requesting data for "data/US", - * "data/US/AL". - * - * @param address the current address. - * @param listener triggered when requested data for the address is returned. - */ - void requestDataForAddress(AddressData address, DataLoadListener listener) { - Util.checkNotNull(address.getPostalCountry(), "null country not allowed"); - - // Gets the key for deepest available node. - Queue subkeys = new LinkedList(); - - for (AddressField field : ADDRESS_HIERARCHY) { - String value = address.getFieldValue(field); - if (value == null) { - break; + requestDataRecursively(ROOT_KEY, subkeys, listener); + } + + private void requestDataRecursively(final LookupKey key, + final Queue subkeys, final DataLoadListener listener) { + Util.checkNotNull(key, "Null key not allowed"); + Util.checkNotNull(subkeys, "Null subkeys not allowed"); + + integratedData.requestData(key, new DataLoadListener() { + @Override + public void dataLoadingBegin() { + } + + @Override + public void dataLoadingEnd() { + List subregions = getRegionData(key); + if (subregions.isEmpty()) { + if (listener != null) { + listener.dataLoadingEnd(); + } + // TODO: Should update the selectors here. + return; + } else if (subkeys.size() > 0) { + String subkey = subkeys.remove(); + for (RegionData subregion : subregions) { + if (subregion.isValidName(subkey)) { + LookupKey nextKey = buildDataLookupKey(key, subregion.getKey()); + requestDataRecursively(nextKey, subkeys, listener); + return; } - subkeys.add(value); - } - if (subkeys.size() == 0) { - throw new RuntimeException("Need at least country level info"); + } } - if (listener != null) { - listener.dataLoadingBegin(); - } - requestDataRecursively(ROOT_KEY, subkeys, listener); + // Current value in the field is not valid, use the first valid subkey + // to request more data instead. + String firstSubkey = subregions.get(0).getKey(); + LookupKey nextKey = buildDataLookupKey(key, firstSubkey); + Queue emptyList = new LinkedList(); + requestDataRecursively(nextKey, emptyList, listener); + } + }); + } + + private LookupKey buildDataLookupKey(LookupKey lookupKey, String subKey) { + String[] subKeys = lookupKey.toString().split(SLASH_DELIM); + String languageCodeSubTag = + (languageCode == null) ? null : Util.getLanguageSubtag(languageCode); + String key = lookupKey.toString() + SLASH_DELIM + subKey; + + // Country level key + if (subKeys.length == 1 && + languageCodeSubTag != null && !isDefaultLanguage(languageCodeSubTag)) { + key += DASH_DELIM + languageCodeSubTag.toString(); } - - private void requestDataRecursively(final LookupKey key, - final Queue subkeys, final DataLoadListener listener) { - Util.checkNotNull(key, "Null key not allowed"); - Util.checkNotNull(subkeys, "Null subkeys not allowed"); - - mIntegratedData.requestData(key, new DataLoadListener() { - @Override - public void dataLoadingBegin() { - } - - @Override - public void dataLoadingEnd() { - List subregions = getRegionData(key); - if (subregions.isEmpty()) { - if (listener != null) { - listener.dataLoadingEnd(); - } - // TODO: Should update the selectors here. - return; - } else if (subkeys.size() > 0) { - String subkey = subkeys.remove(); - for (RegionData subregion : subregions) { - if (subregion.isValidName(subkey)) { - LookupKey nextKey = buildDataLookupKey(key, subregion.getKey()); - requestDataRecursively(nextKey, subkeys, listener); - return; - } - } - } - - // Current value in the field is not valid, use the first valid subkey - // to request more data instead. - String firstSubkey = subregions.get(0).getKey(); - LookupKey nextKey = buildDataLookupKey(key, firstSubkey); - Queue emptyList = new LinkedList(); - requestDataRecursively(nextKey, emptyList, listener); - } - }); + return new LookupKey.Builder(key).build(); + } + + /** + * Compares the language subtags of input {@code languageCode} and default language code. For + * example, "zh-Hant" and "zh" are viewed as identical. + */ + boolean isDefaultLanguage(String languageCode) { + if (languageCode == null) { + return true; } - - private LookupKey buildDataLookupKey(LookupKey lookupKey, String subKey) { - String[] subKeys = lookupKey.toString().split(SLASH_DELIM); - String languageCodeSubTag = - (mLanguageCode == null) ? null : Util.getLanguageSubtag(mLanguageCode); - String key = lookupKey.toString() + SLASH_DELIM + subKey; - - // Country level key - if (subKeys.length == 1 && - languageCodeSubTag != null && !isDefaultLanguage(languageCodeSubTag)) { - key += DASH_DELIM + languageCodeSubTag.toString(); - } - return new LookupKey.Builder(key).build(); + AddressData addr = new AddressData.Builder().setCountry(currentCountry).build(); + LookupKey lookupKey = getDataKeyFor(addr); + AddressVerificationNodeData data = + integratedData.getDefaultData(lookupKey.toString()); + String defaultLanguage = data.get(AddressDataKey.LANG); + + // Current language is not the default language for the country. + if (Util.trimToNull(defaultLanguage) != null && + !Util.getLanguageSubtag(languageCode).equals(Util.getLanguageSubtag(languageCode))) { + return false; } - - /** - * Compares the language subtags of input {@code languageCode} and default language code. For - * example, "zh-Hant" and "zh" are viewed as identical. - */ - boolean isDefaultLanguage(String languageCode) { - if (languageCode == null) { - return true; - } - AddressData addr = new AddressData.Builder().setCountry(mCurrentCountry).build(); - LookupKey lookupKey = getDataKeyFor(addr); - AddressVerificationNodeData data = - mIntegratedData.getDefaultData(lookupKey.toString()); - String defaultLanguage = data.get(AddressDataKey.LANG); - - // Current language is not the default language for the country. - if (Util.trimToNull(defaultLanguage) != null && - !Util.getLanguageSubtag(languageCode).equals(Util.getLanguageSubtag(languageCode))) { - return false; - } - return true; + return true; + } + + /** + * Gets a list of {@link RegionData} for sub-regions for a given key. For example, sub regions + * for "data/US" are AL/Alabama, AK/Alaska, etc. + * + *

TODO: It seems more straight forward to return a list of pairs instead of RegionData. + * Actually, we can remove RegionData since it does not contain anything more than key/value + * pairs now. + * + * @return A list of sub-regions, each sub-region represented by a {@link RegionData}. + */ + List getRegionData(LookupKey key) { + if (key.getKeyType() == KeyType.EXAMPLES) { + throw new RuntimeException("example key not allowed for getting region data"); } - - /** - * Gets a list of {@link RegionData} for sub-regions for a given key. For example, sub regions - * for "data/US" are AL/Alabama, AK/Alaska, etc. - * - *

TODO: It seems more straight forward to return a list of pairs instead of RegionData. - * Actually, we can remove RegionData since it does not contain anything more than key/value - * pairs now. - * - * @return A list of sub-regions, each sub-region represented by a {@link RegionData}. - */ - List getRegionData(LookupKey key) { - if (key.getKeyType() == KeyType.EXAMPLES) { - throw new RuntimeException("example key not allowed for getting region data"); - } - Util.checkNotNull(key, "null regionKey not allowed"); - LookupKey normalizedKey = normalizeLookupKey(key); - List results = new ArrayList(); - - // Root key. - if (normalizedKey.equals(ROOT_KEY)) { - AddressVerificationNodeData data = - mIntegratedData.getDefaultData(normalizedKey.toString()); - String[] countries = splitData(data.get(AddressDataKey.COUNTRIES)); - for (int i = 0; i < countries.length; i++) { - RegionData rd = new RegionData.Builder() - .setKey(countries[i]) - .setName(countries[i]) - .build(); - results.add(rd); - } - return results; - } - - AddressVerificationNodeData data = - mIntegratedData.get(normalizedKey.toString()); - if (data != null) { - String[] keys = splitData(data.get(AddressDataKey.SUB_KEYS)); - String[] names = (getScriptType() == ScriptType.LOCAL) - ? splitData(data.get(AddressDataKey.SUB_NAMES)) - : splitData(data.get(AddressDataKey.SUB_LNAMES)); - - for (int i = 0; i < keys.length; i++) { - RegionData rd = - new RegionData.Builder() - .setKey(keys[i]) - .setName((i < names.length) ? names[i] : keys[i]) - .build(); - results.add(rd); - } - } - return results; + Util.checkNotNull(key, "null regionKey not allowed"); + LookupKey normalizedKey = normalizeLookupKey(key); + List results = new ArrayList(); + + // Root key. + if (normalizedKey.equals(ROOT_KEY)) { + AddressVerificationNodeData data = + integratedData.getDefaultData(normalizedKey.toString()); + String[] countries = splitData(data.get(AddressDataKey.COUNTRIES)); + for (int i = 0; i < countries.length; i++) { + RegionData rd = new RegionData.Builder() + .setKey(countries[i]) + .setName(countries[i]) + .build(); + results.add(rd); + } + return results; } - /** - * Split a '~' delimited string into an array of strings. This method is null tolerant and - * considers an empty string to contain no elements. - * - * @param raw The data to split - * @return an array of strings - */ - private String[] splitData(String raw) { - if (raw == null || raw.length() == 0) { - return new String[]{}; - } - return raw.split(TILDE_DELIM); + AddressVerificationNodeData data = + integratedData.get(normalizedKey.toString()); + if (data != null) { + String[] keys = splitData(data.get(AddressDataKey.SUB_KEYS)); + String[] names = (getScriptType() == ScriptType.LOCAL) + ? splitData(data.get(AddressDataKey.SUB_NAMES)) + : splitData(data.get(AddressDataKey.SUB_LNAMES)); + + for (int i = 0; i < keys.length; i++) { + RegionData rd = new RegionData.Builder() + .setKey(keys[i]) + .setName((i < names.length) ? names[i] : keys[i]) + .build(); + results.add(rd); + } } - - private String getSubKey(LookupKey parentKey, String name) { - for (RegionData subRegion : getRegionData(parentKey)) { - if (subRegion.isValidName(name)) { - return subRegion.getKey(); - } - } - return null; + return results; + } + + /** + * Split a '~' delimited string into an array of strings. This method is null tolerant and + * considers an empty string to contain no elements. + * + * @param raw The data to split + * @return an array of strings + */ + private String[] splitData(String raw) { + if (raw == null || raw.length() == 0) { + return new String[]{}; + } + return raw.split(TILDE_DELIM); + } + + private String getSubKey(LookupKey parentKey, String name) { + for (RegionData subRegion : getRegionData(parentKey)) { + if (subRegion.isValidName(name)) { + return subRegion.getKey(); + } + } + return null; + } + + /** + * Normalizes {@code key} by replacing field values with sub-keys. For example, California is + * replaced with CA. The normalization goes from top (country) to bottom (dependent locality) + * and if any field value is empty, unknown, or invalid, it will stop and return whatever it + * gets. For example, a key "data/US/California/foobar/kar" will be normalized into + * "data/US/CA/foobar/kar" since "foobar" is unknown. This method supports only key of + * {@link KeyType#DATA} type. + * + * @return normalized {@link LookupKey}. + */ + private LookupKey normalizeLookupKey(LookupKey key) { + Util.checkNotNull(key); + if (key.getKeyType() != KeyType.DATA) { + throw new RuntimeException("Only DATA keyType is supported"); } - /** - * Normalizes {@code key} by replacing field values with sub-keys. For example, California is - * replaced with CA. The normalization goes from top (country) to bottom (dependent locality) - * and if any field value is empty, unknown, or invalid, it will stop and return whatever it - * gets. For example, a key "data/US/California/foobar/kar" will be normalized into - * "data/US/CA/foobar/kar" since "foobar" is unknown. This method supports only key of - * {@link KeyType#DATA} type. - * - * @return normalized {@link LookupKey}. - */ - private LookupKey normalizeLookupKey(LookupKey key) { - Util.checkNotNull(key); - if (key.getKeyType() != KeyType.DATA) { - throw new RuntimeException("Only DATA keyType is supported"); - } - - String subStr[] = key.toString().split(SLASH_DELIM); - - // Root key does not need to be normalized. - if (subStr.length < 2) { - return key; - } - - StringBuilder sb = new StringBuilder(subStr[0]); - for (int i = 1; i < subStr.length; ++i) { - // Strips the language code if contained. - String languageCode = null; - if (i == 1 && subStr[i].contains(DASH_DELIM)) { - String[] s = subStr[i].split(DASH_DELIM); - subStr[i] = s[0]; - languageCode = s[1]; - } + String subStr[] = key.toString().split(SLASH_DELIM); - String normalizedSubKey = getSubKey(new LookupKey.Builder(sb.toString()).build(), - subStr[i]); + // Root key does not need to be normalized. + if (subStr.length < 2) { + return key; + } - // Can't find normalized sub-key; assembles the lookup key with the - // remaining sub-keys and returns it. - if (normalizedSubKey == null) { - for (; i < subStr.length; ++i) { - sb.append(SLASH_DELIM).append(subStr[i]); - } - break; - } - sb.append(SLASH_DELIM).append(normalizedSubKey); - if (languageCode != null) { - sb.append(DASH_DELIM).append(languageCode); - } + StringBuilder sb = new StringBuilder(subStr[0]); + for (int i = 1; i < subStr.length; ++i) { + // Strips the language code if contained. + String languageCode = null; + if (i == 1 && subStr[i].contains(DASH_DELIM)) { + String[] s = subStr[i].split(DASH_DELIM); + subStr[i] = s[0]; + languageCode = s[1]; + } + + String normalizedSubKey = getSubKey(new LookupKey.Builder(sb.toString()).build(), + subStr[i]); + + // Can't find normalized sub-key; assembles the lookup key with the + // remaining sub-keys and returns it. + if (normalizedSubKey == null) { + for (; i < subStr.length; ++i) { + sb.append(SLASH_DELIM).append(subStr[i]); } - return new LookupKey.Builder(sb.toString()).build(); + break; + } + sb.append(SLASH_DELIM).append(normalizedSubKey); + if (languageCode != null) { + sb.append(DASH_DELIM).append(languageCode); + } } + return new LookupKey.Builder(sb.toString()).build(); + } } diff --git a/java/src/com/android/i18n/addressinput/FormOptions.java b/java/src/com/android/i18n/addressinput/FormOptions.java index 07bc38e..2b9bee6 100644 --- a/java/src/com/android/i18n/addressinput/FormOptions.java +++ b/java/src/com/android/i18n/addressinput/FormOptions.java @@ -31,257 +31,257 @@ import java.util.Map; */ public class FormOptions { - private final String mBaseId; + private final String baseId; + + private final EnumSet hiddenFields; + + private final EnumSet readonlyFields; + + private final EnumSet requiredFields; + + private final EnumMap customLabels = + new EnumMap(AddressField.class); + + private final Map overrideFieldOrder = + new HashMap(); + + private final EnumMap maxLengths = + new EnumMap(AddressField.class); + + private final String serverUrl; + + private FormOptions(Builder builder) { + // copy values from builder + baseId = builder.baseId; + hiddenFields = EnumSet.copyOf(builder.hiddenFields); + readonlyFields = EnumSet.copyOf(builder.readonlyFields); + requiredFields = EnumSet.copyOf(builder.requiredFields); + customLabels.putAll(builder.customLabels); + overrideFieldOrder.putAll(builder.overrideFieldOrder); + maxLengths.putAll(builder.maxLengths); + serverUrl = builder.serverUrl; + } + + /** + * Gets base ID of the address form. Default is "addressform". + */ + String getBaseId() { + return baseId; + } + + boolean isHidden(AddressField field) { + return hiddenFields.contains(field); + } + + boolean isReadonly(AddressField field) { + return readonlyFields.contains(field); + } + + boolean isRequired(AddressField field) { + return requiredFields.contains(field); + } + + EnumSet getRequiredFields() { + return requiredFields; + } + + /** + * Gets the customized label for the {@code field}, or returns null if none. + */ + String getCustomLabel(AddressField field) { + return customLabels.get(field); + } + + /** + * Gets the URL of the Address Data Server. + */ + String getUrl() { + return serverUrl; + } + + /** + * Gets the overridden field orders with their corresponding region code. Returns null if field + * orders for {@code regionCode} is not specified. + */ + AddressField[] getCustomFieldOrder(String regionCode) { + if (regionCode == null) { + throw new RuntimeException("regionCode cannot be null."); + } + return overrideFieldOrder.get(regionCode); + } - private final EnumSet mHiddenFields; + /** + * Gets the customized max length for the {@code field}, or null if none. + */ + Integer getCustomMaxLength(AddressField field) { + return maxLengths.get(field); + } - private final EnumSet mReadonlyFields; + /** + * Class to build the form, specifying the attributes for each field. + */ + public static class Builder { - private final EnumSet mRequiredFields; + private String baseId = "addressform"; - private final EnumMap mCustomLabels = - new EnumMap(AddressField.class); + private final EnumSet requiredFields = + EnumSet.noneOf(AddressField.class); - private final Map mOverrideFieldOrder = - new HashMap(); + private final EnumSet hiddenFields = + EnumSet.noneOf(AddressField.class); - private final EnumMap mMaxLengths = - new EnumMap(AddressField.class); + private final EnumSet readonlyFields = + EnumSet.noneOf(AddressField.class); - private final String mServerUrl; + private final EnumMap customLabels = + new EnumMap(AddressField.class); - private FormOptions(Builder builder) { - // copy values from builder - mBaseId = builder.mBaseId; - mHiddenFields = EnumSet.copyOf(builder.mHiddenFields); - mReadonlyFields = EnumSet.copyOf(builder.mReadonlyFields); - mRequiredFields = EnumSet.copyOf(builder.mRequiredFields); - mCustomLabels.putAll(builder.mCustomLabels); - mOverrideFieldOrder.putAll(builder.mOverrideFieldOrder); - mMaxLengths.putAll(builder.mMaxLengths); - mServerUrl = builder.mServerUrl; - } + private final Map overrideFieldOrder = + new HashMap(); + + private final EnumMap maxLengths = + new EnumMap(AddressField.class); /** - * Gets base ID of the address form. Default is "addressform". + * Uses the default server URL from CacheData. */ - String getBaseId() { - return mBaseId; - } + private String serverUrl = new CacheData().getUrl(); - boolean isHidden(AddressField field) { - return mHiddenFields.contains(field); - } - - boolean isReadonly(AddressField field) { - return mReadonlyFields.contains(field); + /** + * Sets the base ID of the address form. + */ + public Builder baseId(String baseId) { + if (baseId == null) { + throw new RuntimeException("baseId cannot be null."); + } + baseId = baseId; + return this; } - boolean isRequired(AddressField field) { - return mRequiredFields.contains(field); + public Builder hide(AddressField field) { + if (field == null) { + throw new RuntimeException("AddressField field cannot be null."); + } + hiddenFields.add(field); + return this; } - EnumSet getRequiredFields() { - return mRequiredFields; + /** + * Make a field read-only. + */ + public Builder readonly(AddressField field) { + if (field == null) { + throw new RuntimeException("AddressField field cannot be null."); + } + readonlyFields.add(field); + return this; } /** - * Gets the customized label for the {@code field}, or returns null if none. + * Make a field required. */ - String getCustomLabel(AddressField field) { - return mCustomLabels.get(field); + public Builder required(AddressField field) { + if (field == null) { + throw new RuntimeException("AddressField field cannot be null."); + } + requiredFields.add(field); + return this; } /** - * Gets the URL of the Address Data Server. + * Customizes label for an {@code AddressField}. */ - String getUrl() { - return mServerUrl; + public Builder customizeLabel(AddressField field, String label) { + if (field == null) { + throw new RuntimeException("AddressField field cannot be null."); + } + if (label == null) { + throw new RuntimeException("Label cannot be null."); + } + customLabels.put(field, label); + return this; } /** - * Gets the overridden field orders with their corresponding region code. Returns null if field - * orders for {@code regionCode} is not specified. + * Sets the field order for a region code. The order you set here will override the + * predefined one. For example, you can set field order for US to be first {@code + * AddressField#ORGANIZATION} then {@code AddressField#RECIPIENT}. Repeated address fields + * in {@code fields} are not allowed. Size of {@code fields} has to be larger than one. + * Input {@code fields} can be partial or even contain field not needed in the specified + * {@code regionCode}. For example, German addresses contain the following fields + * (in order):
+ {@link AddressField#RECIPIENT}, {@link AddressField#ORGANIZATION}, {@link + * AddressField#STREET_ADDRESS}, {@link AddressField#POSTAL_CODE}, {@link + * AddressField#LOCALITY}.
+ * + *

With the following call:
+ * + * customizeFieldOrder("DE", AddressField.ORGANIZATION, AddressField.RECIPIENT, + * AddressField.ADMIN_AREA); + * + *

Field order for Germany will become:
{@link AddressField#ORGANIZATION}, {@link + * AddressField#RECIPIENT}, {@link AddressField#STREET_ADDRESS}, {@link + * AddressField#POSTAL_CODE}, {@link AddressField#LOCALITY}.

+ * + *

Notice that:

  1. {@link AddressField#ORGANIZATION} comes before {@link + * AddressField#RECIPIENT} after reordering.
  2. + *
  3. Fields not specified stays the same.
  4. + *
  5. {@link AddressField#ADMIN_AREA} is specified but since it is not in German address + * format, it is simpled neglected.
+ * + * @param fields the overridden field order. */ - AddressField[] getCustomFieldOrder(String regionCode) { - if (regionCode == null) { - throw new RuntimeException("regionCode cannot be null."); + public Builder customizeFieldOrder(String regionCode, AddressField... fields) { + if (regionCode == null) { + throw new RuntimeException("regionCode cannot be null."); + } + if (fields == null) { + throw new RuntimeException("Fields cannot be null."); + } + if (fields.length <= 1) { + throw new RuntimeException("There must be more than one field."); + } + HashSet checkList = new HashSet(); + AddressField[] f = new AddressField[fields.length]; + int i = 0; + for (AddressField field : fields) { + // Can't contain repeated address fields. + if (checkList.contains(field)) { + throw new RuntimeException("Address fields cannot be repeated."); } - return mOverrideFieldOrder.get(regionCode); + checkList.add(field); + f[i] = field; + i++; + } + overrideFieldOrder.put(regionCode, f); + return this; } /** - * Gets the customized max length for the {@code field}, or null if none. + * Sets the URL of address data server. {@code url} cannot be null. This url will override + * the default address server url. */ - Integer getCustomMaxLength(AddressField field) { - return mMaxLengths.get(field); + public Builder setUrl(String url) { + if (url == null) { + throw new RuntimeException("Can't set address server URL to null."); + } + serverUrl = url; + return this; } /** - * Class to build the form, specifying the attributes for each field. + * Customizes max length for a {@code AddressField}. */ - public static class Builder { - - private String mBaseId = "addressform"; - - private final EnumSet mRequiredFields = - EnumSet.noneOf(AddressField.class); - - private final EnumSet mHiddenFields = - EnumSet.noneOf(AddressField.class); - - private final EnumSet mReadonlyFields = - EnumSet.noneOf(AddressField.class); - - private final EnumMap mCustomLabels = - new EnumMap(AddressField.class); - - private final Map mOverrideFieldOrder = - new HashMap(); - - private final EnumMap mMaxLengths = - new EnumMap(AddressField.class); - - /** - * Uses the default server URL from CacheData. - */ - private String mServerUrl = new CacheData().getUrl(); - - /** - * Sets the base ID of the address form. - */ - public Builder baseId(String baseId) { - if (baseId == null) { - throw new RuntimeException("baseId cannot be null."); - } - mBaseId = baseId; - return this; - } - - public Builder hide(AddressField field) { - if (field == null) { - throw new RuntimeException("AddressField field cannot be null."); - } - mHiddenFields.add(field); - return this; - } - - /** - * Make a field read-only. - */ - public Builder readonly(AddressField field) { - if (field == null) { - throw new RuntimeException("AddressField field cannot be null."); - } - mReadonlyFields.add(field); - return this; - } - - /** - * Make a field required. - */ - public Builder required(AddressField field) { - if (field == null) { - throw new RuntimeException("AddressField field cannot be null."); - } - mRequiredFields.add(field); - return this; - } - - /** - * Customizes label for an {@code AddressField}. - */ - public Builder customizeLabel(AddressField field, String label) { - if (field == null) { - throw new RuntimeException("AddressField field cannot be null."); - } - if (label == null) { - throw new RuntimeException("Label cannot be null."); - } - mCustomLabels.put(field, label); - return this; - } - - /** - * Sets the field order for a region code. The order you set here will override the - * predefined one. For example, you can set field order for US to be first {@code - * AddressField#ORGANIZATION} then {@code AddressField#RECIPIENT}. Repeated address fields - * in {@code fields} are not allowed. Size of {@code fields} has to be larger than one. - * Input {@code fields} can be partial or even contain field not needed in the specified - * {@code regionCode}. For example, German addresses contain the following fields - * (in order):
- {@link AddressField#RECIPIENT}, {@link AddressField#ORGANIZATION}, {@link - * AddressField#STREET_ADDRESS}, {@link AddressField#POSTAL_CODE}, {@link - * AddressField#LOCALITY}.
- * - *

With the following call:
- * - * customizeFieldOrder("DE", AddressField.ORGANIZATION, AddressField.RECIPIENT, - * AddressField.ADMIN_AREA); - * - *

Field order for Germany will become:
{@link AddressField#ORGANIZATION}, {@link - * AddressField#RECIPIENT}, {@link AddressField#STREET_ADDRESS}, {@link - * AddressField#POSTAL_CODE}, {@link AddressField#LOCALITY}.

- * - *

Notice that:

  1. {@link AddressField#ORGANIZATION} comes before {@link - * AddressField#RECIPIENT} after reordering.
  2. - *
  3. Fields not specified stays the same.
  4. - *
  5. {@link AddressField#ADMIN_AREA} is specified but since it is not in German address - * format, it is simpled neglected.
- * - * @param fields the overridden field order. - */ - public Builder customizeFieldOrder(String regionCode, AddressField... fields) { - if (regionCode == null) { - throw new RuntimeException("regionCode cannot be null."); - } - if (fields == null) { - throw new RuntimeException("Fields cannot be null."); - } - if (fields.length <= 1) { - throw new RuntimeException("There must be more than one field."); - } - HashSet checkList = new HashSet(); - AddressField[] f = new AddressField[fields.length]; - int i = 0; - for (AddressField field : fields) { - // Can't contain repeated address fields. - if (checkList.contains(field)) { - throw new RuntimeException("Address fields cannot be repeated."); - } - checkList.add(field); - f[i] = field; - i++; - } - mOverrideFieldOrder.put(regionCode, f); - return this; - } - - /** - * Sets the URL of address data server. {@code url} cannot be null. This url will override - * the default address server url. - */ - public Builder setUrl(String url) { - if (url == null) { - throw new RuntimeException("Can't set address server URL to null."); - } - mServerUrl = url; - return this; - } - - /** - * Customizes max length for a {@code AddressField}. - */ - public Builder customizeMaxLength(AddressField field, int maxLength) { - if (field == null) { - throw new RuntimeException("AddressField field cannot be null."); - } - mMaxLengths.put(field, maxLength); - return this; - } + public Builder customizeMaxLength(AddressField field, int maxLength) { + if (field == null) { + throw new RuntimeException("AddressField field cannot be null."); + } + maxLengths.put(field, maxLength); + return this; + } - public FormOptions build() { - return new FormOptions(this); - } + public FormOptions build() { + return new FormOptions(this); } + } } diff --git a/java/src/com/android/i18n/addressinput/FormatInterpreter.java b/java/src/com/android/i18n/addressinput/FormatInterpreter.java index e59b79e..8634cfb 100644 --- a/java/src/com/android/i18n/addressinput/FormatInterpreter.java +++ b/java/src/com/android/i18n/addressinput/FormatInterpreter.java @@ -36,275 +36,275 @@ import java.util.Set; */ class FormatInterpreter { - private static final String NEW_LINE = "%n"; - - private final String mDefaultFormat; - - private final FormOptions mFormOptions; - - /** - * Creates a new instance of {@link FormatInterpreter}. - */ - FormatInterpreter(FormOptions options) { - Util.checkNotNull(RegionDataConstants.getCountryFormatMap(), - "null country name map not allowed"); - Util.checkNotNull(options); - mFormOptions = options; - mDefaultFormat = getJsonValue("ZZ", AddressDataKey.FMT); - Util.checkNotNull(mDefaultFormat, "null default format not allowed"); + private static final String NEW_LINE = "%n"; + + private final String defaultFormat; + + private final FormOptions formOptions; + + /** + * Creates a new instance of {@link FormatInterpreter}. + */ + FormatInterpreter(FormOptions options) { + Util.checkNotNull(RegionDataConstants.getCountryFormatMap(), + "null country name map not allowed"); + Util.checkNotNull(options); + formOptions = options; + defaultFormat = getJsonValue("ZZ", AddressDataKey.FMT); + Util.checkNotNull(defaultFormat, "null default format not allowed"); + } + + /** + * Returns a list of address fields based on the format of {@code regionCode}. Script type is + * needed because some countries uses different address formats for local/Latin scripts. + * + * @param scriptType if {@link ScriptType#LOCAL}, use local format; else use Latin format. + */ + List getAddressFieldOrder(ScriptType scriptType, String regionCode) { + Util.checkNotNull(scriptType); + Util.checkNotNull(regionCode); + List fieldOrder = new ArrayList(); + for (String substring : getFormatSubStrings(scriptType, regionCode)) { + // Skips un-escaped characters and new lines. + if (!substring.matches("%.") || substring.equals(NEW_LINE)) { + continue; + } + + AddressField field = AddressField.of(substring.charAt(1)); + fieldOrder.add(field); } - /** - * Returns a list of address fields based on the format of {@code regionCode}. Script type is - * needed because some countries uses different address formats for local/Latin scripts. - * - * @param scriptType if {@link ScriptType#LOCAL}, use local format; else use Latin format. - */ - List getAddressFieldOrder(ScriptType scriptType, String regionCode) { - Util.checkNotNull(scriptType); - Util.checkNotNull(regionCode); - List fieldOrder = new ArrayList(); - for (String substring : getFormatSubStrings(scriptType, regionCode)) { - // Skips un-escaped characters and new lines. - if (!substring.matches("%.") || substring.equals(NEW_LINE)) { - continue; - } - - AddressField field = AddressField.of(substring.charAt(1)); - fieldOrder.add(field); - } - - overrideFieldOrder(regionCode, fieldOrder); - - // Uses two address lines instead of street address. - List finalFieldOrder = new ArrayList(); - for (AddressField field : fieldOrder) { - if (field == AddressField.STREET_ADDRESS) { - finalFieldOrder.add(AddressField.ADDRESS_LINE_1); - finalFieldOrder.add(AddressField.ADDRESS_LINE_2); - } else { - finalFieldOrder.add(field); - } - } - return finalFieldOrder; + overrideFieldOrder(regionCode, fieldOrder); + + // Uses two address lines instead of street address. + List finalFieldOrder = new ArrayList(); + for (AddressField field : fieldOrder) { + if (field == AddressField.STREET_ADDRESS) { + finalFieldOrder.add(AddressField.ADDRESS_LINE_1); + finalFieldOrder.add(AddressField.ADDRESS_LINE_2); + } else { + finalFieldOrder.add(field); + } } - - /** - * Returns a list of address fields based on the format of {@code regionCode} -- assuming script - * type is {@link ScriptType#LOCAL}. - */ - List getAddressFieldOrder(String regionCode) { - Util.checkNotNull(regionCode); - return getAddressFieldOrder(ScriptType.LOCAL, regionCode); + return finalFieldOrder; + } + + /** + * Returns a list of address fields based on the format of {@code regionCode} -- assuming script + * type is {@link ScriptType#LOCAL}. + */ + List getAddressFieldOrder(String regionCode) { + Util.checkNotNull(regionCode); + return getAddressFieldOrder(ScriptType.LOCAL, regionCode); + } + + private void overrideFieldOrder(String regionCode, List fieldOrder) { + if (formOptions.getCustomFieldOrder(regionCode) == null) { + return; } - private void overrideFieldOrder(String regionCode, List fieldOrder) { - if (mFormOptions.getCustomFieldOrder(regionCode) == null) { - return; - } - - // Constructs a hash for overridden field order. - final Map fieldPriority = new HashMap(); - int i = 0; - for (AddressField field : mFormOptions.getCustomFieldOrder(regionCode)) { - fieldPriority.put(field, i); - i++; - } - - // Finds union of input fields and priority list. - List union = new ArrayList(); - List slots = new ArrayList(); - i = 0; - for (AddressField field : fieldOrder) { - if (fieldPriority.containsKey(field)) { - union.add(field); - slots.add(i); - } - i++; - } - - // Overrides field order with priority list. - Collections.sort(union, new Comparator() { - @Override - public int compare(AddressField o1, AddressField o2) { - return fieldPriority.get(o1) - fieldPriority.get(o2); - } - }); - - // Puts reordered fields in slots. - for (int j = 0; j < union.size(); ++j) { - fieldOrder.set(slots.get(j), union.get(j)); - } + // Constructs a hash for overridden field order. + final Map fieldPriority = new HashMap(); + int i = 0; + for (AddressField field : formOptions.getCustomFieldOrder(regionCode)) { + fieldPriority.put(field, i); + i++; } - /** - * Returns the fields that are required to be filled in for this country. This is based upon the - * "required" field in RegionDataConstants for {@code regionCode}, and handles falling back to - * the default data if necessary. - */ - static Set getRequiredFields(String regionCode) { - Util.checkNotNull(regionCode); - String requireString = getRequiredString(regionCode); - - EnumSet required = EnumSet.of(AddressField.COUNTRY); - for (char c : requireString.toCharArray()) { - required.add(AddressField.of(c)); - } - return required; + // Finds union of input fields and priority list. + List union = new ArrayList(); + List slots = new ArrayList(); + i = 0; + for (AddressField field : fieldOrder) { + if (fieldPriority.containsKey(field)) { + union.add(field); + slots.add(i); + } + i++; } - private static String getRequiredString(String regionCode) { - String required = getJsonValue(regionCode, AddressDataKey.REQUIRE); - if (required == null) { - required = getJsonValue("ZZ", AddressDataKey.REQUIRE); - } - return required; + // Overrides field order with priority list. + Collections.sort(union, new Comparator() { + @Override + public int compare(AddressField o1, AddressField o2) { + return fieldPriority.get(o1) - fieldPriority.get(o2); + } + }); + + // Puts reordered fields in slots. + for (int j = 0; j < union.size(); ++j) { + fieldOrder.set(slots.get(j), union.get(j)); } + } + + /** + * Returns the fields that are required to be filled in for this country. This is based upon the + * "required" field in RegionDataConstants for {@code regionCode}, and handles falling back to + * the default data if necessary. + */ + static Set getRequiredFields(String regionCode) { + Util.checkNotNull(regionCode); + String requireString = getRequiredString(regionCode); + + EnumSet required = EnumSet.of(AddressField.COUNTRY); + for (char c : requireString.toCharArray()) { + required.add(AddressField.of(c)); + } + return required; + } - /** - * Gets formatted address. For example, - * - *

John Doe
Dnar Corp
5th St
Santa Monica CA 90123

- * - * This method does not validate addresses. Also, it will "normalize" the result strings by - * removing redundant spaces and empty lines. - */ - List getEnvelopeAddress(AddressData address) { - Util.checkNotNull(address, "null input address not allowed"); - String regionCode = address.getPostalCountry(); - - String lc = address.getLanguageCode(); - ScriptType scriptType = ScriptType.LOCAL; - if (lc != null) { - scriptType = Util.isExplicitLatinScript(lc) ? ScriptType.LATIN : ScriptType.LOCAL; - } + private static String getRequiredString(String regionCode) { + String required = getJsonValue(regionCode, AddressDataKey.REQUIRE); + if (required == null) { + required = getJsonValue("ZZ", AddressDataKey.REQUIRE); + } + return required; + } + + /** + * Gets formatted address. For example, + * + *

John Doe
Dnar Corp
5th St
Santa Monica CA 90123

+ * + * This method does not validate addresses. Also, it will "normalize" the result strings by + * removing redundant spaces and empty lines. + */ + List getEnvelopeAddress(AddressData address) { + Util.checkNotNull(address, "null input address not allowed"); + String regionCode = address.getPostalCountry(); + + String lc = address.getLanguageCode(); + ScriptType scriptType = ScriptType.LOCAL; + if (lc != null) { + scriptType = Util.isExplicitLatinScript(lc) ? ScriptType.LATIN : ScriptType.LOCAL; + } - List lines = new ArrayList(); - StringBuilder currentLine = new StringBuilder(); - for (String formatSymbol : getFormatSubStrings(scriptType, regionCode)) { - if (formatSymbol.equals(NEW_LINE)) { - String normalizedStr = - removeRedundantSpacesAndLeadingPunctuation(currentLine.toString()); - if (normalizedStr.length() > 0) { - lines.add(normalizedStr); - currentLine.setLength(0); - } - } else if (formatSymbol.startsWith("%")) { - char c = formatSymbol.charAt(1); - AddressField field = AddressField.of(c); - Util.checkNotNull(field, "null address field for character " + c); - - String value = null; - switch (field) { - case STREET_ADDRESS: - value = Util.joinAndSkipNulls("\n", - address.getAddressLine1(), - address.getAddressLine2()); - break; - case COUNTRY: - // Country name is treated separately. - break; - case ADMIN_AREA: - value = address.getAdministrativeArea(); - break; - case LOCALITY: - value = address.getLocality(); - break; - case DEPENDENT_LOCALITY: - value = address.getDependentLocality(); - break; - case RECIPIENT: - value = address.getRecipient(); - break; - case ORGANIZATION: - value = address.getOrganization(); - break; - case POSTAL_CODE: - value = address.getPostalCode(); - break; - default: - break; - } - - if (value != null) { - currentLine.append(value); - } - } else { - currentLine.append(formatSymbol); - } - } - String normalizedStr = removeRedundantSpacesAndLeadingPunctuation(currentLine.toString()); + List lines = new ArrayList(); + StringBuilder currentLine = new StringBuilder(); + for (String formatSymbol : getFormatSubStrings(scriptType, regionCode)) { + if (formatSymbol.equals(NEW_LINE)) { + String normalizedStr = + removeRedundantSpacesAndLeadingPunctuation(currentLine.toString()); if (normalizedStr.length() > 0) { - lines.add(normalizedStr); + lines.add(normalizedStr); + currentLine.setLength(0); + } + } else if (formatSymbol.startsWith("%")) { + char c = formatSymbol.charAt(1); + AddressField field = AddressField.of(c); + Util.checkNotNull(field, "null address field for character " + c); + + String value = null; + switch (field) { + case STREET_ADDRESS: + value = Util.joinAndSkipNulls("\n", + address.getAddressLine1(), + address.getAddressLine2()); + break; + case COUNTRY: + // Country name is treated separately. + break; + case ADMIN_AREA: + value = address.getAdministrativeArea(); + break; + case LOCALITY: + value = address.getLocality(); + break; + case DEPENDENT_LOCALITY: + value = address.getDependentLocality(); + break; + case RECIPIENT: + value = address.getRecipient(); + break; + case ORGANIZATION: + value = address.getOrganization(); + break; + case POSTAL_CODE: + value = address.getPostalCode(); + break; + default: + break; } - return lines; - } - /** - * Tokenizes the format string and returns the token string list. "%" is treated as an escape - * character. So for example "%n%a%nxyz" will be split into "%n", "%a", "%n", "x", "y", and "z". - * Escaped tokens correspond to either new line or address fields. - */ - private List getFormatSubStrings(ScriptType scriptType, String regionCode) { - String formatString = getFormatString(scriptType, regionCode); - List parts = new ArrayList(); - - boolean escaped = false; - for (char c : formatString.toCharArray()) { - if (escaped) { - escaped = false; - if (NEW_LINE.equals("%" + c)) { - parts.add(NEW_LINE); - } else { - Util.checkNotNull(AddressField.of(c), "Unrecognized character '" + c - + "' in format pattern: " + formatString); - parts.add("%" + c); - } - } else if (c == '%') { - escaped = true; - } else { - parts.add(c + ""); - } + if (value != null) { + currentLine.append(value); } - return parts; + } else { + currentLine.append(formatSymbol); + } } - - private static String removeRedundantSpacesAndLeadingPunctuation(String str) { - // Remove leading commas and other punctuation that might have been added by the formatter - // in the case of missing data. - str = str.replaceFirst("^[-,\\s]+", ""); - str = str.trim(); - str = str.replaceAll(" +", " "); - return str; + String normalizedStr = removeRedundantSpacesAndLeadingPunctuation(currentLine.toString()); + if (normalizedStr.length() > 0) { + lines.add(normalizedStr); } - - private static String getFormatString(ScriptType scriptType, String regionCode) { - String format = (scriptType == ScriptType.LOCAL) - ? getJsonValue(regionCode, AddressDataKey.FMT) - : getJsonValue(regionCode, AddressDataKey.LFMT); - if (format == null) { - format = getJsonValue("ZZ", AddressDataKey.FMT); + return lines; + } + + /** + * Tokenizes the format string and returns the token string list. "%" is treated as an escape + * character. So for example "%n%a%nxyz" will be split into "%n", "%a", "%n", "x", "y", and "z". + * Escaped tokens correspond to either new line or address fields. + */ + private List getFormatSubStrings(ScriptType scriptType, String regionCode) { + String formatString = getFormatString(scriptType, regionCode); + List parts = new ArrayList(); + + boolean escaped = false; + for (char c : formatString.toCharArray()) { + if (escaped) { + escaped = false; + if (NEW_LINE.equals("%" + c)) { + parts.add(NEW_LINE); + } else { + Util.checkNotNull(AddressField.of(c), "Unrecognized character '" + c + + "' in format pattern: " + formatString); + parts.add("%" + c); } - return format; + } else if (c == '%') { + escaped = true; + } else { + parts.add(c + ""); + } } - - private static String getJsonValue(String regionCode, AddressDataKey key) { - Util.checkNotNull(regionCode); - String jsonString = RegionDataConstants.getCountryFormatMap().get(regionCode); - Util.checkNotNull(jsonString, "no json data for region code " + regionCode); - - try { - JSONObject jsonObj = new JSONObject(new JSONTokener(jsonString)); - if (!jsonObj.has(key.name().toLowerCase())) { - // Key not found. Return null. - return null; - } - // Gets the string for this key. - String parsedJsonString = jsonObj.getString(key.name().toLowerCase()); - return parsedJsonString; - } catch (JSONException e) { - throw new RuntimeException("Invalid json for region code " + regionCode - + ": " + jsonString); - } + return parts; + } + + private static String removeRedundantSpacesAndLeadingPunctuation(String str) { + // Remove leading commas and other punctuation that might have been added by the formatter + // in the case of missing data. + str = str.replaceFirst("^[-,\\s]+", ""); + str = str.trim(); + str = str.replaceAll(" +", " "); + return str; + } + + private static String getFormatString(ScriptType scriptType, String regionCode) { + String format = (scriptType == ScriptType.LOCAL) + ? getJsonValue(regionCode, AddressDataKey.FMT) + : getJsonValue(regionCode, AddressDataKey.LFMT); + if (format == null) { + format = getJsonValue("ZZ", AddressDataKey.FMT); + } + return format; + } + + private static String getJsonValue(String regionCode, AddressDataKey key) { + Util.checkNotNull(regionCode); + String jsonString = RegionDataConstants.getCountryFormatMap().get(regionCode); + Util.checkNotNull(jsonString, "no json data for region code " + regionCode); + + try { + JSONObject jsonObj = new JSONObject(new JSONTokener(jsonString)); + if (!jsonObj.has(key.name().toLowerCase())) { + // Key not found. Return null. + return null; + } + // Gets the string for this key. + String parsedJsonString = jsonObj.getString(key.name().toLowerCase()); + return parsedJsonString; + } catch (JSONException e) { + throw new RuntimeException("Invalid json for region code " + regionCode + + ": " + jsonString); } + } } diff --git a/java/src/com/android/i18n/addressinput/JsoMap.java b/java/src/com/android/i18n/addressinput/JsoMap.java index fc5d16b..01e873b 100644 --- a/java/src/com/android/i18n/addressinput/JsoMap.java +++ b/java/src/com/android/i18n/addressinput/JsoMap.java @@ -29,256 +29,256 @@ import java.util.Iterator; */ class JsoMap extends JSONObject { - /** - * Construct a JsoMap object given some json text. This method directly evaluates the String - * that you pass in; no error or safety checking is performed, so be very careful about the - * source of your data. - * - * @param json JSON text describing an address format - * @return a JsoMap object made from the supplied JSON. - */ - static JsoMap buildJsoMap(String json) throws JSONException { - return new JsoMap(new JSONTokener(json)); - } + /** + * Construct a JsoMap object given some json text. This method directly evaluates the String + * that you pass in; no error or safety checking is performed, so be very careful about the + * source of your data. + * + * @param json JSON text describing an address format + * @return a JsoMap object made from the supplied JSON. + */ + static JsoMap buildJsoMap(String json) throws JSONException { + return new JsoMap(new JSONTokener(json)); + } - /** - * Construct an empty JsoMap. - * - * @return the empty object. - */ - static JsoMap createEmptyJsoMap() { - return new JsoMap(); - } + /** + * Construct an empty JsoMap. + * + * @return the empty object. + */ + static JsoMap createEmptyJsoMap() { + return new JsoMap(); + } - /** - * constructor. - */ - protected JsoMap() { - } + /** + * constructor. + */ + protected JsoMap() { + } - private JsoMap(JSONTokener readFrom) throws JSONException { - super(readFrom); - } + private JsoMap(JSONTokener readFrom) throws JSONException { + super(readFrom); + } - private JsoMap(JSONObject copyFrom, String[] names) throws JSONException { - super(copyFrom, names); - } + private JsoMap(JSONObject copyFrom, String[] names) throws JSONException { + super(copyFrom, names); + } - /** - * Remove the specified key. - * - * @param key key name. - */ - void delKey(String key) { - super.remove(key); - } + /** + * Remove the specified key. + * + * @param key key name. + */ + void delKey(String key) { + super.remove(key); + } - /** - * Retrieve the string value for specified key. - * - * @param key key name. - * @return string value. - * @throws ClassCastException, IllegalArgumentException. - */ - @Override - public String get(String key) { // throws ClassCastException, IllegalArgumentException - try { - Object o = super.get(key); - if (o instanceof String) { - return (String) o; - } else if (o instanceof Integer) { - throw new IllegalArgumentException(); - } else { - throw new ClassCastException(); - } - } catch (JSONException e) { - return null; - } + /** + * Retrieve the string value for specified key. + * + * @param key key name. + * @return string value. + * @throws ClassCastException, IllegalArgumentException. + */ + @Override + public String get(String key) { // throws ClassCastException, IllegalArgumentException + try { + Object o = super.get(key); + if (o instanceof String) { + return (String) o; + } else if (o instanceof Integer) { + throw new IllegalArgumentException(); + } else { + throw new ClassCastException(); + } + } catch (JSONException e) { + return null; } + } - /** - * Access JSONObject.get(String) which is shadowed by JsoMap.get(String). - * - * @param name A key string. - * @return The object associated with the key. - * @throws JSONException if the key is not found. - */ - private Object getObject(String name) throws JSONException { - return super.get(name); - } + /** + * Access JSONObject.get(String) which is shadowed by JsoMap.get(String). + * + * @param name A key string. + * @return The object associated with the key. + * @throws JSONException if the key is not found. + */ + private Object getObject(String name) throws JSONException { + return super.get(name); + } - /** - * Retrieves the integer value for specified key. - * - * @return integer value or -1 if value is undefined. - */ - @Override - public int getInt(String key) { - try { - Object o = super.get(key); - if (o instanceof Integer) { - return ((Integer) o).intValue(); - } else { - throw new RuntimeException("Something other than an int was returned"); - } - } catch (JSONException e) { - return -1; - } + /** + * Retrieves the integer value for specified key. + * + * @return integer value or -1 if value is undefined. + */ + @Override + public int getInt(String key) { + try { + Object o = super.get(key); + if (o instanceof Integer) { + return ((Integer) o).intValue(); + } else { + throw new RuntimeException("Something other than an int was returned"); + } + } catch (JSONException e) { + return -1; } + } - /** - * Collect all the keys and return as a JSONArray. - * - * @return A JSONArray that contains all the keys. - */ - JSONArray getKeys() { - return super.names(); - } + /** + * Collect all the keys and return as a JSONArray. + * + * @return A JSONArray that contains all the keys. + */ + JSONArray getKeys() { + return super.names(); + } - /** - * Retrieve the JsoMap object for specified key. - * - * @param key key name. - * @return JsoMap object. - * @throws ClassCastException, IllegalArgumentException. - */ - @SuppressWarnings("unchecked") - // JSONObject.keys() has no type information. - JsoMap getObj(String key) - throws ClassCastException, IllegalArgumentException { + /** + * Retrieve the JsoMap object for specified key. + * + * @param key key name. + * @return JsoMap object. + * @throws ClassCastException, IllegalArgumentException. + */ + @SuppressWarnings("unchecked") + // JSONObject.keys() has no type information. + JsoMap getObj(String key) + throws ClassCastException, IllegalArgumentException { try { - Object o = super.get(key); - if (o instanceof JSONObject) { - JSONObject value = (JSONObject) o; - ArrayList keys = new ArrayList(value.length()); - for (Iterator it = value.keys(); it.hasNext();) { - keys.add(it.next()); - } - String[] names = new String[keys.size()]; - return new JsoMap(value, keys.toArray(names)); - } else if (o instanceof Integer) { - throw new IllegalArgumentException(); - } else { - throw new ClassCastException(); + Object o = super.get(key); + if (o instanceof JSONObject) { + JSONObject value = (JSONObject) o; + ArrayList keys = new ArrayList(value.length()); + for (Iterator it = value.keys(); it.hasNext();) { + keys.add(it.next()); } + String[] names = new String[keys.size()]; + return new JsoMap(value, keys.toArray(names)); + } else if (o instanceof Integer) { + throw new IllegalArgumentException(); + } else { + throw new ClassCastException(); + } } catch (JSONException e) { - return null; + return null; } - } - - /** - * Check if the object has specified key. - * - * @param key The key name to be checked. - * @return true if key can be found. - */ - boolean containsKey(String key) { - return super.has(key); - } + } - /** - * Merge those keys not found in this object from specified object. - * - * @param obj The other object to be merged. - */ - void mergeData(JsoMap obj) { - if (obj == null) { - return; - } + /** + * Check if the object has specified key. + * + * @param key The key name to be checked. + * @return true if key can be found. + */ + boolean containsKey(String key) { + return super.has(key); + } - JSONArray names = obj.names(); - if (names == null) { - return; - } + /** + * Merge those keys not found in this object from specified object. + * + * @param obj The other object to be merged. + */ + void mergeData(JsoMap obj) { + if (obj == null) { + return; + } - for (int i = 0; i < names.length(); i++) { - try { - String name = names.getString(i); - try { - if (!super.has(name)) { - super.put(name, obj.getObject(name)); - } - } catch (JSONException e) { - throw new RuntimeException(e); - } - } catch (JSONException e) { - // Ignored. - } - } + JSONArray names = obj.names(); + if (names == null) { + return; } - /** - * Save a string to string mapping into this map. - * - * @param key the string key. - * @param value the String value. - */ - void put(String key, String value) { + for (int i = 0; i < names.length(); i++) { + try { + String name = names.getString(i); try { - super.put(key, value); + if (!super.has(name)) { + super.put(name, obj.getObject(name)); + } } catch (JSONException e) { - throw new RuntimeException(e); + throw new RuntimeException(e); } + } catch (JSONException e) { + // Ignored. + } } + } - /** - * Save a string to integer mapping into this map. - * - * @param key the string key. - * @param value the integer value. - */ - void putInt(String key, int value) { - try { - super.put(key, value); - } catch (JSONException e) { - throw new RuntimeException(e); - } + /** + * Save a string to string mapping into this map. + * + * @param key the string key. + * @param value the String value. + */ + void put(String key, String value) { + try { + super.put(key, value); + } catch (JSONException e) { + throw new RuntimeException(e); } + } - /** - * Save a string to JSONObject mapping into this map. - * - * @param key the string key. - * @param value a JSONObject as value. - */ - void putObj(String key, JSONObject value) { - try { - super.put(key, value); - } catch (JSONException e) { - throw new RuntimeException(e); - } + /** + * Save a string to integer mapping into this map. + * + * @param key the string key. + * @param value the integer value. + */ + void putInt(String key, int value) { + try { + super.put(key, value); + } catch (JSONException e) { + throw new RuntimeException(e); } + } - String string() throws ClassCastException, IllegalArgumentException { - StringBuilder sb = new StringBuilder("JsoMap[\n"); - JSONArray keys = getKeys(); - for (int i = 0; i < keys.length(); i++) { - String key; - try { - key = keys.getString(i); - } catch (JSONException e) { - throw new RuntimeException(e); - } - sb.append('(').append(key).append(':').append(get(key)).append(')').append('\n'); - } - sb.append(']'); - return sb.toString(); + /** + * Save a string to JSONObject mapping into this map. + * + * @param key the string key. + * @param value a JSONObject as value. + */ + void putObj(String key, JSONObject value) { + try { + super.put(key, value); + } catch (JSONException e) { + throw new RuntimeException(e); } + } - String map() throws ClassCastException, IllegalArgumentException { - StringBuilder sb = new StringBuilder("JsoMap[\n"); - JSONArray keys = getKeys(); - for (int i = 0; i < keys.length(); i++) { - String key; - try { - key = keys.getString(i); - } catch (JSONException e) { - throw new RuntimeException(e); - } - sb.append('(').append(key).append(':').append(getObj(key).string()).append(')') - .append('\n'); - } - sb.append(']'); - return sb.toString(); + String string() throws ClassCastException, IllegalArgumentException { + StringBuilder sb = new StringBuilder("JsoMap[\n"); + JSONArray keys = getKeys(); + for (int i = 0; i < keys.length(); i++) { + String key; + try { + key = keys.getString(i); + } catch (JSONException e) { + throw new RuntimeException(e); + } + sb.append('(').append(key).append(':').append(get(key)).append(')').append('\n'); + } + sb.append(']'); + return sb.toString(); + } + + String map() throws ClassCastException, IllegalArgumentException { + StringBuilder sb = new StringBuilder("JsoMap[\n"); + JSONArray keys = getKeys(); + for (int i = 0; i < keys.length(); i++) { + String key; + try { + key = keys.getString(i); + } catch (JSONException e) { + throw new RuntimeException(e); + } + sb.append('(').append(key).append(':').append(getObj(key).string()).append(')') + .append('\n'); } + sb.append(']'); + return sb.toString(); + } } diff --git a/java/src/com/android/i18n/addressinput/JsonpRequestBuilder.java b/java/src/com/android/i18n/addressinput/JsonpRequestBuilder.java index 0f40f15..b21fded 100644 --- a/java/src/com/android/i18n/addressinput/JsonpRequestBuilder.java +++ b/java/src/com/android/i18n/addressinput/JsonpRequestBuilder.java @@ -33,98 +33,98 @@ import java.net.URLEncoder; */ class JsonpRequestBuilder { - /** - * Re-implementation of the com.google.gwt.user.client.rpc.AsyncCallback interface. - */ - interface AsyncCallback { - - public void onFailure(Throwable caught); - - public void onSuccess(T result); - } - - /** - * @param timeout The expected timeout (ms) for this request. - */ - void setTimeout(int timeout) { - HttpParams params = AsyncHttp.CLIENT.getParams(); - HttpConnectionParams.setConnectionTimeout(params, timeout); - HttpConnectionParams.setSoTimeout(params, timeout); + /** + * Re-implementation of the com.google.gwt.user.client.rpc.AsyncCallback interface. + */ + interface AsyncCallback { + + public void onFailure(Throwable caught); + + public void onSuccess(T result); + } + + /** + * @param timeout The expected timeout (ms) for this request. + */ + void setTimeout(int timeout) { + HttpParams params = AsyncHttp.CLIENT.getParams(); + HttpConnectionParams.setConnectionTimeout(params, timeout); + HttpConnectionParams.setSoTimeout(params, timeout); + } + + /** + * Sends a JSONP request and expects a JsoMap object as a result. + */ + void requestObject(String url, AsyncCallback callback) { + HttpUriRequest request = new HttpGet(encodeUrl(url)); + (new AsyncHttp(request, callback)).start(); + } + + /** + * Simple implementation of asynchronous HTTP GET. + */ + private static class AsyncHttp extends Thread { + + private static final HttpClient CLIENT = new DefaultHttpClient(); + + private HttpUriRequest request; + + private AsyncCallback callback; + + protected AsyncHttp(HttpUriRequest request, AsyncCallback callback) { + request = request; + callback = callback; } - /** - * Sends a JSONP request and expects a JsoMap object as a result. - */ - void requestObject(String url, AsyncCallback callback) { - HttpUriRequest request = new HttpGet(encodeUrl(url)); - (new AsyncHttp(request, callback)).start(); + @Override + public void run() { + try { + final String response; + synchronized (CLIENT) { + response = CLIENT.execute(request, new BasicResponseHandler()); + } + callback.onSuccess(JsoMap.buildJsoMap(response)); + } catch (Exception e) { + callback.onFailure(e); + } } - - /** - * Simple implementation of asynchronous HTTP GET. - */ - private static class AsyncHttp extends Thread { - - private static final HttpClient CLIENT = new DefaultHttpClient(); - - private HttpUriRequest mRequest; - - private AsyncCallback mCallback; - - protected AsyncHttp(HttpUriRequest request, AsyncCallback callback) { - mRequest = request; - mCallback = callback; + } + + /** + * A quick hack to transform a string into an RFC 3986 compliant URL. + * + * TODO: Refactor the code to stop passing URLs around as strings, to eliminate the need for + * this hack. + */ + private static String encodeUrl(String url) { + int length = url.length(); + StringBuilder tmp = new StringBuilder(length); + + try { + for (int i = 0; i < length; i++) { + int j = i; + char c = '\0'; + for (; j < length; j++) { + c = url.charAt(j); + if (c == ':' || c == '/') { + break; + } } - - @Override - public void run() { - try { - final String response; - synchronized (CLIENT) { - response = CLIENT.execute(mRequest, new BasicResponseHandler()); - } - mCallback.onSuccess(JsoMap.buildJsoMap(response)); - } catch (Exception e) { - mCallback.onFailure(e); - } + if (j == length) { + tmp.append(URLEncoder.encode(url.substring(i), "UTF-8")); + break; + } else if (j > i) { + tmp.append(URLEncoder.encode(url.substring(i, j), "UTF-8")); + tmp.append(c); + i = j; + } else { + tmp.append(c); } + } + } catch (UnsupportedEncodingException e) { + throw new RuntimeException(e); // Impossible. } - /** - * A quick hack to transform a string into an RFC 3986 compliant URL. - * - * TODO: Refactor the code to stop passing URLs around as strings, to eliminate the need for - * this hack. - */ - private static String encodeUrl(String url) { - int length = url.length(); - StringBuilder tmp = new StringBuilder(length); - - try { - for (int i = 0; i < length; i++) { - int j = i; - char c = '\0'; - for (; j < length; j++) { - c = url.charAt(j); - if (c == ':' || c == '/') { - break; - } - } - if (j == length) { - tmp.append(URLEncoder.encode(url.substring(i), "UTF-8")); - break; - } else if (j > i) { - tmp.append(URLEncoder.encode(url.substring(i, j), "UTF-8")); - tmp.append(c); - i = j; - } else { - tmp.append(c); - } - } - } catch (UnsupportedEncodingException e) { - throw new RuntimeException(e); // Impossible. - } - - return tmp.toString(); - } + return tmp.toString(); + } } 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: - * - *

7-2, Marunouchi 2-Chome, Chiyoda-ku, Tokyo 100-8799

- * - * 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 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: + * + *

7-2, Marunouchi 2-Chome, Chiyoda-ku, Tokyo 100-8799

+ * + * 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 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 nodes = new EnumMap( + AddressField.class); - private Map nodes = new EnumMap( - 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". - * - *

country: US
administrative area: null
locality: Mt. View

- */ - 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". + * + *

country: US
administrative area: null
locality: Mt. View

+ */ + 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); } + } } diff --git a/java/src/com/android/i18n/addressinput/NotifyingListener.java b/java/src/com/android/i18n/addressinput/NotifyingListener.java index 60a5f74..4e64d2d 100644 --- a/java/src/com/android/i18n/addressinput/NotifyingListener.java +++ b/java/src/com/android/i18n/addressinput/NotifyingListener.java @@ -20,34 +20,34 @@ package com.android.i18n.addressinput; * A helper class to let the calling thread wait until loading has finished. */ public class NotifyingListener implements DataLoadListener { - private Object mSleeper; - private boolean mDone; + private Object sleeper; + private boolean done; - NotifyingListener(Object sleeper) { - mSleeper = sleeper; - mDone = false; - } + NotifyingListener(Object sleeper) { + sleeper = sleeper; + done = false; + } - @Override - public void dataLoadingBegin() { - } + @Override + public void dataLoadingBegin() { + } - @Override - public void dataLoadingEnd() { - synchronized (this) { - mDone = true; - } - synchronized (mSleeper) { - mSleeper.notify(); - } + @Override + public void dataLoadingEnd() { + synchronized (this) { + done = true; } + synchronized (sleeper) { + sleeper.notify(); + } + } - void waitLoadingEnd() throws InterruptedException { - synchronized (this) { - if (mDone) return; - } - synchronized (mSleeper) { - mSleeper.wait(); - } + void waitLoadingEnd() throws InterruptedException { + synchronized (this) { + if (done) return; + } + synchronized (sleeper) { + sleeper.wait(); } + } } diff --git a/java/src/com/android/i18n/addressinput/RegionData.java b/java/src/com/android/i18n/addressinput/RegionData.java index 2b82c0a..62d3821 100644 --- a/java/src/com/android/i18n/addressinput/RegionData.java +++ b/java/src/com/android/i18n/addressinput/RegionData.java @@ -21,87 +21,87 @@ package com.android.i18n.addressinput; */ class RegionData { - private String mKey; - private String mName; + private String key; + private String name; - /** - * Create a new RegionData object. - */ - private RegionData() { - } + /** + * Create a new RegionData object. + */ + private RegionData() { + } - /** - * Copy constructor. data should not be null. - * - * @param data A populated instance of RegionData - */ - private RegionData(RegionData data) { - Util.checkNotNull(data); - mKey = data.mKey; - mName = data.mName; - } + /** + * Copy constructor. data should not be null. + * + * @param data A populated instance of RegionData + */ + private RegionData(RegionData data) { + Util.checkNotNull(data); + key = data.key; + name = data.name; + } - /** - * Gets the key of the region. For example, California's key is "CA". - */ - String getKey() { - return mKey; - } + /** + * Gets the key of the region. For example, California's key is "CA". + */ + String getKey() { + return key; + } - /** - * Gets the name. Returns null if not specified. - */ - String getName() { - return mName; + /** + * Gets the name. Returns null if not specified. + */ + String getName() { + return name; + } + + /** + * Gets the best display name. Returns the name if this is not null, otherwise the key. + */ + public String getDisplayName() { + return (name != null) ? name : key; + } + + /** + * Checks if the input subkey is the name (in Latin or local script) of the region. Returns + * false if subkey is not a valid name for the region, or the input subkey is null. + * + * @param subkey a string that refers to the name of a geo location. Like "California", "CA", or + * "Mountain View". Names in the local script are also supported. + */ + boolean isValidName(String subkey) { + if (subkey == null) { + return false; + } + if (subkey.equalsIgnoreCase(key) || subkey.equalsIgnoreCase(name)) { + return true; } + return false; + } - /** - * Gets the best display name. Returns the name if this is not null, otherwise the key. - */ - public String getDisplayName() { - return (mName != null) ? mName : mKey; + /** + * A builder class to facilitate the creation of RegionData objects. + */ + static class Builder { + RegionData data = new RegionData(); + + RegionData build() { + return new RegionData(data); } - /** - * Checks if the input subkey is the name (in Latin or local script) of the region. Returns - * false if subkey is not a valid name for the region, or the input subkey is null. - * - * @param subkey a string that refers to the name of a geo location. Like "California", "CA", or - * "Mountain View". Names in the local script are also supported. - */ - boolean isValidName(String subkey) { - if (subkey == null) { - return false; - } - if (subkey.equalsIgnoreCase(mKey) || subkey.equalsIgnoreCase(mName)) { - return true; - } - return false; + Builder setKey(String key) { + Util.checkNotNull(key, "Key should not be null."); + data.key = key; + return this; } /** - * A builder class to facilitate the creation of RegionData objects. + * Sets name of the region. For example, "California". If the name is an empty string, sets + * it to null. */ - static class Builder { - RegionData mData = new RegionData(); - - RegionData build() { - return new RegionData(mData); - } - - Builder setKey(String key) { - Util.checkNotNull(key, "Key should not be null."); - mData.mKey = key; - return this; - } - - /** - * Sets name of the region. For example, "California". If the name is an empty string, sets - * it to null. - */ - Builder setName(String name) { - mData.mName = Util.trimToNull(name); - return this; - } + Builder setName(String name) { + data.name = Util.trimToNull(name); + return this; } + } } diff --git a/java/src/com/android/i18n/addressinput/RegionDataConstants.java b/java/src/com/android/i18n/addressinput/RegionDataConstants.java index 0b486dd..bd453a8 100644 --- a/java/src/com/android/i18n/addressinput/RegionDataConstants.java +++ b/java/src/com/android/i18n/addressinput/RegionDataConstants.java @@ -29,1287 +29,1287 @@ import java.util.Map; */ class RegionDataConstants { - private static final Map COUNTRY_FORMAT_MAP = - new HashMap(); + private static final Map COUNTRY_FORMAT_MAP = + new HashMap(); - private enum RegionDataEnum { + private enum RegionDataEnum { - AC(new String[]{ - "name", "ASCENSION ISLAND", - }), - AD(new String[]{ - "name", "ANDORRA", - "lang", "ca", - "languages", "ca", - "fmt", "%N%n%O%n%A%n%Z %C", - "require", "A", - }), - AE(new String[]{ - "name", "UNITED ARAB EMIRATES", - "fmt", "%N%n%O%n%A%n%C", - "require", "AC", - }), - AF(new String[]{ - "name", "AFGHANISTAN", - }), - AG(new String[]{ - "name", "ANTIGUA AND BARBUDA", - "require", "A", - }), - AI(new String[]{ - "name", "ANGUILLA", - }), - AL(new String[]{ - "name", "ALBANIA", - }), - AM(new String[]{ - "name", "ARMENIA", - "lang", "hy", - "languages", "hy", - "fmt", "%N%n%O%n%A%n%Z%n%C%n%S", - "lfmt", "%N%n%O%n%A%n%Z%n%C%n%S", - }), - AO(new String[]{ - "name", "ANGOLA", - }), - AQ(new String[]{ - "name", "ANTARCTICA", - }), - AR(new String[]{ - "name", "ARGENTINA", - "lang", "es", - "languages", "es", - "fmt", "%N%n%O%n%A%n%Z %C%n%S", - "upper", "ACZ", - "state_name_type", "state", - }), - AS(new String[]{ - "name", "AMERICAN SAMOA", - "fmt", "%N%n%O%n%A%n%C %S %Z", - "require", "ACSZ", - "upper", "ACNOS", - "zip_name_type", "zip", - "state_name_type", "state", - }), - AT(new String[]{ - "name", "AUSTRIA", - "fmt", "%O%n%N%n%A%n%Z %C", - "require", "ACZ", - }), - AU(new String[]{ - "name", "AUSTRALIA", - "lang", "en", - "languages", "en", - "fmt", "%O%n%N%n%A%n%C %S %Z", - "require", "ACSZ", - "upper", "CS", - "state_name_type", "state", - }), - AW(new String[]{ - "name", "ARUBA", - }), - AX(new String[]{ - "name", "FINLAND", - "fmt", "%O%n%N%n%A%nAX-%Z %C%n\u00C5LAND", - "require", "ACZ", - "postprefix", "AX-", - }), - AZ(new String[]{ - "name", "AZERBAIJAN", - "fmt", "%N%n%O%n%A%nAZ %Z %C", - "postprefix", "AZ ", - }), - BA(new String[]{ - "name", "BOSNIA AND HERZEGOVINA", - "fmt", "%N%n%O%n%A%n%Z %C", - }), - BB(new String[]{ - "name", "BARBADOS", - "state_name_type", "parish", - }), - BD(new String[]{ - "name", "BANGLADESH", - "fmt", "%N%n%O%n%A%n%C - %Z", - }), - BE(new String[]{ - "name", "BELGIUM", - "fmt", "%O%n%N%n%A%n%Z %C", - "require", "ACZ", - }), - BF(new String[]{ - "name", "BURKINA FASO", - "fmt", "%N%n%O%n%A%n%C %X", - }), - BG(new String[]{ - "name", "BULGARIA (REP.)", - "fmt", "%N%n%O%n%A%n%Z %C", - }), - BH(new String[]{ - "name", "BAHRAIN", - "fmt", "%N%n%O%n%A%n%C %Z", - }), - BI(new String[]{ - "name", "BURUNDI", - }), - BJ(new String[]{ - "name", "BENIN", - "upper", "AC", - }), - BL(new String[]{ - "name", "SAINT BARTHELEMY", - "fmt", "%O%n%N%n%A%n%Z %C %X", - "upper", "ACX", - "require", "ACZ", - }), - BM(new String[]{ - "name", "BERMUDA", - "fmt", "%N%n%O%n%A%n%C %Z", - }), - BN(new String[]{ - "name", "BRUNEI DARUSSALAM", - "fmt", "%N%n%O%n%A%n%C %Z", - }), - BO(new String[]{ - "name", "BOLIVIA", - "upper", "AC", - }), - BR(new String[]{ - "name", "BRAZIL", - "lang", "pt", - "languages", "pt", - "fmt", "%O%n%N%n%A%n%D%n%C-%S%n%Z", - "require", "ASCZ", - "upper", "CS", - "state_name_type", "state", - "sublocality_name_type", "neighborhood", - }), - BS(new String[]{ - "name", "BAHAMAS", - "lang", "en", - "languages", "en", - "fmt", "%N%n%O%n%A%n%C, %S", - "state_name_type", "island", - }), - BT(new String[]{ - "name", "BHUTAN", - }), - BV(new String[]{ - "name", "BOUVET ISLAND", - }), - BW(new String[]{ - "name", "BOTSWANA", - }), - BY(new String[]{ - "name", "BELARUS", - "fmt", "%S%n%Z %C %X%n%A%n%O%n%N", - }), - BZ(new String[]{ - "name", "BELIZE", - }), - CA(new String[]{ - "name", "CANADA", - "lang", "en", - "languages", "en~fr", - "fmt", "%N%n%O%n%A%n%C %S %Z", - "require", "ACSZ", - "upper", "ACNOSZ", - }), - CC(new String[]{ - "name", "COCOS (KEELING) ISLANDS", - "fmt", "%O%n%N%n%A%n%C %S %Z", - "upper", "CS", - }), - CD(new String[]{ - "name", "CONGO (DEM. REP.)", - "fmt", "%N%n%O%n%A%n%C %X", - }), - CF(new String[]{ - "name", "CENTRAL AFRICAN REPUBLIC", - }), - CG(new String[]{ - "name", "CONGO (REP.)", - }), - CH(new String[]{ - "name", "SWITZERLAND", - "lang", "de", - "languages", "de~fr~it", - "fmt", "%O%n%N%n%A%nCH-%Z %C", - "require", "ACZ", - "upper", "", - "postprefix", "CH-", - }), - CI(new String[]{ - "name", "COTE D'IVOIRE", - "fmt", "%N%n%O%n%X %A %C %X", - }), - CK(new String[]{ - "name", "COOK ISLANDS", - }), - CL(new String[]{ - "name", "CHILE", - "lang", "es", - "languages", "es", - "fmt", "%N%n%O%n%A%n%Z %C%n%S", - "state_name_type", "state", - }), - CM(new String[]{ - "name", "CAMEROON", - }), - CN(new String[]{ - "name", "P.R. CHINA", - "lang", "zh-Hans", - "languages", "zh-Hans", - "fmt", "%Z%n%S%C%D%n%A%n%O%n%N", - "lfmt", "%N%n%O%n%A%n%D%n%C%n%S, %Z", - "require", "ACSZ", - "upper", "S", - "sublocality_name_type", "district", - }), - CO(new String[]{ - "name", "COLOMBIA", - "fmt", "%N%n%O%n%A%n%C, %S", - }), - CR(new String[]{ - "name", "COSTA RICA", - "fmt", "%N%n%O%n%A%n%Z %C", - }), - CV(new String[]{ - "name", "CAPE VERDE", - "lang", "pt", - "languages", "pt", - "fmt", "%N%n%O%n%A%n%Z %C%n%S", - "state_name_type", "island", - }), - CX(new String[]{ - "name", "CHRISTMAS ISLAND", - "fmt", "%O%n%N%n%A%n%C %S %Z", - "upper", "CS", - }), - CY(new String[]{ - "name", "CYPRUS", - "fmt", "%N%n%O%n%A%n%Z %C", - }), - CZ(new String[]{ - "name", "CZECH REP.", - "fmt", "%N%n%O%n%A%n%Z %C", - }), - DE(new String[]{ - "name", "GERMANY", - "fmt", "%N%n%O%n%A%n%Z %C", - "require", "ACZ", - }), - DJ(new String[]{ - "name", "DJIBOUTI", - }), - DK(new String[]{ - "name", "DENMARK", - "fmt", "%N%n%O%n%A%n%Z %C", - "require", "ACZ", - }), - DM(new String[]{ - "name", "DOMINICA", - }), - DO(new String[]{ - "name", "DOMINICAN REP.", - "fmt", "%N%n%O%n%A%n%Z %C", - }), - DZ(new String[]{ - "name", "ALGERIA", - "fmt", "%N%n%O%n%A%n%Z %C", - }), - EC(new String[]{ - "name", "ECUADOR", - "fmt", "%N%n%O%n%A%n%Z%n%C", - "upper", "CZ", - }), - EE(new String[]{ - "name", "ESTONIA", - "fmt", "%N%n%O%n%A%n%Z %C", - }), - EG(new String[]{ - "name", "EGYPT", - "lang", "ar", - "languages", "ar", - "fmt", "%N%n%O%n%A%n%C%n%S%n%Z", - "lfmt", "%N%n%O%n%A%n%C%n%S%n%Z", - }), - EH(new String[]{ - "name", "WESTERN SAHARA", - "fmt", "%N%n%O%n%A%n%Z %C", - }), - ER(new String[]{ - "name", "ERITREA", - }), - ES(new String[]{ - "name", "SPAIN", - "lang", "es", - "languages", "es", - "fmt", "%N%n%O%n%A%n%Z %C %S", - "require", "ACSZ", - "upper", "CS", - }), - ET(new String[]{ - "name", "ETHIOPIA", - "fmt", "%N%n%O%n%A%n%Z %C", - }), - FI(new String[]{ - "name", "FINLAND", - "fmt", "%O%n%N%n%A%nFI-%Z %C", - "require", "ACZ", - "postprefix", "FI-", - }), - FJ(new String[]{ - "name", "FIJI", - }), - FK(new String[]{ - "name", "FALKLAND ISLANDS (MALVINAS)", - "fmt", "%N%n%O%n%A%n%X%n%C%n%Z", - "require", "ACZ", - "upper", "CZ", - }), - FM(new String[]{ - "name", "MICRONESIA (Federated State of)", - "fmt", "%N%n%O%n%A%n%C %S %Z", - "require", "ACSZ", - "upper", "ACNOS", - "zip_name_type", "zip", - "state_name_type", "state", - }), - FO(new String[]{ - "name", "FAROE ISLANDS", - "fmt", "%N%n%O%n%A%nFO%Z %C", - "postprefix", "FO", - }), - FR(new String[]{ - "name", "FRANCE", - "fmt", "%O%n%N%n%A%n%Z %C %X", - "require", "ACZ", - "upper", "CX", - }), - GA(new String[]{ - "name", "GABON", - }), - GB(new String[]{ - "name", "UNITED KINGDOM", - "fmt", "%N%n%O%n%A%n%C%n%S%n%Z", - "require", "ACZ", - "upper", "CZ", - "state_name_type", "county", - "locality_name_type", "post_town", - }), - GD(new String[]{ - "name", "GRENADA (WEST INDIES)", - }), - GE(new String[]{ - "name", "GEORGIA", - "fmt", "%N%n%O%n%A%n%Z %C", - }), - GF(new String[]{ - "name", "FRENCH GUIANA", - "fmt", "%O%n%N%n%A%n%Z %C %X", - "require", "ACZ", - "upper", "ACX", - }), - GG(new String[]{ - "name", "CHANNEL ISLANDS", - "fmt", "%N%n%O%n%A%n%X%n%C%nGUERNSEY%n%Z", - "require", "ACZ", - "upper", "CZ", - }), - GH(new String[]{ - "name", "GHANA", - }), - GI(new String[]{ - "name", "GIBRALTAR", - "fmt", "%N%n%O%n%A%nGIBRALTAR%n%Z", - "require", "A", - }), - GL(new String[]{ - "name", "GREENLAND", - "fmt", "%N%n%O%n%A%n%Z %C", - "require", "ACZ", - }), - GM(new String[]{ - "name", "GAMBIA", - }), - GN(new String[]{ - "name", "GUINEA", - "fmt", "%N%n%O%n%Z %A %C", - }), - GP(new String[]{ - "name", "GUADELOUPE", - "fmt", "%O%n%N%n%A%n%Z %C %X", - "require", "ACZ", - "upper", "ACX", - }), - GQ(new String[]{ - "name", "EQUATORIAL GUINEA", - }), - GR(new String[]{ - "name", "GREECE", - "fmt", "%N%n%O%n%A%n%Z %C", - "require", "ACZ", - }), - GS(new String[]{ - "name", "SOUTH GEORGIA", - "fmt", "%N%n%O%n%A%n%X%n%C%n%Z", - "require", "ACZ", - "upper", "CZ", - }), - GT(new String[]{ - "name", "GUATEMALA", - "fmt", "%N%n%O%n%A%n%Z- %C", - }), - GU(new String[]{ - "name", "GUAM", - "fmt", "%N%n%O%n%A%n%C %S %Z", - "require", "ACSZ", - "upper", "ACNOS", - "zip_name_type", "zip", - "state_name_type", "state", - }), - GW(new String[]{ - "name", "GUINEA-BISSAU", - "fmt", "%N%n%O%n%A%n%Z %C", - }), - GY(new String[]{ - "name", "GUYANA", - }), - HK(new String[]{ - "name", "HONG KONG", - "lang", "zh-Hant", - "languages", "zh-Hant~en", - "fmt", "%S%n%C%n%A%n%O%n%N", - "lfmt", "%N%n%O%n%A%n%C%n%S", - "require", "AS", - "upper", "S", - "state_name_type", "area", - "locality_name_type", "district", - }), - HM(new String[]{ - "name", "HEARD AND MCDONALD ISLANDS", - "fmt", "%O%n%N%n%A%n%C %S %Z", - "upper", "CS", - }), - HN(new String[]{ - "name", "HONDURAS", - "fmt", "%N%n%O%n%A%n%C, %S%n%Z", - "require", "ACS", - }), - HR(new String[]{ - "name", "CROATIA", - "fmt", "%N%n%O%n%A%nHR-%Z %C", - "postprefix", "HR-", - }), - HT(new String[]{ - "name", "HAITI", - "fmt", "%N%n%O%n%A%nHT%Z %C %X", - "postprefix", "HT", - }), - HU(new String[]{ - "name", "HUNGARY (Rep.)", - "fmt", "%N%n%O%n%C%n%A%n%Z", - "upper", "ACNO", - }), - ID(new String[]{ - "name", "INDONESIA", - "lang", "id", - "languages", "id", - "fmt", "%N%n%O%n%A%n%C%n%S %Z", - }), - IE(new String[]{ - "name", "IRELAND", - "lang", "en", - "languages", "en", - "fmt", "%N%n%O%n%A%n%C%n%S", - "state_name_type", "county", - }), - IL(new String[]{ - "name", "ISRAEL", - "fmt", "%N%n%O%n%A%n%C %Z", - }), - IM(new String[]{ - "name", "ISLE OF MAN", - "fmt", "%N%n%O%n%A%n%X%n%C%n%Z", - "require", "ACZ", - "upper", "CZ", - }), - IN(new String[]{ - "name", "INDIA", - "lang", "en", - "languages", "en", - "fmt", "%N%n%O%n%A%n%C %Z%n%S", - "require", "ACSZ", - "state_name_type", "state", - }), - IO(new String[]{ - "name", "BRITISH INDIAN OCEAN TERRITORY", - "fmt", "%N%n%O%n%A%n%X%n%C%n%Z", - "require", "ACZ", - "upper", "CZ", - }), - IQ(new String[]{ - "name", "IRAQ", - "fmt", "%O%n%N%n%A%n%C, %S%n%Z", - "require", "ACS", - "upper", "CS", - }), - IS(new String[]{ - "name", "ICELAND", - "fmt", "%N%n%O%n%A%n%Z %C", - }), - IT(new String[]{ - "name", "ITALY", - "lang", "it", - "languages", "it", - "fmt", "%N%n%O%n%A%n%Z %C %S", - "require", "ACSZ", - "upper", "CS", - }), - JE(new String[]{ - "name", "CHANNEL ISLANDS", - "fmt", "%N%n%O%n%A%n%X%n%C%nJERSEY%n%Z", - "require", "ACZ", - "upper", "CZ", - }), - JM(new String[]{ - "name", "JAMAICA", - "lang", "en", - "languages", "en", - "fmt", "%N%n%O%n%A%n%C%n%S %X", - "require", "ACS", - "state_name_type", "parish", - }), - JO(new String[]{ - "name", "JORDAN", - "fmt", "%N%n%O%n%A%n%C %Z", - }), - JP(new String[]{ - "name", "JAPAN", - "lang", "ja", - "languages", "ja", - "fmt", "\u3012%Z%n%S%C%n%A%n%O%n%N", - "lfmt", "%N%n%O%n%A%n%C, %S%n%Z", - "require", "ACSZ", - "upper", "S", - "state_name_type", "prefecture", - }), - KE(new String[]{ - "name", "KENYA", - "fmt", "%N%n%O%n%A%n%C%n%Z", - }), - KG(new String[]{ - "name", "KYRGYZSTAN", - "fmt", "%Z %C %X%n%A%n%O%n%N", - }), - KH(new String[]{ - "name", "CAMBODIA", - "fmt", "%N%n%O%n%A%n%C %Z", - }), - KI(new String[]{ - "name", "KIRIBATI", - "fmt", "%N%n%O%n%A%n%S%n%C", - "upper", "ACNOS", - "state_name_type", "island", - }), - KM(new String[]{ - "name", "COMOROS", - "upper", "AC", - }), - KN(new String[]{ - "name", "SAINT KITTS AND NEVIS", - "lang", "en", - "languages", "en", - "fmt", "%N%n%O%n%A%n%C, %S", - "require", "ACS", - "state_name_type", "island", - }), - KR(new String[]{ - "name", "KOREA (REP.)", - "lang", "ko", - "languages", "ko", - "fmt", "%S %C%D%n%A%n%O%n%N%n%Z", - "lfmt", "%N%n%O%n%A%n%D%n%C%n%S%n%Z", - "require", "ACSZ", - "upper", "Z", - "state_name_type", "do_si", - "sublocality_name_type", "district", - }), - KW(new String[]{ - "name", "KUWAIT", - "fmt", "%N%n%O%n%A%n%Z %C", - }), - KY(new String[]{ - "name", "CAYMAN ISLANDS", - "lang", "en", - "languages", "en", - "fmt", "%N%n%O%n%A%n%S %Z", - "require", "AS", - "state_name_type", "island", - }), - KZ(new String[]{ - "name", "KAZAKHSTAN", - "fmt", "%Z%n%S%n%C%n%A%n%O%n%N", - }), - LA(new String[]{ - "name", "LAO (PEOPLE'S DEM. REP.)", - "fmt", "%N%n%O%n%A%n%Z %C", - }), - LB(new String[]{ - "name", "LEBANON", - "fmt", "%N%n%O%n%A%n%C %Z", - }), - LC(new String[]{ - "name", "SAINT LUCIA", - }), - LI(new String[]{ - "name", "LIECHTENSTEIN", - "fmt", "%O%n%N%n%A%nFL-%Z %C", - "require", "ACZ", - "postprefix", "FL-", - }), - LK(new String[]{ - "name", "SRI LANKA", - "fmt", "%N%n%O%n%A%n%C%n%Z", - }), - LR(new String[]{ - "name", "LIBERIA", - "fmt", "%N%n%O%n%A%n%Z %C %X", - }), - LS(new String[]{ - "name", "LESOTHO", - "fmt", "%N%n%O%n%A%n%C %Z", - }), - LT(new String[]{ - "name", "LITHUANIA", - "fmt", "%O%n%N%n%A%nLT-%Z %C", - "postprefix", "LT-", - }), - LU(new String[]{ - "name", "LUXEMBOURG", - "fmt", "%O%n%N%n%A%nL-%Z %C", - "require", "ACZ", - "postprefix", "L-", - }), - LV(new String[]{ - "name", "LATVIA", - "fmt", "%N%n%O%n%A%n%C, %Z", - }), - LY(new String[]{ - "name", "LIBYA", - }), - MA(new String[]{ - "name", "MOROCCO", - "fmt", "%N%n%O%n%A%n%Z %C", - }), - MC(new String[]{ - "name", "MONACO", - "fmt", "%N%n%O%n%A%nMC-%Z %C %X", - "postprefix", "MC-", - }), - MD(new String[]{ - "name", "Rep. MOLDOVA", - "fmt", "%N%n%O%n%A%nMD-%Z %C", - "postprefix", "MD-", - }), - ME(new String[]{ - "name", "MONTENEGRO", - "fmt", "%N%n%O%n%A%n%Z %C", - }), - MF(new String[]{ - "name", "SAINT MARTIN", - "fmt", "%O%n%N%n%A%n%Z %C %X", - "upper", "ACX", - "require", "ACZ", - }), - MG(new String[]{ - "name", "MADAGASCAR", - "fmt", "%N%n%O%n%A%n%Z %C", - }), - MH(new String[]{ - "name", "MARSHALL ISLANDS", - "fmt", "%N%n%O%n%A%n%C %S %Z", - "require", "ACSZ", - "upper", "ACNOS", - "zip_name_type", "zip", - "state_name_type", "state", - }), - MK(new String[]{ - "name", "MACEDONIA", - "fmt", "%N%n%O%n%A%n%Z %C", - }), - ML(new String[]{ - "name", "MALI", - }), - MN(new String[]{ - "name", "MONGOLIA", - "fmt", "%N%n%O%n%A%n%S %C-%X%n%Z", - }), - MO(new String[]{ - "name", "MACAO", - "lang", "zh-Hant", - "languages", "zh-Hant", - "fmt", "%A%n%O%n%N", - "lfmt", "%N%n%O%n%A", - "require", "A", - }), - MP(new String[]{ - "name", "NORTHERN MARIANA ISLANDS", - "fmt", "%N%n%O%n%A%n%C %S %Z", - "require", "ACSZ", - "upper", "ACNOS", - "zip_name_type", "zip", - "state_name_type", "state", - }), - MQ(new String[]{ - "name", "MARTINIQUE", - "fmt", "%O%n%N%n%A%n%Z %C %X", - "require", "ACZ", - "upper", "ACX", - }), - MR(new String[]{ - "name", "MAURITANIA", - "upper", "AC", - }), - MS(new String[]{ - "name", "MONTSERRAT", - }), - MT(new String[]{ - "name", "MALTA", - "fmt", "%N%n%O%n%A%n%C %Z", - "upper", "CZ", - }), - MU(new String[]{ - "name", "MAURITIUS", - "fmt", "%N%n%O%n%A%n%Z%n%C", - "upper", "CZ", - }), - MV(new String[]{ - "name", "MALDIVES", - "fmt", "%N%n%O%n%A%n%C %Z", - }), - MW(new String[]{ - "name", "MALAWI", - "fmt", "%N%n%O%n%A%n%C %X", - }), - MX(new String[]{ - "name", "MEXICO", - "lang", "es", - "languages", "es", - "fmt", "%N%n%O%n%A%n%D%n%Z %C, %S", - "require", "ACZ", - "upper", "CSZ", - "state_name_type", "state", - "sublocality_name_type", "neighborhood", - }), - MY(new String[]{ - "name", "MALAYSIA", - "lang", "ms", - "languages", "ms", - "fmt", "%N%n%O%n%A%n%D%n%Z %C%n%S", - "require", "ACZ", - "upper", "CS", - "state_name_type", "state", - "sublocality_name_type", "village_township", - }), - MZ(new String[]{ - "name", "MOZAMBIQUE", - }), - NA(new String[]{ - "name", "NAMIBIA", - }), - NC(new String[]{ - "name", "NEW CALEDONIA", - "fmt", "%O%n%N%n%A%n%Z %C %X", - "require", "ACZ", - "upper", "ACX", - }), - NE(new String[]{ - "name", "NIGER", - "fmt", "%N%n%O%n%A%n%Z %C", - }), - NF(new String[]{ - "name", "NORFOLK ISLAND", - "fmt", "%O%n%N%n%A%n%C %S %Z", - "upper", "CS", - }), - NG(new String[]{ - "name", "NIGERIA", - "lang", "en", - "languages", "en", - "fmt", "%N%n%O%n%A%n%C %Z%n%S", - "upper", "CS", - "state_name_type", "state", - }), - NI(new String[]{ - "name", "NICARAGUA", - "lang", "es", - "languages", "es", - "fmt", "%N%n%O%n%A%n%Z%n%C, %S", - "upper", "CS", - "state_name_type", "department", - }), - NL(new String[]{ - "name", "NETHERLANDS", - "fmt", "%O%n%N%n%A%n%Z %C", - "require", "ACZ", - }), - NO(new String[]{ - "name", "NORWAY", - "fmt", "%N%n%O%n%A%n%Z %C", - "require", "ACZ", - }), - NP(new String[]{ - "name", "NEPAL", - "fmt", "%N%n%O%n%A%n%C %Z", - }), - NR(new String[]{ - "name", "NAURU CENTRAL PACIFIC", - "lang", "en", - "languages", "en", - "fmt", "%N%n%O%n%A%n%S", - "require", "AS", - "state_name_type", "district", - }), - NU(new String[]{ - "name", "NIUE", - }), - NZ(new String[]{ - "name", "NEW ZEALAND", - "fmt", "%N%n%O%n%A%n%D%n%C %Z", - "require", "ACZ", - }), - OM(new String[]{ - "name", "OMAN", - "fmt", "%N%n%O%n%A%n%Z%n%C", - }), - PA(new String[]{ - "name", "PANAMA (REP.)", - "fmt", "%N%n%O%n%A%n%C%n%S", - "upper", "CS", - }), - PE(new String[]{ - "name", "PERU", - }), - PF(new String[]{ - "name", "FRENCH POLYNESIA", - "fmt", "%N%n%O%n%A%n%Z %C %S", - "require", "ACSZ", - "upper", "CS", - "state_name_type", "island", - }), - PG(new String[]{ - "name", "PAPUA NEW GUINEA", - "fmt", "%N%n%O%n%A%n%C %Z %S", - "require", "ACS", - }), - PH(new String[]{ - "name", "PHILIPPINES", - "lang", "en", - "languages", "en", - "fmt", "%N%n%O%n%A%n%D, %C%n%Z %S", - "require", "AC", - }), - PK(new String[]{ - "name", "PAKISTAN", - "fmt", "%N%n%O%n%A%n%C-%Z", - }), - PL(new String[]{ - "name", "POLAND", - "fmt", "%N%n%O%n%A%n%Z %C", - "require", "ACZ", - }), - PM(new String[]{ - "name", "ST. PIERRE AND MIQUELON", - "fmt", "%O%n%N%n%A%n%Z %C %X", - "require", "ACZ", - "upper", "ACX", - }), - PN(new String[]{ - "name", "PITCAIRN", - "fmt", "%N%n%O%n%A%n%X%n%C%n%Z", - "require", "ACZ", - "upper", "CZ", - }), - PR(new String[]{ - "name", "PUERTO RICO", - "fmt", "%N%n%O%n%A%n%C PR %Z", - "require", "ACZ", - "upper", "ACNO", - "zip_name_type", "zip", - "postprefix", "PR", - }), - PS(new String[]{ - "name", "PALESTINIAN TERRITORY", - }), - PT(new String[]{ - "name", "PORTUGAL", - "fmt", "%N%n%O%n%A%n%Z %C", - "require", "ACZ", - }), - PW(new String[]{ - "name", "PALAU", - "fmt", "%N%n%O%n%A%n%C %S %Z", - "require", "ACSZ", - "upper", "ACNOS", - "zip_name_type", "zip", - "state_name_type", "state", - }), - PY(new String[]{ - "name", "PARAGUAY", - "fmt", "%N%n%O%n%A%n%Z %C", - }), - QA(new String[]{ - "name", "QATAR", - "upper", "AC", - }), - RE(new String[]{ - "name", "REUNION", - "fmt", "%O%n%N%n%A%n%Z %C %X", - "require", "ACZ", - "upper", "ACX", - }), - RO(new String[]{ - "name", "ROMANIA", - "fmt", "%N%n%O%n%A%n%Z %C", - "upper", "AC", - }), - RS(new String[]{ - "name", "REPUBLIC OF SERBIA", - "fmt", "%N%n%O%n%A%n%Z %C", - }), - RU(new String[]{ - "name", "RUSSIAN FEDERATION", - "fmt", "%N%n%O%n%A%n%C%n%S%n%Z", - "require", "ACZ", - "upper", "AC", - "state_name_type", "oblast", - }), - RW(new String[]{ - "name", "RWANDA", - "upper", "AC", - }), - SA(new String[]{ - "name", "SAUDI ARABIA", - "fmt", "%N%n%O%n%A%n%C %Z", - }), - SB(new String[]{ - "name", "SOLOMON ISLANDS", - }), - SC(new String[]{ - "name", "SEYCHELLES", - "fmt", "%N%n%O%n%A%n%C%n%S", - "upper", "S", - "state_name_type", "island", - }), - SE(new String[]{ - "name", "SWEDEN", - "fmt", "%O%n%N%n%A%nSE-%Z %C", - "require", "ACZ", - "postprefix", "SE-", - }), - SG(new String[]{ - "name", "REP. OF SINGAPORE", - "fmt", "%N%n%O%n%A%nSINGAPORE %Z", - "require", "AZ", - }), - SH(new String[]{ - "name", "SAINT HELENA", - "fmt", "%N%n%O%n%A%n%X%n%C%n%Z", - "require", "ACZ", - "upper", "CZ", - }), - SI(new String[]{ - "name", "SLOVENIA", - "fmt", "%N%n%O%n%A%nSI- %Z %C", - "postprefix", "SI-", - }), - SJ(new String[]{ - "name", "SVALBARD AND JAN MAYEN ISLANDS", - "fmt", "%N%n%O%n%A%n%Z %C", - "require", "ACZ", - }), - SK(new String[]{ - "name", "SLOVAKIA", - "fmt", "%N%n%O%n%A%n%Z %C", - }), - SL(new String[]{ - "name", "SIERRA LEONE", - }), - SM(new String[]{ - "name", "SAN MARINO", - "fmt", "%N%n%O%n%A%n%Z %C", - "require", "AZ", - }), - SN(new String[]{ - "name", "SENEGAL", - "fmt", "%N%n%O%n%A%n%Z %C", - }), - SO(new String[]{ - "name", "SOMALIA", - "lang", "so", - "languages", "so", - "fmt", "%N%n%O%n%A%n%C, %S %Z", - "require", "ACS", - "upper", "ACS", - }), - SR(new String[]{ - "name", "SURINAME", - "lang", "nl", - "languages", "nl", - "fmt", "%N%n%O%n%A%n%C %X%n%S", - "upper", "AS", - }), - ST(new String[]{ - "name", "SAO TOME AND PRINCIPE", - "fmt", "%N%n%O%n%A%n%C %X", - }), - SV(new String[]{ - "name", "EL SALVADOR", - "lang", "es", - "languages", "es", - "fmt", "%N%n%O%n%A%n%Z-%C%n%S", - "require", "ACS", - "upper", "CSZ", - }), - SZ(new String[]{ - "name", "SWAZILAND", - "fmt", "%N%n%O%n%A%n%C%n%Z", - "upper", "ACZ", - }), - TA(new String[]{ - "name", "TRISTAN DA CUNHA", - }), - TC(new String[]{ - "name", "TURKS AND CAICOS ISLANDS", - "fmt", "%N%n%O%n%A%n%X%n%C%n%Z", - "require", "ACZ", - "upper", "CZ", - }), - TD(new String[]{ - "name", "CHAD", - }), - TF(new String[]{ - "name", "FRENCH SOUTHERN TERRITORIES", - }), - TG(new String[]{ - "name", "TOGO", - }), - TH(new String[]{ - "name", "THAILAND", - "lang", "th", - "languages", "th", - "fmt", "%N%n%O%n%A%n%D %C%n%S %Z", - "lfmt", "%N%n%O%n%A%n%D, %C%n%S %Z", - "upper", "S", - }), - TJ(new String[]{ - "name", "TAJIKISTAN", - "fmt", "%N%n%O%n%A%n%Z %C", - }), - TK(new String[]{ - "name", "TOKELAU", - }), - TL(new String[]{ - "name", "TIMOR-LESTE", - }), - TM(new String[]{ - "name", "TURKMENISTAN", - "fmt", "%N%n%O%n%A%n%Z %C", - }), - TN(new String[]{ - "name", "TUNISIA", - "fmt", "%N%n%O%n%A%n%Z %C", - }), - TO(new String[]{ - "name", "TONGA", - }), - TR(new String[]{ - "name", "TURKEY", - "lang", "tr", - "languages", "tr", - "fmt", "%N%n%O%n%A%n%Z %C/%S", - "require", "ACZ", - "locality_name_type", "district", - }), - TT(new String[]{ - "name", "TRINIDAD AND TOBAGO", - }), - TV(new String[]{ - "name", "TUVALU", - "lang", "tyv", - "languages", "tyv", - "fmt", "%N%n%O%n%A%n%X%n%C%n%S", - "upper", "ACS", - "state_name_type", "island", - }), - TW(new String[]{ - "name", "TAIWAN", - "lang", "zh-Hant", - "languages", "zh-Hant", - "fmt", "%Z%n%S%C%n%A%n%O%n%N", - "lfmt", "%N%n%O%n%A%n%C, %S %Z", - "require", "ACSZ", - "state_name_type", "county", - }), - TZ(new String[]{ - "name", "TANZANIA (UNITED REP.)", - }), - UA(new String[]{ - "name", "UKRAINE", - "fmt", "%N%n%O%n%A%n%C%n%S%n%Z", - "require", "ACZ", - "state_name_type", "oblast", - }), - UG(new String[]{ - "name", "UGANDA", - }), - UM(new String[]{ - "name", "UNITED STATES MINOR OUTLYING ISLANDS", - "fmt", "%N%n%O%n%A%n%C %S %Z", - "require", "ACS", - "upper", "ACNOS", - "zip_name_type", "zip", - "state_name_type", "state", - }), - US(new String[]{ - "name", "UNITED STATES", - "lang", "en", - "languages", "en", - "fmt", "%N%n%O%n%A%n%C, %S %Z", - "require", "ACSZ", - "upper", "CS", - "zip_name_type", "zip", - "state_name_type", "state", - }), - UY(new String[]{ - "name", "URUGUAY", - "lang", "es", - "languages", "es", - "fmt", "%N%n%O%n%A%n%Z %C %S", - "upper", "CS", - }), - UZ(new String[]{ - "name", "UZBEKISTAN", - "fmt", "%N%n%O%n%A%n%Z %C%n%S", - "upper", "CS", - }), - VA(new String[]{ - "name", "VATICAN", - "fmt", "%N%n%O%n%A%n%Z %C", - }), - VC(new String[]{ - "name", "SAINT VINCENT AND THE GRENADINES (ANTILLES)", - }), - VE(new String[]{ - "name", "VENEZUELA", - "lang", "es", - "languages", "es", - "fmt", "%N%n%O%n%A%n%C %Z, %S", - "require", "ACS", - "upper", "CS", - }), - VG(new String[]{ - "name", "VIRGIN ISLANDS (BRITISH)", - "fmt", "%N%n%O%n%A%n%C%n%Z", - "require", "A", - }), - VI(new String[]{ - "name", "VIRGIN ISLANDS (U.S.)", - "fmt", "%N%n%O%n%A%n%C %S %Z", - "require", "ACSZ", - "upper", "ACNOS", - "zip_name_type", "zip", - "state_name_type", "state", - }), - VN(new String[]{ - "name", "VIET NAM", - "lang", "vi", - "languages", "vi", - "fmt", "%N%n%O%n%A%n%C%n%S %Z", - "lfmt", "%N%n%O%n%A%n%C%n%S %Z", - }), - VU(new String[]{ - "name", "VANUATU", - }), - WF(new String[]{ - "name", "WALLIS AND FUTUNA ISLANDS", - "fmt", "%O%n%N%n%A%n%Z %C %X", - "require", "ACZ", - "upper", "ACX", - }), - WS(new String[]{ - "name", "SAMOA", - }), - XK(new String[]{ - "name", "KOSOVO", - "fmt", "%N%n%O%n%A%n%Z %C", - }), - YE(new String[]{ - "name", "YEMEN", - }), - YT(new String[]{ - "name", "MAYOTTE", - "fmt", "%O%n%N%n%A%n%Z %C %X", - "require", "ACZ", - "upper", "ACX", - }), - ZA(new String[]{ - "name", "SOUTH AFRICA", - "fmt", "%N%n%O%n%A%n%D%n%C%n%Z", - "require", "ACZ", - }), - ZM(new String[]{ - "name", "ZAMBIA", - "fmt", "%N%n%O%n%A%n%Z %C", - }), - ZW(new String[]{ - "name", "ZIMBABWE", - }), - ZZ(new String[]{ - "fmt", "%N%n%O%n%A%n%C", - "require", "AC", - "upper", "C", - "zip_name_type", "postal", - "state_name_type", "province", - "locality_name_type", "city", - "sublocality_name_type", "suburb", - }); + AC(new String[]{ + "name", "ASCENSION ISLAND", + }), + AD(new String[]{ + "name", "ANDORRA", + "lang", "ca", + "languages", "ca", + "fmt", "%N%n%O%n%A%n%Z %C", + "require", "A", + }), + AE(new String[]{ + "name", "UNITED ARAB EMIRATES", + "fmt", "%N%n%O%n%A%n%C", + "require", "AC", + }), + AF(new String[]{ + "name", "AFGHANISTAN", + }), + AG(new String[]{ + "name", "ANTIGUA AND BARBUDA", + "require", "A", + }), + AI(new String[]{ + "name", "ANGUILLA", + }), + AL(new String[]{ + "name", "ALBANIA", + }), + AM(new String[]{ + "name", "ARMENIA", + "lang", "hy", + "languages", "hy", + "fmt", "%N%n%O%n%A%n%Z%n%C%n%S", + "lfmt", "%N%n%O%n%A%n%Z%n%C%n%S", + }), + AO(new String[]{ + "name", "ANGOLA", + }), + AQ(new String[]{ + "name", "ANTARCTICA", + }), + AR(new String[]{ + "name", "ARGENTINA", + "lang", "es", + "languages", "es", + "fmt", "%N%n%O%n%A%n%Z %C%n%S", + "upper", "ACZ", + "state_name_type", "state", + }), + AS(new String[]{ + "name", "AMERICAN SAMOA", + "fmt", "%N%n%O%n%A%n%C %S %Z", + "require", "ACSZ", + "upper", "ACNOS", + "zip_name_type", "zip", + "state_name_type", "state", + }), + AT(new String[]{ + "name", "AUSTRIA", + "fmt", "%O%n%N%n%A%n%Z %C", + "require", "ACZ", + }), + AU(new String[]{ + "name", "AUSTRALIA", + "lang", "en", + "languages", "en", + "fmt", "%O%n%N%n%A%n%C %S %Z", + "require", "ACSZ", + "upper", "CS", + "state_name_type", "state", + }), + AW(new String[]{ + "name", "ARUBA", + }), + AX(new String[]{ + "name", "FINLAND", + "fmt", "%O%n%N%n%A%nAX-%Z %C%n\u00C5LAND", + "require", "ACZ", + "postprefix", "AX-", + }), + AZ(new String[]{ + "name", "AZERBAIJAN", + "fmt", "%N%n%O%n%A%nAZ %Z %C", + "postprefix", "AZ ", + }), + BA(new String[]{ + "name", "BOSNIA AND HERZEGOVINA", + "fmt", "%N%n%O%n%A%n%Z %C", + }), + BB(new String[]{ + "name", "BARBADOS", + "state_name_type", "parish", + }), + BD(new String[]{ + "name", "BANGLADESH", + "fmt", "%N%n%O%n%A%n%C - %Z", + }), + BE(new String[]{ + "name", "BELGIUM", + "fmt", "%O%n%N%n%A%n%Z %C", + "require", "ACZ", + }), + BF(new String[]{ + "name", "BURKINA FASO", + "fmt", "%N%n%O%n%A%n%C %X", + }), + BG(new String[]{ + "name", "BULGARIA (REP.)", + "fmt", "%N%n%O%n%A%n%Z %C", + }), + BH(new String[]{ + "name", "BAHRAIN", + "fmt", "%N%n%O%n%A%n%C %Z", + }), + BI(new String[]{ + "name", "BURUNDI", + }), + BJ(new String[]{ + "name", "BENIN", + "upper", "AC", + }), + BL(new String[]{ + "name", "SAINT BARTHELEMY", + "fmt", "%O%n%N%n%A%n%Z %C %X", + "upper", "ACX", + "require", "ACZ", + }), + BM(new String[]{ + "name", "BERMUDA", + "fmt", "%N%n%O%n%A%n%C %Z", + }), + BN(new String[]{ + "name", "BRUNEI DARUSSALAM", + "fmt", "%N%n%O%n%A%n%C %Z", + }), + BO(new String[]{ + "name", "BOLIVIA", + "upper", "AC", + }), + BR(new String[]{ + "name", "BRAZIL", + "lang", "pt", + "languages", "pt", + "fmt", "%O%n%N%n%A%n%D%n%C-%S%n%Z", + "require", "ASCZ", + "upper", "CS", + "state_name_type", "state", + "sublocality_name_type", "neighborhood", + }), + BS(new String[]{ + "name", "BAHAMAS", + "lang", "en", + "languages", "en", + "fmt", "%N%n%O%n%A%n%C, %S", + "state_name_type", "island", + }), + BT(new String[]{ + "name", "BHUTAN", + }), + BV(new String[]{ + "name", "BOUVET ISLAND", + }), + BW(new String[]{ + "name", "BOTSWANA", + }), + BY(new String[]{ + "name", "BELARUS", + "fmt", "%S%n%Z %C %X%n%A%n%O%n%N", + }), + BZ(new String[]{ + "name", "BELIZE", + }), + CA(new String[]{ + "name", "CANADA", + "lang", "en", + "languages", "en~fr", + "fmt", "%N%n%O%n%A%n%C %S %Z", + "require", "ACSZ", + "upper", "ACNOSZ", + }), + CC(new String[]{ + "name", "COCOS (KEELING) ISLANDS", + "fmt", "%O%n%N%n%A%n%C %S %Z", + "upper", "CS", + }), + CD(new String[]{ + "name", "CONGO (DEM. REP.)", + "fmt", "%N%n%O%n%A%n%C %X", + }), + CF(new String[]{ + "name", "CENTRAL AFRICAN REPUBLIC", + }), + CG(new String[]{ + "name", "CONGO (REP.)", + }), + CH(new String[]{ + "name", "SWITZERLAND", + "lang", "de", + "languages", "de~fr~it", + "fmt", "%O%n%N%n%A%nCH-%Z %C", + "require", "ACZ", + "upper", "", + "postprefix", "CH-", + }), + CI(new String[]{ + "name", "COTE D'IVOIRE", + "fmt", "%N%n%O%n%X %A %C %X", + }), + CK(new String[]{ + "name", "COOK ISLANDS", + }), + CL(new String[]{ + "name", "CHILE", + "lang", "es", + "languages", "es", + "fmt", "%N%n%O%n%A%n%Z %C%n%S", + "state_name_type", "state", + }), + CM(new String[]{ + "name", "CAMEROON", + }), + CN(new String[]{ + "name", "P.R. CHINA", + "lang", "zh-Hans", + "languages", "zh-Hans", + "fmt", "%Z%n%S%C%D%n%A%n%O%n%N", + "lfmt", "%N%n%O%n%A%n%D%n%C%n%S, %Z", + "require", "ACSZ", + "upper", "S", + "sublocality_name_type", "district", + }), + CO(new String[]{ + "name", "COLOMBIA", + "fmt", "%N%n%O%n%A%n%C, %S", + }), + CR(new String[]{ + "name", "COSTA RICA", + "fmt", "%N%n%O%n%A%n%Z %C", + }), + CV(new String[]{ + "name", "CAPE VERDE", + "lang", "pt", + "languages", "pt", + "fmt", "%N%n%O%n%A%n%Z %C%n%S", + "state_name_type", "island", + }), + CX(new String[]{ + "name", "CHRISTMAS ISLAND", + "fmt", "%O%n%N%n%A%n%C %S %Z", + "upper", "CS", + }), + CY(new String[]{ + "name", "CYPRUS", + "fmt", "%N%n%O%n%A%n%Z %C", + }), + CZ(new String[]{ + "name", "CZECH REP.", + "fmt", "%N%n%O%n%A%n%Z %C", + }), + DE(new String[]{ + "name", "GERMANY", + "fmt", "%N%n%O%n%A%n%Z %C", + "require", "ACZ", + }), + DJ(new String[]{ + "name", "DJIBOUTI", + }), + DK(new String[]{ + "name", "DENMARK", + "fmt", "%N%n%O%n%A%n%Z %C", + "require", "ACZ", + }), + DM(new String[]{ + "name", "DOMINICA", + }), + DO(new String[]{ + "name", "DOMINICAN REP.", + "fmt", "%N%n%O%n%A%n%Z %C", + }), + DZ(new String[]{ + "name", "ALGERIA", + "fmt", "%N%n%O%n%A%n%Z %C", + }), + EC(new String[]{ + "name", "ECUADOR", + "fmt", "%N%n%O%n%A%n%Z%n%C", + "upper", "CZ", + }), + EE(new String[]{ + "name", "ESTONIA", + "fmt", "%N%n%O%n%A%n%Z %C", + }), + EG(new String[]{ + "name", "EGYPT", + "lang", "ar", + "languages", "ar", + "fmt", "%N%n%O%n%A%n%C%n%S%n%Z", + "lfmt", "%N%n%O%n%A%n%C%n%S%n%Z", + }), + EH(new String[]{ + "name", "WESTERN SAHARA", + "fmt", "%N%n%O%n%A%n%Z %C", + }), + ER(new String[]{ + "name", "ERITREA", + }), + ES(new String[]{ + "name", "SPAIN", + "lang", "es", + "languages", "es", + "fmt", "%N%n%O%n%A%n%Z %C %S", + "require", "ACSZ", + "upper", "CS", + }), + ET(new String[]{ + "name", "ETHIOPIA", + "fmt", "%N%n%O%n%A%n%Z %C", + }), + FI(new String[]{ + "name", "FINLAND", + "fmt", "%O%n%N%n%A%nFI-%Z %C", + "require", "ACZ", + "postprefix", "FI-", + }), + FJ(new String[]{ + "name", "FIJI", + }), + FK(new String[]{ + "name", "FALKLAND ISLANDS (MALVINAS)", + "fmt", "%N%n%O%n%A%n%X%n%C%n%Z", + "require", "ACZ", + "upper", "CZ", + }), + FM(new String[]{ + "name", "MICRONESIA (Federated State of)", + "fmt", "%N%n%O%n%A%n%C %S %Z", + "require", "ACSZ", + "upper", "ACNOS", + "zip_name_type", "zip", + "state_name_type", "state", + }), + FO(new String[]{ + "name", "FAROE ISLANDS", + "fmt", "%N%n%O%n%A%nFO%Z %C", + "postprefix", "FO", + }), + FR(new String[]{ + "name", "FRANCE", + "fmt", "%O%n%N%n%A%n%Z %C %X", + "require", "ACZ", + "upper", "CX", + }), + GA(new String[]{ + "name", "GABON", + }), + GB(new String[]{ + "name", "UNITED KINGDOM", + "fmt", "%N%n%O%n%A%n%C%n%S%n%Z", + "require", "ACZ", + "upper", "CZ", + "state_name_type", "county", + "locality_name_type", "post_town", + }), + GD(new String[]{ + "name", "GRENADA (WEST INDIES)", + }), + GE(new String[]{ + "name", "GEORGIA", + "fmt", "%N%n%O%n%A%n%Z %C", + }), + GF(new String[]{ + "name", "FRENCH GUIANA", + "fmt", "%O%n%N%n%A%n%Z %C %X", + "require", "ACZ", + "upper", "ACX", + }), + GG(new String[]{ + "name", "CHANNEL ISLANDS", + "fmt", "%N%n%O%n%A%n%X%n%C%nGUERNSEY%n%Z", + "require", "ACZ", + "upper", "CZ", + }), + GH(new String[]{ + "name", "GHANA", + }), + GI(new String[]{ + "name", "GIBRALTAR", + "fmt", "%N%n%O%n%A%nGIBRALTAR%n%Z", + "require", "A", + }), + GL(new String[]{ + "name", "GREENLAND", + "fmt", "%N%n%O%n%A%n%Z %C", + "require", "ACZ", + }), + GM(new String[]{ + "name", "GAMBIA", + }), + GN(new String[]{ + "name", "GUINEA", + "fmt", "%N%n%O%n%Z %A %C", + }), + GP(new String[]{ + "name", "GUADELOUPE", + "fmt", "%O%n%N%n%A%n%Z %C %X", + "require", "ACZ", + "upper", "ACX", + }), + GQ(new String[]{ + "name", "EQUATORIAL GUINEA", + }), + GR(new String[]{ + "name", "GREECE", + "fmt", "%N%n%O%n%A%n%Z %C", + "require", "ACZ", + }), + GS(new String[]{ + "name", "SOUTH GEORGIA", + "fmt", "%N%n%O%n%A%n%X%n%C%n%Z", + "require", "ACZ", + "upper", "CZ", + }), + GT(new String[]{ + "name", "GUATEMALA", + "fmt", "%N%n%O%n%A%n%Z- %C", + }), + GU(new String[]{ + "name", "GUAM", + "fmt", "%N%n%O%n%A%n%C %S %Z", + "require", "ACSZ", + "upper", "ACNOS", + "zip_name_type", "zip", + "state_name_type", "state", + }), + GW(new String[]{ + "name", "GUINEA-BISSAU", + "fmt", "%N%n%O%n%A%n%Z %C", + }), + GY(new String[]{ + "name", "GUYANA", + }), + HK(new String[]{ + "name", "HONG KONG", + "lang", "zh-Hant", + "languages", "zh-Hant~en", + "fmt", "%S%n%C%n%A%n%O%n%N", + "lfmt", "%N%n%O%n%A%n%C%n%S", + "require", "AS", + "upper", "S", + "state_name_type", "area", + "locality_name_type", "district", + }), + HM(new String[]{ + "name", "HEARD AND MCDONALD ISLANDS", + "fmt", "%O%n%N%n%A%n%C %S %Z", + "upper", "CS", + }), + HN(new String[]{ + "name", "HONDURAS", + "fmt", "%N%n%O%n%A%n%C, %S%n%Z", + "require", "ACS", + }), + HR(new String[]{ + "name", "CROATIA", + "fmt", "%N%n%O%n%A%nHR-%Z %C", + "postprefix", "HR-", + }), + HT(new String[]{ + "name", "HAITI", + "fmt", "%N%n%O%n%A%nHT%Z %C %X", + "postprefix", "HT", + }), + HU(new String[]{ + "name", "HUNGARY (Rep.)", + "fmt", "%N%n%O%n%C%n%A%n%Z", + "upper", "ACNO", + }), + ID(new String[]{ + "name", "INDONESIA", + "lang", "id", + "languages", "id", + "fmt", "%N%n%O%n%A%n%C%n%S %Z", + }), + IE(new String[]{ + "name", "IRELAND", + "lang", "en", + "languages", "en", + "fmt", "%N%n%O%n%A%n%C%n%S", + "state_name_type", "county", + }), + IL(new String[]{ + "name", "ISRAEL", + "fmt", "%N%n%O%n%A%n%C %Z", + }), + IM(new String[]{ + "name", "ISLE OF MAN", + "fmt", "%N%n%O%n%A%n%X%n%C%n%Z", + "require", "ACZ", + "upper", "CZ", + }), + IN(new String[]{ + "name", "INDIA", + "lang", "en", + "languages", "en", + "fmt", "%N%n%O%n%A%n%C %Z%n%S", + "require", "ACSZ", + "state_name_type", "state", + }), + IO(new String[]{ + "name", "BRITISH INDIAN OCEAN TERRITORY", + "fmt", "%N%n%O%n%A%n%X%n%C%n%Z", + "require", "ACZ", + "upper", "CZ", + }), + IQ(new String[]{ + "name", "IRAQ", + "fmt", "%O%n%N%n%A%n%C, %S%n%Z", + "require", "ACS", + "upper", "CS", + }), + IS(new String[]{ + "name", "ICELAND", + "fmt", "%N%n%O%n%A%n%Z %C", + }), + IT(new String[]{ + "name", "ITALY", + "lang", "it", + "languages", "it", + "fmt", "%N%n%O%n%A%n%Z %C %S", + "require", "ACSZ", + "upper", "CS", + }), + JE(new String[]{ + "name", "CHANNEL ISLANDS", + "fmt", "%N%n%O%n%A%n%X%n%C%nJERSEY%n%Z", + "require", "ACZ", + "upper", "CZ", + }), + JM(new String[]{ + "name", "JAMAICA", + "lang", "en", + "languages", "en", + "fmt", "%N%n%O%n%A%n%C%n%S %X", + "require", "ACS", + "state_name_type", "parish", + }), + JO(new String[]{ + "name", "JORDAN", + "fmt", "%N%n%O%n%A%n%C %Z", + }), + JP(new String[]{ + "name", "JAPAN", + "lang", "ja", + "languages", "ja", + "fmt", "\u3012%Z%n%S%C%n%A%n%O%n%N", + "lfmt", "%N%n%O%n%A%n%C, %S%n%Z", + "require", "ACSZ", + "upper", "S", + "state_name_type", "prefecture", + }), + KE(new String[]{ + "name", "KENYA", + "fmt", "%N%n%O%n%A%n%C%n%Z", + }), + KG(new String[]{ + "name", "KYRGYZSTAN", + "fmt", "%Z %C %X%n%A%n%O%n%N", + }), + KH(new String[]{ + "name", "CAMBODIA", + "fmt", "%N%n%O%n%A%n%C %Z", + }), + KI(new String[]{ + "name", "KIRIBATI", + "fmt", "%N%n%O%n%A%n%S%n%C", + "upper", "ACNOS", + "state_name_type", "island", + }), + KM(new String[]{ + "name", "COMOROS", + "upper", "AC", + }), + KN(new String[]{ + "name", "SAINT KITTS AND NEVIS", + "lang", "en", + "languages", "en", + "fmt", "%N%n%O%n%A%n%C, %S", + "require", "ACS", + "state_name_type", "island", + }), + KR(new String[]{ + "name", "KOREA (REP.)", + "lang", "ko", + "languages", "ko", + "fmt", "%S %C%D%n%A%n%O%n%N%n%Z", + "lfmt", "%N%n%O%n%A%n%D%n%C%n%S%n%Z", + "require", "ACSZ", + "upper", "Z", + "state_name_type", "do_si", + "sublocality_name_type", "district", + }), + KW(new String[]{ + "name", "KUWAIT", + "fmt", "%N%n%O%n%A%n%Z %C", + }), + KY(new String[]{ + "name", "CAYMAN ISLANDS", + "lang", "en", + "languages", "en", + "fmt", "%N%n%O%n%A%n%S %Z", + "require", "AS", + "state_name_type", "island", + }), + KZ(new String[]{ + "name", "KAZAKHSTAN", + "fmt", "%Z%n%S%n%C%n%A%n%O%n%N", + }), + LA(new String[]{ + "name", "LAO (PEOPLE'S DEM. REP.)", + "fmt", "%N%n%O%n%A%n%Z %C", + }), + LB(new String[]{ + "name", "LEBANON", + "fmt", "%N%n%O%n%A%n%C %Z", + }), + LC(new String[]{ + "name", "SAINT LUCIA", + }), + LI(new String[]{ + "name", "LIECHTENSTEIN", + "fmt", "%O%n%N%n%A%nFL-%Z %C", + "require", "ACZ", + "postprefix", "FL-", + }), + LK(new String[]{ + "name", "SRI LANKA", + "fmt", "%N%n%O%n%A%n%C%n%Z", + }), + LR(new String[]{ + "name", "LIBERIA", + "fmt", "%N%n%O%n%A%n%Z %C %X", + }), + LS(new String[]{ + "name", "LESOTHO", + "fmt", "%N%n%O%n%A%n%C %Z", + }), + LT(new String[]{ + "name", "LITHUANIA", + "fmt", "%O%n%N%n%A%nLT-%Z %C", + "postprefix", "LT-", + }), + LU(new String[]{ + "name", "LUXEMBOURG", + "fmt", "%O%n%N%n%A%nL-%Z %C", + "require", "ACZ", + "postprefix", "L-", + }), + LV(new String[]{ + "name", "LATVIA", + "fmt", "%N%n%O%n%A%n%C, %Z", + }), + LY(new String[]{ + "name", "LIBYA", + }), + MA(new String[]{ + "name", "MOROCCO", + "fmt", "%N%n%O%n%A%n%Z %C", + }), + MC(new String[]{ + "name", "MONACO", + "fmt", "%N%n%O%n%A%nMC-%Z %C %X", + "postprefix", "MC-", + }), + MD(new String[]{ + "name", "Rep. MOLDOVA", + "fmt", "%N%n%O%n%A%nMD-%Z %C", + "postprefix", "MD-", + }), + ME(new String[]{ + "name", "MONTENEGRO", + "fmt", "%N%n%O%n%A%n%Z %C", + }), + MF(new String[]{ + "name", "SAINT MARTIN", + "fmt", "%O%n%N%n%A%n%Z %C %X", + "upper", "ACX", + "require", "ACZ", + }), + MG(new String[]{ + "name", "MADAGASCAR", + "fmt", "%N%n%O%n%A%n%Z %C", + }), + MH(new String[]{ + "name", "MARSHALL ISLANDS", + "fmt", "%N%n%O%n%A%n%C %S %Z", + "require", "ACSZ", + "upper", "ACNOS", + "zip_name_type", "zip", + "state_name_type", "state", + }), + MK(new String[]{ + "name", "MACEDONIA", + "fmt", "%N%n%O%n%A%n%Z %C", + }), + ML(new String[]{ + "name", "MALI", + }), + MN(new String[]{ + "name", "MONGOLIA", + "fmt", "%N%n%O%n%A%n%S %C-%X%n%Z", + }), + MO(new String[]{ + "name", "MACAO", + "lang", "zh-Hant", + "languages", "zh-Hant", + "fmt", "%A%n%O%n%N", + "lfmt", "%N%n%O%n%A", + "require", "A", + }), + MP(new String[]{ + "name", "NORTHERN MARIANA ISLANDS", + "fmt", "%N%n%O%n%A%n%C %S %Z", + "require", "ACSZ", + "upper", "ACNOS", + "zip_name_type", "zip", + "state_name_type", "state", + }), + MQ(new String[]{ + "name", "MARTINIQUE", + "fmt", "%O%n%N%n%A%n%Z %C %X", + "require", "ACZ", + "upper", "ACX", + }), + MR(new String[]{ + "name", "MAURITANIA", + "upper", "AC", + }), + MS(new String[]{ + "name", "MONTSERRAT", + }), + MT(new String[]{ + "name", "MALTA", + "fmt", "%N%n%O%n%A%n%C %Z", + "upper", "CZ", + }), + MU(new String[]{ + "name", "MAURITIUS", + "fmt", "%N%n%O%n%A%n%Z%n%C", + "upper", "CZ", + }), + MV(new String[]{ + "name", "MALDIVES", + "fmt", "%N%n%O%n%A%n%C %Z", + }), + MW(new String[]{ + "name", "MALAWI", + "fmt", "%N%n%O%n%A%n%C %X", + }), + MX(new String[]{ + "name", "MEXICO", + "lang", "es", + "languages", "es", + "fmt", "%N%n%O%n%A%n%D%n%Z %C, %S", + "require", "ACZ", + "upper", "CSZ", + "state_name_type", "state", + "sublocality_name_type", "neighborhood", + }), + MY(new String[]{ + "name", "MALAYSIA", + "lang", "ms", + "languages", "ms", + "fmt", "%N%n%O%n%A%n%D%n%Z %C%n%S", + "require", "ACZ", + "upper", "CS", + "state_name_type", "state", + "sublocality_name_type", "village_township", + }), + MZ(new String[]{ + "name", "MOZAMBIQUE", + }), + NA(new String[]{ + "name", "NAMIBIA", + }), + NC(new String[]{ + "name", "NEW CALEDONIA", + "fmt", "%O%n%N%n%A%n%Z %C %X", + "require", "ACZ", + "upper", "ACX", + }), + NE(new String[]{ + "name", "NIGER", + "fmt", "%N%n%O%n%A%n%Z %C", + }), + NF(new String[]{ + "name", "NORFOLK ISLAND", + "fmt", "%O%n%N%n%A%n%C %S %Z", + "upper", "CS", + }), + NG(new String[]{ + "name", "NIGERIA", + "lang", "en", + "languages", "en", + "fmt", "%N%n%O%n%A%n%C %Z%n%S", + "upper", "CS", + "state_name_type", "state", + }), + NI(new String[]{ + "name", "NICARAGUA", + "lang", "es", + "languages", "es", + "fmt", "%N%n%O%n%A%n%Z%n%C, %S", + "upper", "CS", + "state_name_type", "department", + }), + NL(new String[]{ + "name", "NETHERLANDS", + "fmt", "%O%n%N%n%A%n%Z %C", + "require", "ACZ", + }), + NO(new String[]{ + "name", "NORWAY", + "fmt", "%N%n%O%n%A%n%Z %C", + "require", "ACZ", + }), + NP(new String[]{ + "name", "NEPAL", + "fmt", "%N%n%O%n%A%n%C %Z", + }), + NR(new String[]{ + "name", "NAURU CENTRAL PACIFIC", + "lang", "en", + "languages", "en", + "fmt", "%N%n%O%n%A%n%S", + "require", "AS", + "state_name_type", "district", + }), + NU(new String[]{ + "name", "NIUE", + }), + NZ(new String[]{ + "name", "NEW ZEALAND", + "fmt", "%N%n%O%n%A%n%D%n%C %Z", + "require", "ACZ", + }), + OM(new String[]{ + "name", "OMAN", + "fmt", "%N%n%O%n%A%n%Z%n%C", + }), + PA(new String[]{ + "name", "PANAMA (REP.)", + "fmt", "%N%n%O%n%A%n%C%n%S", + "upper", "CS", + }), + PE(new String[]{ + "name", "PERU", + }), + PF(new String[]{ + "name", "FRENCH POLYNESIA", + "fmt", "%N%n%O%n%A%n%Z %C %S", + "require", "ACSZ", + "upper", "CS", + "state_name_type", "island", + }), + PG(new String[]{ + "name", "PAPUA NEW GUINEA", + "fmt", "%N%n%O%n%A%n%C %Z %S", + "require", "ACS", + }), + PH(new String[]{ + "name", "PHILIPPINES", + "lang", "en", + "languages", "en", + "fmt", "%N%n%O%n%A%n%D, %C%n%Z %S", + "require", "AC", + }), + PK(new String[]{ + "name", "PAKISTAN", + "fmt", "%N%n%O%n%A%n%C-%Z", + }), + PL(new String[]{ + "name", "POLAND", + "fmt", "%N%n%O%n%A%n%Z %C", + "require", "ACZ", + }), + PM(new String[]{ + "name", "ST. PIERRE AND MIQUELON", + "fmt", "%O%n%N%n%A%n%Z %C %X", + "require", "ACZ", + "upper", "ACX", + }), + PN(new String[]{ + "name", "PITCAIRN", + "fmt", "%N%n%O%n%A%n%X%n%C%n%Z", + "require", "ACZ", + "upper", "CZ", + }), + PR(new String[]{ + "name", "PUERTO RICO", + "fmt", "%N%n%O%n%A%n%C PR %Z", + "require", "ACZ", + "upper", "ACNO", + "zip_name_type", "zip", + "postprefix", "PR", + }), + PS(new String[]{ + "name", "PALESTINIAN TERRITORY", + }), + PT(new String[]{ + "name", "PORTUGAL", + "fmt", "%N%n%O%n%A%n%Z %C", + "require", "ACZ", + }), + PW(new String[]{ + "name", "PALAU", + "fmt", "%N%n%O%n%A%n%C %S %Z", + "require", "ACSZ", + "upper", "ACNOS", + "zip_name_type", "zip", + "state_name_type", "state", + }), + PY(new String[]{ + "name", "PARAGUAY", + "fmt", "%N%n%O%n%A%n%Z %C", + }), + QA(new String[]{ + "name", "QATAR", + "upper", "AC", + }), + RE(new String[]{ + "name", "REUNION", + "fmt", "%O%n%N%n%A%n%Z %C %X", + "require", "ACZ", + "upper", "ACX", + }), + RO(new String[]{ + "name", "ROMANIA", + "fmt", "%N%n%O%n%A%n%Z %C", + "upper", "AC", + }), + RS(new String[]{ + "name", "REPUBLIC OF SERBIA", + "fmt", "%N%n%O%n%A%n%Z %C", + }), + RU(new String[]{ + "name", "RUSSIAN FEDERATION", + "fmt", "%N%n%O%n%A%n%C%n%S%n%Z", + "require", "ACZ", + "upper", "AC", + "state_name_type", "oblast", + }), + RW(new String[]{ + "name", "RWANDA", + "upper", "AC", + }), + SA(new String[]{ + "name", "SAUDI ARABIA", + "fmt", "%N%n%O%n%A%n%C %Z", + }), + SB(new String[]{ + "name", "SOLOMON ISLANDS", + }), + SC(new String[]{ + "name", "SEYCHELLES", + "fmt", "%N%n%O%n%A%n%C%n%S", + "upper", "S", + "state_name_type", "island", + }), + SE(new String[]{ + "name", "SWEDEN", + "fmt", "%O%n%N%n%A%nSE-%Z %C", + "require", "ACZ", + "postprefix", "SE-", + }), + SG(new String[]{ + "name", "REP. OF SINGAPORE", + "fmt", "%N%n%O%n%A%nSINGAPORE %Z", + "require", "AZ", + }), + SH(new String[]{ + "name", "SAINT HELENA", + "fmt", "%N%n%O%n%A%n%X%n%C%n%Z", + "require", "ACZ", + "upper", "CZ", + }), + SI(new String[]{ + "name", "SLOVENIA", + "fmt", "%N%n%O%n%A%nSI- %Z %C", + "postprefix", "SI-", + }), + SJ(new String[]{ + "name", "SVALBARD AND JAN MAYEN ISLANDS", + "fmt", "%N%n%O%n%A%n%Z %C", + "require", "ACZ", + }), + SK(new String[]{ + "name", "SLOVAKIA", + "fmt", "%N%n%O%n%A%n%Z %C", + }), + SL(new String[]{ + "name", "SIERRA LEONE", + }), + SM(new String[]{ + "name", "SAN MARINO", + "fmt", "%N%n%O%n%A%n%Z %C", + "require", "AZ", + }), + SN(new String[]{ + "name", "SENEGAL", + "fmt", "%N%n%O%n%A%n%Z %C", + }), + SO(new String[]{ + "name", "SOMALIA", + "lang", "so", + "languages", "so", + "fmt", "%N%n%O%n%A%n%C, %S %Z", + "require", "ACS", + "upper", "ACS", + }), + SR(new String[]{ + "name", "SURINAME", + "lang", "nl", + "languages", "nl", + "fmt", "%N%n%O%n%A%n%C %X%n%S", + "upper", "AS", + }), + ST(new String[]{ + "name", "SAO TOME AND PRINCIPE", + "fmt", "%N%n%O%n%A%n%C %X", + }), + SV(new String[]{ + "name", "EL SALVADOR", + "lang", "es", + "languages", "es", + "fmt", "%N%n%O%n%A%n%Z-%C%n%S", + "require", "ACS", + "upper", "CSZ", + }), + SZ(new String[]{ + "name", "SWAZILAND", + "fmt", "%N%n%O%n%A%n%C%n%Z", + "upper", "ACZ", + }), + TA(new String[]{ + "name", "TRISTAN DA CUNHA", + }), + TC(new String[]{ + "name", "TURKS AND CAICOS ISLANDS", + "fmt", "%N%n%O%n%A%n%X%n%C%n%Z", + "require", "ACZ", + "upper", "CZ", + }), + TD(new String[]{ + "name", "CHAD", + }), + TF(new String[]{ + "name", "FRENCH SOUTHERN TERRITORIES", + }), + TG(new String[]{ + "name", "TOGO", + }), + TH(new String[]{ + "name", "THAILAND", + "lang", "th", + "languages", "th", + "fmt", "%N%n%O%n%A%n%D %C%n%S %Z", + "lfmt", "%N%n%O%n%A%n%D, %C%n%S %Z", + "upper", "S", + }), + TJ(new String[]{ + "name", "TAJIKISTAN", + "fmt", "%N%n%O%n%A%n%Z %C", + }), + TK(new String[]{ + "name", "TOKELAU", + }), + TL(new String[]{ + "name", "TIMOR-LESTE", + }), + TM(new String[]{ + "name", "TURKMENISTAN", + "fmt", "%N%n%O%n%A%n%Z %C", + }), + TN(new String[]{ + "name", "TUNISIA", + "fmt", "%N%n%O%n%A%n%Z %C", + }), + TO(new String[]{ + "name", "TONGA", + }), + TR(new String[]{ + "name", "TURKEY", + "lang", "tr", + "languages", "tr", + "fmt", "%N%n%O%n%A%n%Z %C/%S", + "require", "ACZ", + "locality_name_type", "district", + }), + TT(new String[]{ + "name", "TRINIDAD AND TOBAGO", + }), + TV(new String[]{ + "name", "TUVALU", + "lang", "tyv", + "languages", "tyv", + "fmt", "%N%n%O%n%A%n%X%n%C%n%S", + "upper", "ACS", + "state_name_type", "island", + }), + TW(new String[]{ + "name", "TAIWAN", + "lang", "zh-Hant", + "languages", "zh-Hant", + "fmt", "%Z%n%S%C%n%A%n%O%n%N", + "lfmt", "%N%n%O%n%A%n%C, %S %Z", + "require", "ACSZ", + "state_name_type", "county", + }), + TZ(new String[]{ + "name", "TANZANIA (UNITED REP.)", + }), + UA(new String[]{ + "name", "UKRAINE", + "fmt", "%N%n%O%n%A%n%C%n%S%n%Z", + "require", "ACZ", + "state_name_type", "oblast", + }), + UG(new String[]{ + "name", "UGANDA", + }), + UM(new String[]{ + "name", "UNITED STATES MINOR OUTLYING ISLANDS", + "fmt", "%N%n%O%n%A%n%C %S %Z", + "require", "ACS", + "upper", "ACNOS", + "zip_name_type", "zip", + "state_name_type", "state", + }), + US(new String[]{ + "name", "UNITED STATES", + "lang", "en", + "languages", "en", + "fmt", "%N%n%O%n%A%n%C, %S %Z", + "require", "ACSZ", + "upper", "CS", + "zip_name_type", "zip", + "state_name_type", "state", + }), + UY(new String[]{ + "name", "URUGUAY", + "lang", "es", + "languages", "es", + "fmt", "%N%n%O%n%A%n%Z %C %S", + "upper", "CS", + }), + UZ(new String[]{ + "name", "UZBEKISTAN", + "fmt", "%N%n%O%n%A%n%Z %C%n%S", + "upper", "CS", + }), + VA(new String[]{ + "name", "VATICAN", + "fmt", "%N%n%O%n%A%n%Z %C", + }), + VC(new String[]{ + "name", "SAINT VINCENT AND THE GRENADINES (ANTILLES)", + }), + VE(new String[]{ + "name", "VENEZUELA", + "lang", "es", + "languages", "es", + "fmt", "%N%n%O%n%A%n%C %Z, %S", + "require", "ACS", + "upper", "CS", + }), + VG(new String[]{ + "name", "VIRGIN ISLANDS (BRITISH)", + "fmt", "%N%n%O%n%A%n%C%n%Z", + "require", "A", + }), + VI(new String[]{ + "name", "VIRGIN ISLANDS (U.S.)", + "fmt", "%N%n%O%n%A%n%C %S %Z", + "require", "ACSZ", + "upper", "ACNOS", + "zip_name_type", "zip", + "state_name_type", "state", + }), + VN(new String[]{ + "name", "VIET NAM", + "lang", "vi", + "languages", "vi", + "fmt", "%N%n%O%n%A%n%C%n%S %Z", + "lfmt", "%N%n%O%n%A%n%C%n%S %Z", + }), + VU(new String[]{ + "name", "VANUATU", + }), + WF(new String[]{ + "name", "WALLIS AND FUTUNA ISLANDS", + "fmt", "%O%n%N%n%A%n%Z %C %X", + "require", "ACZ", + "upper", "ACX", + }), + WS(new String[]{ + "name", "SAMOA", + }), + XK(new String[]{ + "name", "KOSOVO", + "fmt", "%N%n%O%n%A%n%Z %C", + }), + YE(new String[]{ + "name", "YEMEN", + }), + YT(new String[]{ + "name", "MAYOTTE", + "fmt", "%O%n%N%n%A%n%Z %C %X", + "require", "ACZ", + "upper", "ACX", + }), + ZA(new String[]{ + "name", "SOUTH AFRICA", + "fmt", "%N%n%O%n%A%n%D%n%C%n%Z", + "require", "ACZ", + }), + ZM(new String[]{ + "name", "ZAMBIA", + "fmt", "%N%n%O%n%A%n%Z %C", + }), + ZW(new String[]{ + "name", "ZIMBABWE", + }), + ZZ(new String[]{ + "fmt", "%N%n%O%n%A%n%C", + "require", "AC", + "upper", "C", + "zip_name_type", "postal", + "state_name_type", "province", + "locality_name_type", "city", + "sublocality_name_type", "suburb", + }); - private String jsonString; + private String jsonString; - private RegionDataEnum(String[] inputArray) { - jsonString = convertArrayToJsonString(inputArray); - } - - String getJsonString() { - return jsonString; - } + private RegionDataEnum(String[] inputArray) { + jsonString = convertArrayToJsonString(inputArray); } - static { - for (RegionDataEnum region : RegionDataEnum.values()) { - COUNTRY_FORMAT_MAP.put(region.toString(), region.getJsonString()); - } + String getJsonString() { + return jsonString; } + } - static Map getCountryFormatMap() { - return COUNTRY_FORMAT_MAP; + static { + for (RegionDataEnum region : RegionDataEnum.values()) { + COUNTRY_FORMAT_MAP.put(region.toString(), region.getJsonString()); } + } + + static Map getCountryFormatMap() { + return COUNTRY_FORMAT_MAP; + } - /** - * Assumes the array is a well-formed array - i.e., there are no unmatched keys in the input. - * Package-private so it can be accessed by tests. - */ - static String convertArrayToJsonString(String[] input) { - JSONObject object = new JSONObject(); - for (int i = 0; i < input.length; i += 2) { - try { - object.put(input[i], input[i + 1]); - } catch (JSONException e) { - // Ignore for now. - } - } - return object.toString(); + /** + * Assumes the array is a well-formed array - i.e., there are no unmatched keys in the input. + * Package-private so it can be accessed by tests. + */ + static String convertArrayToJsonString(String[] input) { + JSONObject object = new JSONObject(); + for (int i = 0; i < input.length; i += 2) { + try { + object.put(input[i], input[i + 1]); + } catch (JSONException e) { + // Ignore for now. + } } + return object.toString(); + } } diff --git a/java/src/com/android/i18n/addressinput/SimpleClientCacheManager.java b/java/src/com/android/i18n/addressinput/SimpleClientCacheManager.java index c8943ea..4e253c8 100644 --- a/java/src/com/android/i18n/addressinput/SimpleClientCacheManager.java +++ b/java/src/com/android/i18n/addressinput/SimpleClientCacheManager.java @@ -20,20 +20,20 @@ package com.android.i18n.addressinput; * A simple implementation of ClientCacheManager which doesn't do any caching on its own. */ public class SimpleClientCacheManager implements ClientCacheManager { - // URL to get public address data. - private static final String PUBLIC_ADDRESS_SERVER = "http://i18napis.appspot.com/address"; + // URL to get public address data. + private static final String PUBLIC_ADDRESS_SERVER = "http://i18napis.appspot.com/address"; - @Override - public String get(String key) { - return ""; - } + @Override + public String get(String key) { + return ""; + } - @Override - public void put(String key, String data) { - } + @Override + public void put(String key, String data) { + } - @Override - public String getAddressServerUrl() { - return PUBLIC_ADDRESS_SERVER; - } + @Override + public String getAddressServerUrl() { + return PUBLIC_ADDRESS_SERVER; + } } diff --git a/java/src/com/android/i18n/addressinput/StandardAddressVerifier.java b/java/src/com/android/i18n/addressinput/StandardAddressVerifier.java index fccb24b..1b547c1 100644 --- a/java/src/com/android/i18n/addressinput/StandardAddressVerifier.java +++ b/java/src/com/android/i18n/addressinput/StandardAddressVerifier.java @@ -39,200 +39,200 @@ import java.util.Map; */ public class StandardAddressVerifier { - protected final FieldVerifier mRootVerifier; - - protected final VerifierRefiner mRefiner; - - protected final Map> mProblemMap; - - /** - * Uses the rootVerifier and {@link #DEFAULT_REFINER} to perform the standard checks on the - * address fields, as defined in {@link StandardChecks}. - */ - public StandardAddressVerifier(FieldVerifier rootVerifier) { - this(rootVerifier, DEFAULT_REFINER, StandardChecks.PROBLEM_MAP); - } - - /** - * Uses the rootVerifier and the refiner to perform the standard checks on the address fields, - * as defined in {@link StandardChecks}. - */ - public StandardAddressVerifier(FieldVerifier rootVerifier, VerifierRefiner refiner) { - this(rootVerifier, refiner, StandardChecks.PROBLEM_MAP); - } - - /** - * Uses the rootVerifier and {@link #DEFAULT_REFINER} to perform the given checks on the address - * fields. A reference to problemMap is maintained. It is not modified by this class, and should - * not be modified subsequent to this call. - */ - public StandardAddressVerifier(FieldVerifier rootVerifier, - Map> problemMap) { - this(rootVerifier, DEFAULT_REFINER, problemMap); + protected final FieldVerifier rootVerifier; + + protected final VerifierRefiner refiner; + + protected final Map> problemMap; + + /** + * Uses the rootVerifier and {@link #DEFAULT_REFINER} to perform the standard checks on the + * address fields, as defined in {@link StandardChecks}. + */ + public StandardAddressVerifier(FieldVerifier rootVerifier) { + this(rootVerifier, DEFAULT_REFINER, StandardChecks.PROBLEM_MAP); + } + + /** + * Uses the rootVerifier and the refiner to perform the standard checks on the address fields, + * as defined in {@link StandardChecks}. + */ + public StandardAddressVerifier(FieldVerifier rootVerifier, VerifierRefiner refiner) { + this(rootVerifier, refiner, StandardChecks.PROBLEM_MAP); + } + + /** + * Uses the rootVerifier and {@link #DEFAULT_REFINER} to perform the given checks on the address + * fields. A reference to problemMap is maintained. It is not modified by this class, and should + * not be modified subsequent to this call. + */ + public StandardAddressVerifier(FieldVerifier rootVerifier, + Map> problemMap) { + this(rootVerifier, DEFAULT_REFINER, problemMap); + } + + /** + * Uses the rootVerifier and the refiner to perform the given checks on the address fields. A + * reference to problemMap is maintained. It is not modified by this class, and should not be + * modified subsequent to this call. + */ + public StandardAddressVerifier(FieldVerifier rootVerifier, VerifierRefiner refiner, + Map> problemMap) { + this.rootVerifier = rootVerifier; + this.refiner = refiner; + this.problemMap = StandardChecks.PROBLEM_MAP; + } + + public void verify(AddressData address, AddressProblems problems) { + NotifyingListener listener = new NotifyingListener(this); + verifyAsync(address, problems, listener); + try { + listener.waitLoadingEnd(); + } catch (InterruptedException e) { + throw new RuntimeException(e); } - - /** - * Uses the rootVerifier and the refiner to perform the given checks on the address fields. A - * reference to problemMap is maintained. It is not modified by this class, and should not be - * modified subsequent to this call. - */ - public StandardAddressVerifier(FieldVerifier rootVerifier, VerifierRefiner refiner, - Map> problemMap) { - mRootVerifier = rootVerifier; - mRefiner = refiner; - mProblemMap = StandardChecks.PROBLEM_MAP; + } + + public void verifyAsync(AddressData address, AddressProblems problems, + DataLoadListener listener) { + Thread verifier = new Thread(new Verifier(address, problems, listener)); + verifier.start(); + } + + private class Verifier implements Runnable { + private AddressData address; + private AddressProblems problems; + private DataLoadListener listener; + + Verifier(AddressData address, AddressProblems problems, DataLoadListener listener) { + address = address; + problems = problems; + listener = listener; } - public void verify(AddressData address, AddressProblems problems) { - NotifyingListener listener = new NotifyingListener(this); - verifyAsync(address, problems, listener); - try { - listener.waitLoadingEnd(); - } catch (InterruptedException e) { - throw new RuntimeException(e); - } - } - - public void verifyAsync(AddressData address, AddressProblems problems, - DataLoadListener listener) { - Thread verifier = new Thread(new Verifier(address, problems, listener)); - verifier.start(); - } + @Override + public void run() { + listener.dataLoadingBegin(); - private class Verifier implements Runnable { - private AddressData mAddress; - private AddressProblems mProblems; - private DataLoadListener mListener; + FieldVerifier v = rootVerifier; - Verifier(AddressData address, AddressProblems problems, DataLoadListener listener) { - mAddress = address; - mProblems = problems; - mListener = listener; + ScriptType script = null; + if (address.getLanguageCode() != null) { + if (Util.isExplicitLatinScript(address.getLanguageCode())) { + script = ScriptType.LATIN; + } else { + script = ScriptType.LOCAL; } - - @Override - public void run() { - mListener.dataLoadingBegin(); - - FieldVerifier v = mRootVerifier; - - ScriptType script = null; - if (mAddress.getLanguageCode() != null) { - if (Util.isExplicitLatinScript(mAddress.getLanguageCode())) { - script = ScriptType.LATIN; - } else { - script = ScriptType.LOCAL; - } - } - - // The first four calls refine the verifier, so must come first, and in this - // order. - verifyField(script, v, COUNTRY, mAddress.getPostalCountry(), mProblems); - if (mProblems.isEmpty()) { - v = v.refineVerifier(mAddress.getPostalCountry()); - verifyField(script, v, ADMIN_AREA, mAddress.getAdministrativeArea(), mProblems); - if (mProblems.isEmpty()) { - v = v.refineVerifier(mAddress.getAdministrativeArea()); - verifyField(script, v, LOCALITY, mAddress.getLocality(), mProblems); - if (mProblems.isEmpty()) { - v = v.refineVerifier(mAddress.getLocality()); - verifyField(script, v, DEPENDENT_LOCALITY, - mAddress.getDependentLocality(), mProblems); - if (mProblems.isEmpty()) { - v = v.refineVerifier(mAddress.getDependentLocality()); - } - } - } + } + + // The first four calls refine the verifier, so must come first, and in this + // order. + verifyField(script, v, COUNTRY, address.getPostalCountry(), problems); + if (problems.isEmpty()) { + v = v.refineVerifier(address.getPostalCountry()); + verifyField(script, v, ADMIN_AREA, address.getAdministrativeArea(), problems); + if (problems.isEmpty()) { + v = v.refineVerifier(address.getAdministrativeArea()); + verifyField(script, v, LOCALITY, address.getLocality(), problems); + if (problems.isEmpty()) { + v = v.refineVerifier(address.getLocality()); + verifyField(script, v, DEPENDENT_LOCALITY, + address.getDependentLocality(), problems); + if (problems.isEmpty()) { + v = v.refineVerifier(address.getDependentLocality()); } + } + } + } - String street = Util.joinAndSkipNulls("\n", mAddress.getAddressLine1(), - mAddress.getAddressLine2()); + String street = Util.joinAndSkipNulls("\n", address.getAddressLine1(), + address.getAddressLine2()); - // remaining calls don't change the field verifier - verifyField(script, v, POSTAL_CODE, mAddress.getPostalCode(), mProblems); - verifyField(script, v, STREET_ADDRESS, street, mProblems); - verifyField(script, v, SORTING_CODE, mAddress.getSortingCode(), mProblems); - verifyField(script, v, ORGANIZATION, mAddress.getOrganization(), mProblems); - verifyField(script, v, RECIPIENT, mAddress.getRecipient(), mProblems); + // remaining calls don't change the field verifier + verifyField(script, v, POSTAL_CODE, address.getPostalCode(), problems); + verifyField(script, v, STREET_ADDRESS, street, problems); + verifyField(script, v, SORTING_CODE, address.getSortingCode(), problems); + verifyField(script, v, ORGANIZATION, address.getOrganization(), problems); + verifyField(script, v, RECIPIENT, address.getRecipient(), problems); - postVerify(v, mAddress, mProblems); + postVerify(v, address, problems); - mListener.dataLoadingEnd(); - } + listener.dataLoadingEnd(); } - - /** - * Hook to perform any final processing using the final verifier. Default does no additional - * verification. - */ - protected void postVerify(FieldVerifier verifier, AddressData address, - AddressProblems problems) { + } + + /** + * Hook to perform any final processing using the final verifier. Default does no additional + * verification. + */ + protected void postVerify(FieldVerifier verifier, AddressData address, + AddressProblems problems) { + } + + /** + * Hook called by verify with each verifiable field, in order. Override to provide pre- or + * post-checks for all fields. + */ + protected boolean verifyField(LookupKey.ScriptType script, + FieldVerifier verifier, AddressField field, String value, + AddressProblems problems) { + Iterator iter = getProblemIterator(field); + while (iter.hasNext()) { + AddressProblemType prob = iter.next(); + if (!verifyProblemField(script, verifier, prob, field, value, problems)) { + return false; + } } - - /** - * Hook called by verify with each verifiable field, in order. Override to provide pre- or - * post-checks for all fields. - */ - protected boolean verifyField(LookupKey.ScriptType script, - FieldVerifier verifier, AddressField field, String value, - AddressProblems problems) { - Iterator iter = getProblemIterator(field); - while (iter.hasNext()) { - AddressProblemType prob = iter.next(); - if (!verifyProblemField(script, verifier, prob, field, value, problems)) { - return false; - } - } - return true; - } - - /** - * Hook for on-the-fly modification of the problem list. Override to change the problems to - * check for a particular field. Generally, changing the problemMap passed to the constructor - * is a better approach. - */ - protected Iterator getProblemIterator(AddressField field) { - List list = mProblemMap.get(field); - if (list == null) { - list = Collections.emptyList(); - } - return list.iterator(); + return true; + } + + /** + * Hook for on-the-fly modification of the problem list. Override to change the problems to + * check for a particular field. Generally, changing the problemMap passed to the constructor + * is a better approach. + */ + protected Iterator getProblemIterator(AddressField field) { + List list = problemMap.get(field); + if (list == null) { + list = Collections.emptyList(); } + return list.iterator(); + } + + /** + * Hook for adding special checks for particular problems and/or fields. + */ + protected boolean verifyProblemField(LookupKey.ScriptType script, + FieldVerifier verifier, AddressProblemType problem, AddressField field, + String datum, AddressProblems problems) { + return verifier.check(script, problem, field, datum, problems); + } + + /** + * This gets called with the hierarchical fields COUNTRY, ADMIN_AREA, LOCALITY, + * DEPENDENT_LOCALITY in order, returning the refined verifier at each step. + * + *

The default implementation is stateless, and delegates to the verifier to do the + * refinement. + */ + public static class VerifierRefiner { /** - * Hook for adding special checks for particular problems and/or fields. + * Refines the verifier. This delegates to the verifier to perform the refinement. */ - protected boolean verifyProblemField(LookupKey.ScriptType script, - FieldVerifier verifier, AddressProblemType problem, AddressField field, - String datum, AddressProblems problems) { - return verifier.check(script, problem, field, datum, problems); + public FieldVerifier refineVerifier(FieldVerifier v, AddressField field, + String subkey) { + return v.refineVerifier(subkey); } /** - * This gets called with the hierarchical fields COUNTRY, ADMIN_AREA, LOCALITY, - * DEPENDENT_LOCALITY in order, returning the refined verifier at each step. - * - *

The default implementation is stateless, and delegates to the verifier to do the - * refinement. + * Returns a clean version of the refiner. Since this implementation is stateless, returns + * this. */ - public static class VerifierRefiner { - - /** - * Refines the verifier. This delegates to the verifier to perform the refinement. - */ - public FieldVerifier refineVerifier(FieldVerifier v, AddressField field, - String subkey) { - return v.refineVerifier(subkey); - } - - /** - * Returns a clean version of the refiner. Since this implementation is stateless, returns - * this. - */ - public VerifierRefiner newInstance() { - return this; - } + public VerifierRefiner newInstance() { + return this; } + } - private static final VerifierRefiner DEFAULT_REFINER = new VerifierRefiner(); + private static final VerifierRefiner DEFAULT_REFINER = new VerifierRefiner(); } diff --git a/java/src/com/android/i18n/addressinput/StandardChecks.java b/java/src/com/android/i18n/addressinput/StandardChecks.java index f243afd..a76591e 100644 --- a/java/src/com/android/i18n/addressinput/StandardChecks.java +++ b/java/src/com/android/i18n/addressinput/StandardChecks.java @@ -27,41 +27,41 @@ import java.util.Map; */ public class StandardChecks { - private StandardChecks() { - } + private StandardChecks() { + } - public static final Map> PROBLEM_MAP; + public static final Map> PROBLEM_MAP; - static { - Map> map = - new HashMap>(); + static { + Map> map = + new HashMap>(); - addToMap(map, AddressField.COUNTRY, AddressProblemType.USING_UNUSED_FIELD, - AddressProblemType.MISSING_REQUIRED_FIELD, AddressProblemType.UNKNOWN_VALUE); - addToMap(map, AddressField.ADMIN_AREA, AddressProblemType.USING_UNUSED_FIELD, - AddressProblemType.MISSING_REQUIRED_FIELD, AddressProblemType.UNKNOWN_VALUE); - addToMap(map, AddressField.LOCALITY, AddressProblemType.USING_UNUSED_FIELD, - AddressProblemType.MISSING_REQUIRED_FIELD, AddressProblemType.UNKNOWN_VALUE); - addToMap(map, AddressField.DEPENDENT_LOCALITY, AddressProblemType.USING_UNUSED_FIELD, - AddressProblemType.MISSING_REQUIRED_FIELD, AddressProblemType.UNKNOWN_VALUE); - addToMap(map, AddressField.POSTAL_CODE, AddressProblemType.USING_UNUSED_FIELD, - AddressProblemType.MISSING_REQUIRED_FIELD, AddressProblemType.UNRECOGNIZED_FORMAT, - AddressProblemType.MISMATCHING_VALUE); - addToMap(map, AddressField.STREET_ADDRESS, AddressProblemType.USING_UNUSED_FIELD, - AddressProblemType.MISSING_REQUIRED_FIELD); - addToMap(map, AddressField.SORTING_CODE, AddressProblemType.USING_UNUSED_FIELD, - AddressProblemType.MISSING_REQUIRED_FIELD); - addToMap(map, AddressField.ORGANIZATION, AddressProblemType.USING_UNUSED_FIELD, - AddressProblemType.MISSING_REQUIRED_FIELD); - addToMap(map, AddressField.RECIPIENT, AddressProblemType.USING_UNUSED_FIELD, - AddressProblemType.MISSING_REQUIRED_FIELD); + addToMap(map, AddressField.COUNTRY, AddressProblemType.USING_UNUSED_FIELD, + AddressProblemType.MISSING_REQUIRED_FIELD, AddressProblemType.UNKNOWN_VALUE); + addToMap(map, AddressField.ADMIN_AREA, AddressProblemType.USING_UNUSED_FIELD, + AddressProblemType.MISSING_REQUIRED_FIELD, AddressProblemType.UNKNOWN_VALUE); + addToMap(map, AddressField.LOCALITY, AddressProblemType.USING_UNUSED_FIELD, + AddressProblemType.MISSING_REQUIRED_FIELD, AddressProblemType.UNKNOWN_VALUE); + addToMap(map, AddressField.DEPENDENT_LOCALITY, AddressProblemType.USING_UNUSED_FIELD, + AddressProblemType.MISSING_REQUIRED_FIELD, AddressProblemType.UNKNOWN_VALUE); + addToMap(map, AddressField.POSTAL_CODE, AddressProblemType.USING_UNUSED_FIELD, + AddressProblemType.MISSING_REQUIRED_FIELD, AddressProblemType.UNRECOGNIZED_FORMAT, + AddressProblemType.MISMATCHING_VALUE); + addToMap(map, AddressField.STREET_ADDRESS, AddressProblemType.USING_UNUSED_FIELD, + AddressProblemType.MISSING_REQUIRED_FIELD); + addToMap(map, AddressField.SORTING_CODE, AddressProblemType.USING_UNUSED_FIELD, + AddressProblemType.MISSING_REQUIRED_FIELD); + addToMap(map, AddressField.ORGANIZATION, AddressProblemType.USING_UNUSED_FIELD, + AddressProblemType.MISSING_REQUIRED_FIELD); + addToMap(map, AddressField.RECIPIENT, AddressProblemType.USING_UNUSED_FIELD, + AddressProblemType.MISSING_REQUIRED_FIELD); - PROBLEM_MAP = Collections.unmodifiableMap(map); - } + PROBLEM_MAP = Collections.unmodifiableMap(map); + } - private static void addToMap(Map> map, - AddressField field, - AddressProblemType... problems) { - map.put(field, Collections.unmodifiableList(Arrays.asList(problems))); - } + private static void addToMap(Map> map, + AddressField field, + AddressProblemType... problems) { + map.put(field, Collections.unmodifiableList(Arrays.asList(problems))); + } } diff --git a/java/src/com/android/i18n/addressinput/Util.java b/java/src/com/android/i18n/addressinput/Util.java index 0547543..f883c3b 100644 --- a/java/src/com/android/i18n/addressinput/Util.java +++ b/java/src/com/android/i18n/addressinput/Util.java @@ -26,201 +26,201 @@ import java.util.regex.Pattern; * Utility functions used by the address widget. */ class Util { - /** - * This variable is in upper-case, since we convert the language code to upper case before doing - * string comparison. - */ - private static final String LATIN_SCRIPT = "LATN"; + /** + * This variable is in upper-case, since we convert the language code to upper case before doing + * string comparison. + */ + private static final String LATIN_SCRIPT = "LATN"; - /** - * Map of countries that have non-latin local names, with the language that their local names - * are in. We only list a country here if we have the appropriate data. Only language sub-tags - * are listed. - */ - private static final Map nonLatinLocalLanguageCountries = - new HashMap(); - static { - nonLatinLocalLanguageCountries.put("AM", "hy"); - nonLatinLocalLanguageCountries.put("CN", "zh"); - nonLatinLocalLanguageCountries.put("HK", "zh"); - nonLatinLocalLanguageCountries.put("JP", "ja"); - nonLatinLocalLanguageCountries.put("KP", "ko"); - nonLatinLocalLanguageCountries.put("KR", "ko"); - nonLatinLocalLanguageCountries.put("MO", "zh"); - nonLatinLocalLanguageCountries.put("TH", "th"); - nonLatinLocalLanguageCountries.put("TW", "zh"); - nonLatinLocalLanguageCountries.put("VN", "vi"); - } + /** + * Map of countries that have non-latin local names, with the language that their local names + * are in. We only list a country here if we have the appropriate data. Only language sub-tags + * are listed. + */ + private static final Map nonLatinLocalLanguageCountries = + new HashMap(); + static { + nonLatinLocalLanguageCountries.put("AM", "hy"); + nonLatinLocalLanguageCountries.put("CN", "zh"); + nonLatinLocalLanguageCountries.put("HK", "zh"); + nonLatinLocalLanguageCountries.put("JP", "ja"); + nonLatinLocalLanguageCountries.put("KP", "ko"); + nonLatinLocalLanguageCountries.put("KR", "ko"); + nonLatinLocalLanguageCountries.put("MO", "zh"); + nonLatinLocalLanguageCountries.put("TH", "th"); + nonLatinLocalLanguageCountries.put("TW", "zh"); + nonLatinLocalLanguageCountries.put("VN", "vi"); + } - /** - * Cannot instantiate this class - private constructor. - */ - private Util() { - } + /** + * Cannot instantiate this class - private constructor. + */ + private Util() { + } - /** - * Returns true if the language code is explicitly marked to be in the latin script. For - * example, "zh-Latn" would return true, but "zh-TW", "en" and "zh" would all return false. - */ - static boolean isExplicitLatinScript(String languageCode) { - // Convert to upper-case for easier comparison. - languageCode = languageCode.toUpperCase(); - // Check to see if the language code contains a script modifier. - final Pattern languageCodePattern = Pattern.compile("\\w{2,3}[-_](\\w{4})"); - Matcher m = languageCodePattern.matcher(languageCode); - if (m.lookingAt()) { - String script = m.group(1); - if (script.equals(LATIN_SCRIPT)) { - return true; - } - } - return false; + /** + * Returns true if the language code is explicitly marked to be in the latin script. For + * example, "zh-Latn" would return true, but "zh-TW", "en" and "zh" would all return false. + */ + static boolean isExplicitLatinScript(String languageCode) { + // Convert to upper-case for easier comparison. + languageCode = languageCode.toUpperCase(); + // Check to see if the language code contains a script modifier. + final Pattern languageCodePattern = Pattern.compile("\\w{2,3}[-_](\\w{4})"); + Matcher m = languageCodePattern.matcher(languageCode); + if (m.lookingAt()) { + String script = m.group(1); + if (script.equals(LATIN_SCRIPT)) { + return true; + } } + return false; + } - /** - * Returns the language subtag of a language code. For example, returns "zh" if given "zh-Hans", - * "zh-CN" or other "zh" variants. If no language subtag can be found or the language tag is - * malformed, returns "und". - */ - static String getLanguageSubtag(String languageCode) { - final Pattern languageCodePattern = Pattern - .compile("(\\w{2,3})(?:[-_]\\w{4})?(?:[-_]\\w{2})?"); - Matcher m = languageCodePattern.matcher(languageCode); - if (m.matches()) { - return m.group(1).toLowerCase(); - } - return "und"; + /** + * Returns the language subtag of a language code. For example, returns "zh" if given "zh-Hans", + * "zh-CN" or other "zh" variants. If no language subtag can be found or the language tag is + * malformed, returns "und". + */ + static String getLanguageSubtag(String languageCode) { + final Pattern languageCodePattern = Pattern + .compile("(\\w{2,3})(?:[-_]\\w{4})?(?:[-_]\\w{2})?"); + Matcher m = languageCodePattern.matcher(languageCode); + if (m.matches()) { + return m.group(1).toLowerCase(); } + return "und"; + } - /** - * Trims the string. If the field is empty after trimming, returns null instead. Note that this - * only trims ASCII white-space. - */ - static String trimToNull(String originalStr) { - if (originalStr == null) { - return null; - } - String trimmedString = originalStr.trim(); - return (trimmedString.length() == 0) ? null : trimmedString; + /** + * Trims the string. If the field is empty after trimming, returns null instead. Note that this + * only trims ASCII white-space. + */ + static String trimToNull(String originalStr) { + if (originalStr == null) { + return null; } + String trimmedString = originalStr.trim(); + return (trimmedString.length() == 0) ? null : trimmedString; + } - /** - * Throws an exception if the object is null, with a generic error message. - */ - static void checkNotNull(Object o) throws NullPointerException { - checkNotNull(o, "This object should not be null."); - } + /** + * Throws an exception if the object is null, with a generic error message. + */ + static void checkNotNull(Object o) throws NullPointerException { + checkNotNull(o, "This object should not be null."); + } - /** - * Throws an exception if the object is null, with the error message supplied. - */ - static void checkNotNull(Object o, String message) throws NullPointerException { - if (o == null) { - throw new NullPointerException(message); - } + /** + * Throws an exception if the object is null, with the error message supplied. + */ + static void checkNotNull(Object o, String message) throws NullPointerException { + if (o == null) { + throw new NullPointerException(message); } + } - /** - * Joins input string with the given separator. If an input string is null, it will be skipped. - */ - static String joinAndSkipNulls(String separator, String... strings) { - StringBuilder sb = null; - for (String s : strings) { - if (s != null) { - s = s.trim(); - if (s.length() > 0) { - if (sb == null) { - sb = new StringBuilder(s); - } else { - sb.append(separator).append(s); - } - } - } + /** + * Joins input string with the given separator. If an input string is null, it will be skipped. + */ + static String joinAndSkipNulls(String separator, String... strings) { + StringBuilder sb = null; + for (String s : strings) { + if (s != null) { + s = s.trim(); + if (s.length() > 0) { + if (sb == null) { + sb = new StringBuilder(s); + } else { + sb.append(separator).append(s); + } } - return sb == null ? null : sb.toString(); + } } + return sb == null ? null : sb.toString(); + } - /** - * Builds a map of the lower-cased values of the keys, names and local names provided. Each name - * and local name is mapped to its respective key in the map. - * - * @throws IllegalStateException if the names or lnames array is greater than the keys array. - */ - static Map buildNameToKeyMap(String[] keys, String[] names, String[] lnames) { - if (keys == null) { - return null; - } + /** + * Builds a map of the lower-cased values of the keys, names and local names provided. Each name + * and local name is mapped to its respective key in the map. + * + * @throws IllegalStateException if the names or lnames array is greater than the keys array. + */ + static Map buildNameToKeyMap(String[] keys, String[] names, String[] lnames) { + if (keys == null) { + return null; + } - Map nameToKeyMap = new HashMap(); + Map nameToKeyMap = new HashMap(); - int keyLength = keys.length; - for (String k : keys) { - nameToKeyMap.put(k.toLowerCase(), k); - } - if (names != null) { - if (names.length > keyLength) { - throw new IllegalStateException( - "names length (" + names.length + ") is greater than keys length (" + - keys.length + ")"); - } - for (int i = 0; i < keyLength; i++) { - // If we have less names than keys, we ignore all missing names. This happens - // generally because reg-ex splitting methods on different platforms (java, js etc) - // behave differently in the default case. Since missing names are fine, we opt to - // be more robust here. - if (i < names.length && names[i].length() > 0) { - nameToKeyMap.put(names[i].toLowerCase(), keys[i]); - } - } + int keyLength = keys.length; + for (String k : keys) { + nameToKeyMap.put(k.toLowerCase(), k); + } + if (names != null) { + if (names.length > keyLength) { + throw new IllegalStateException( + "names length (" + names.length + ") is greater than keys length (" + + keys.length + ")"); + } + for (int i = 0; i < keyLength; i++) { + // If we have less names than keys, we ignore all missing names. This happens + // generally because reg-ex splitting methods on different platforms (java, js etc) + // behave differently in the default case. Since missing names are fine, we opt to + // be more robust here. + if (i < names.length && names[i].length() > 0) { + nameToKeyMap.put(names[i].toLowerCase(), keys[i]); } - if (lnames != null) { - if (lnames.length > keyLength) { - throw new IllegalStateException( - "lnames length (" + lnames.length + ") is greater than keys length (" + - keys.length + ")"); - } - for (int i = 0; i < keyLength; i++) { - if (i < lnames.length && lnames[i].length() > 0) { - nameToKeyMap.put(lnames[i].toLowerCase(), keys[i]); - } - } + } + } + if (lnames != null) { + if (lnames.length > keyLength) { + throw new IllegalStateException( + "lnames length (" + lnames.length + ") is greater than keys length (" + + keys.length + ")"); + } + for (int i = 0; i < keyLength; i++) { + if (i < lnames.length && lnames[i].length() > 0) { + nameToKeyMap.put(lnames[i].toLowerCase(), keys[i]); } - return nameToKeyMap; + } } + return nameToKeyMap; + } - /** - * Returns a language code that the widget can use when fetching data, based on a {@link - * java.util.Locale} language and the current selected country in the address widget. This - * method is necessary since we have to determine later whether a language is "local" or "latin" - * for certain countries. - * - * @param language the current user language - * @param currentCountry the current selected country - * @return a language code string in BCP-47 format (e.g. "en", "zh-Latn", "zh-Hans" or - * "en-US"). - */ - static String getWidgetCompatibleLanguageCode(Locale language, String currentCountry) { - String country = currentCountry.toUpperCase(); - // Only do something if the country is one of those where we have names in the local - // language as well as in latin script. - if (nonLatinLocalLanguageCountries.containsKey(country)) { - String languageTag = language.getLanguage(); - // Only do something if the language tag is _not_ the local language. - if (!languageTag.equals(nonLatinLocalLanguageCountries.get(country))) { - // Build up the language tag with the country and language specified, and add in the - // script-tag of "Latn" explicitly, since this is _not_ a local language. This means - // that we might create a language tag of "th-Latn", which is not what the actual - // language being used is, but it indicates that we prefer "Latn" names to whatever - // the local alternative was. - StringBuilder languageTagBuilder = new StringBuilder(languageTag); - languageTagBuilder.append("_latn"); - if (language.getCountry().length() > 0) { - languageTagBuilder.append("_"); - languageTagBuilder.append(language.getCountry()); - } - return languageTagBuilder.toString(); - } + /** + * Returns a language code that the widget can use when fetching data, based on a {@link + * java.util.Locale} language and the current selected country in the address widget. This + * method is necessary since we have to determine later whether a language is "local" or "latin" + * for certain countries. + * + * @param language the current user language + * @param currentCountry the current selected country + * @return a language code string in BCP-47 format (e.g. "en", "zh-Latn", "zh-Hans" or + * "en-US"). + */ + static String getWidgetCompatibleLanguageCode(Locale language, String currentCountry) { + String country = currentCountry.toUpperCase(); + // Only do something if the country is one of those where we have names in the local + // language as well as in latin script. + if (nonLatinLocalLanguageCountries.containsKey(country)) { + String languageTag = language.getLanguage(); + // Only do something if the language tag is _not_ the local language. + if (!languageTag.equals(nonLatinLocalLanguageCountries.get(country))) { + // Build up the language tag with the country and language specified, and add in the + // script-tag of "Latn" explicitly, since this is _not_ a local language. This means + // that we might create a language tag of "th-Latn", which is not what the actual + // language being used is, but it indicates that we prefer "Latn" names to whatever + // the local alternative was. + StringBuilder languageTagBuilder = new StringBuilder(languageTag); + languageTagBuilder.append("_latn"); + if (language.getCountry().length() > 0) { + languageTagBuilder.append("_"); + languageTagBuilder.append(language.getCountry()); } - return language.toString(); + return languageTagBuilder.toString(); + } } + return language.toString(); + } } diff --git a/java/src/com/android/i18n/addressinput/testing/AddressDataMapLoader.java b/java/src/com/android/i18n/addressinput/testing/AddressDataMapLoader.java index 3310ea4..072356d 100644 --- a/java/src/com/android/i18n/addressinput/testing/AddressDataMapLoader.java +++ b/java/src/com/android/i18n/addressinput/testing/AddressDataMapLoader.java @@ -27,30 +27,30 @@ import java.util.Map; */ public class AddressDataMapLoader { - private static final String DATA_PATH = "/countryinfo.txt"; + private static final String DATA_PATH = "/countryinfo.txt"; - private AddressDataMapLoader() { - } + private AddressDataMapLoader() { + } - public static final Map DATA; + public static final Map DATA; - static { - DATA = new HashMap(); - try { - BufferedReader br = new BufferedReader( - new InputStreamReader(AddressDataMapLoader.class.getResourceAsStream(DATA_PATH), - "utf-8")); - String line = null; - while (null != (line = br.readLine())) { - line = line.trim(); - if (line.length() == 0 || line.charAt(0) == '#') { - continue; - } - int x = line.indexOf('='); - DATA.put(line.substring(0, x), line.substring(x + 1)); - } - } catch (IOException e) { - System.err.println("unable to create map: " + e.getMessage()); + static { + DATA = new HashMap(); + try { + BufferedReader br = new BufferedReader( + new InputStreamReader(AddressDataMapLoader.class.getResourceAsStream(DATA_PATH), + "utf-8")); + String line = null; + while (null != (line = br.readLine())) { + line = line.trim(); + if (line.length() == 0 || line.charAt(0) == '#') { + continue; } + int x = line.indexOf('='); + DATA.put(line.substring(0, x), line.substring(x + 1)); + } + } catch (IOException e) { + System.err.println("unable to create map: " + e.getMessage()); } + } } diff --git a/java/src/com/android/i18n/addressinput/testing/AsyncTestCase.java b/java/src/com/android/i18n/addressinput/testing/AsyncTestCase.java index 69c3020..d8a5a43 100644 --- a/java/src/com/android/i18n/addressinput/testing/AsyncTestCase.java +++ b/java/src/com/android/i18n/addressinput/testing/AsyncTestCase.java @@ -25,51 +25,51 @@ import java.util.concurrent.TimeoutException; * like the corresponding methods in GWTTestCase for testing asynchronous code. */ public abstract class AsyncTestCase extends TestCase { - /** - * Tracks whether this test is completely done. - */ - private boolean mTestIsFinished; + /** + * Tracks whether this test is completely done. + */ + private boolean testIsFinished; - /** - * The system time in milliseconds when the test should time out. - */ - private long mTestTimeoutMillis; + /** + * The system time in milliseconds when the test should time out. + */ + private long testTimeoutMillis; - /** - * Puts the current test in asynchronous mode. - * - * @param timeoutMillis time to wait before failing the test for timing out - */ - protected void delayTestFinish(int timeoutMillis) { - mTestTimeoutMillis = System.currentTimeMillis() + timeoutMillis; - } + /** + * Puts the current test in asynchronous mode. + * + * @param timeoutMillis time to wait before failing the test for timing out + */ + protected void delayTestFinish(int timeoutMillis) { + testTimeoutMillis = System.currentTimeMillis() + timeoutMillis; + } - /** - * Causes this test to succeed during asynchronous mode. - */ - protected void finishTest() { - mTestIsFinished = true; - synchronized (this) { - notify(); - } + /** + * Causes this test to succeed during asynchronous mode. + */ + protected void finishTest() { + testIsFinished = true; + synchronized (this) { + notify(); } + } - @Override - protected void runTest() throws Throwable { - mTestIsFinished = false; - mTestTimeoutMillis = 0; - super.runTest(); + @Override + protected void runTest() throws Throwable { + testIsFinished = false; + testTimeoutMillis = 0; + super.runTest(); - if (mTestTimeoutMillis > 0) { - long timeoutMillis = mTestTimeoutMillis - System.currentTimeMillis(); - if (timeoutMillis > 0) { - synchronized (this) { - wait(timeoutMillis); - } - } - if (!mTestIsFinished) { - throw new TimeoutException("Waited " + timeoutMillis + " ms!"); - } + if (testTimeoutMillis > 0) { + long timeoutMillis = testTimeoutMillis - System.currentTimeMillis(); + if (timeoutMillis > 0) { + synchronized (this) { + wait(timeoutMillis); } + } + if (!testIsFinished) { + throw new TimeoutException("Waited " + timeoutMillis + " ms!"); + } } + } } diff --git a/java/test/com/android/i18n/addressinput/AddressDataTest.java b/java/test/com/android/i18n/addressinput/AddressDataTest.java index 7b211b4..870b318 100644 --- a/java/test/com/android/i18n/addressinput/AddressDataTest.java +++ b/java/test/com/android/i18n/addressinput/AddressDataTest.java @@ -22,45 +22,45 @@ import junit.framework.TestCase; * Tests for the AddressData class. */ public class AddressDataTest extends TestCase { - private static final String ADDRESS_LINE = "First address line"; + private static final String ADDRESS_LINE = "First address line"; - public void testSetAddressLine() { - AddressData.Builder builder = new AddressData.Builder(); - builder = builder.setAddress("\n " + ADDRESS_LINE); - AddressData ad = builder.build(); - assertEquals(ADDRESS_LINE, ad.getAddressLine1()); - assertEquals(null, ad.getAddressLine2()); - } + public void testSetAddressLine() { + AddressData.Builder builder = new AddressData.Builder(); + builder = builder.setAddress("\n " + ADDRESS_LINE); + AddressData ad = builder.build(); + assertEquals(ADDRESS_LINE, ad.getAddressLine1()); + assertEquals(null, ad.getAddressLine2()); + } - public void testAddressLineNormalisation() { - AddressData address = new AddressData.Builder().setAddressLine1(null) - .setAddressLine2(ADDRESS_LINE).build(); - AddressData copiedAddress = new AddressData.Builder(address).build(); - assertEquals(ADDRESS_LINE, copiedAddress.getAddressLine1()); - assertEquals(null, copiedAddress.getAddressLine2()); - } + public void testAddressLineNormalisation() { + AddressData address = new AddressData.Builder().setAddressLine1(null) + .setAddressLine2(ADDRESS_LINE).build(); + AddressData copiedAddress = new AddressData.Builder(address).build(); + assertEquals(ADDRESS_LINE, copiedAddress.getAddressLine1()); + assertEquals(null, copiedAddress.getAddressLine2()); + } - public void testAddressLineNormalisationWithNewLineCharacters() { - AddressData address = - new AddressData.Builder().setAddressLine1(ADDRESS_LINE + "\n" + ADDRESS_LINE).build(); - AddressData copiedAddress = new AddressData.Builder(address).build(); - assertEquals(ADDRESS_LINE, copiedAddress.getAddressLine1()); - assertEquals(ADDRESS_LINE, copiedAddress.getAddressLine2()); - } + public void testAddressLineNormalisationWithNewLineCharacters() { + AddressData address = + new AddressData.Builder().setAddressLine1(ADDRESS_LINE + "\n" + ADDRESS_LINE).build(); + AddressData copiedAddress = new AddressData.Builder(address).build(); + assertEquals(ADDRESS_LINE, copiedAddress.getAddressLine1()); + assertEquals(ADDRESS_LINE, copiedAddress.getAddressLine2()); + } - public void testNoAdminArea() { - AddressData address = new AddressData.Builder().build(); - assertEquals(null, address.getAdministrativeArea()); - } + public void testNoAdminArea() { + AddressData address = new AddressData.Builder().build(); + assertEquals(null, address.getAdministrativeArea()); + } - public void testSetLanguageCode() throws Exception { - AddressData address = new AddressData.Builder().setCountry("TW") - // Taipei City - .setAdminArea("\u53F0\u5317\u5E02") - // Da-an District - .setLocality("\u5927\u5B89\u5340") - .build(); - address = new AddressData.Builder(address).setLanguageCode("zh-latn").build(); - assertEquals("zh-latn", address.getLanguageCode()); - } + public void testSetLanguageCode() throws Exception { + AddressData address = new AddressData.Builder().setCountry("TW") + // Taipei City + .setAdminArea("\u53F0\u5317\u5E02") + // Da-an District + .setLocality("\u5927\u5B89\u5340") + .build(); + address = new AddressData.Builder(address).setLanguageCode("zh-latn").build(); + assertEquals("zh-latn", address.getLanguageCode()); + } } diff --git a/java/test/com/android/i18n/addressinput/AddressFieldTest.java b/java/test/com/android/i18n/addressinput/AddressFieldTest.java index aa0a741..8009bd5 100644 --- a/java/test/com/android/i18n/addressinput/AddressFieldTest.java +++ b/java/test/com/android/i18n/addressinput/AddressFieldTest.java @@ -23,11 +23,11 @@ import junit.framework.TestCase; */ public class AddressFieldTest extends TestCase { - public void testOf() throws Exception { - assertEquals(AddressField.COUNTRY, AddressField.of('R')); - } + public void testOf() throws Exception { + assertEquals(AddressField.COUNTRY, AddressField.of('R')); + } - public void testGetChar() throws Exception { - assertEquals('R', AddressField.COUNTRY.getChar()); - } + public void testGetChar() throws Exception { + assertEquals('R', AddressField.COUNTRY.getChar()); + } } diff --git a/java/test/com/android/i18n/addressinput/AddressProblemsTest.java b/java/test/com/android/i18n/addressinput/AddressProblemsTest.java index 14cef05..8f6740b 100644 --- a/java/test/com/android/i18n/addressinput/AddressProblemsTest.java +++ b/java/test/com/android/i18n/addressinput/AddressProblemsTest.java @@ -22,16 +22,16 @@ import junit.framework.TestCase; * Tests for the AddressProblems class. */ public class AddressProblemsTest extends TestCase { - public void testAddError() { - AddressProblems ap = new AddressProblems(); - ap.add(AddressField.POSTAL_CODE, AddressProblemType.MISSING_REQUIRED_FIELD); - assertEquals(AddressProblemType.MISSING_REQUIRED_FIELD, - ap.getProblem(AddressField.POSTAL_CODE)); - } + public void testAddError() { + AddressProblems ap = new AddressProblems(); + ap.add(AddressField.POSTAL_CODE, AddressProblemType.MISSING_REQUIRED_FIELD); + assertEquals(AddressProblemType.MISSING_REQUIRED_FIELD, + ap.getProblem(AddressField.POSTAL_CODE)); + } - public void testEmptyErrorList() { - AddressProblems ap = new AddressProblems(); - assertNull(ap.getProblem(AddressField.POSTAL_CODE)); - assertTrue(ap.isEmpty()); - } + public void testEmptyErrorList() { + AddressProblems ap = new AddressProblems(); + assertNull(ap.getProblem(AddressField.POSTAL_CODE)); + assertTrue(ap.isEmpty()); + } } diff --git a/java/test/com/android/i18n/addressinput/AddressVerificationDataTest.java b/java/test/com/android/i18n/addressinput/AddressVerificationDataTest.java index b57955a..40521ab 100644 --- a/java/test/com/android/i18n/addressinput/AddressVerificationDataTest.java +++ b/java/test/com/android/i18n/addressinput/AddressVerificationDataTest.java @@ -25,80 +25,80 @@ import junit.framework.TestCase; */ public class AddressVerificationDataTest extends TestCase { - private static final AddressVerificationData ADDRESS_DATA = - new AddressVerificationData(AddressDataMapLoader.DATA); - - public void testParseAllData() { - for (String key : ADDRESS_DATA.keys()) { - AddressVerificationNodeData nodeData = ADDRESS_DATA.get(key); - assertNotNull(key + " maps to null value.", nodeData); - assertNotNull("Id is required", nodeData.get(AddressDataKey.ID)); - } - } - - public void testLoadingCountries() { - AddressVerificationNodeData nodeData = ADDRESS_DATA.get("data"); - String[] countries = nodeData.get(AddressDataKey.COUNTRIES).split("~"); - assertTrue(countries.length > 0); - } - - public void testUsData() { - AddressVerificationNodeData nodeData = ADDRESS_DATA.get("data/US"); - assertEquals("data/US", nodeData.get(AddressDataKey.ID)); - assertNotNull(nodeData.get(AddressDataKey.SUB_KEYS)); - assertNotNull(nodeData.get(AddressDataKey.SUB_NAMES)); - assertEquals("en", nodeData.get(AddressDataKey.LANG)); + private static final AddressVerificationData ADDRESS_DATA = + new AddressVerificationData(AddressDataMapLoader.DATA); + + public void testParseAllData() { + for (String key : ADDRESS_DATA.keys()) { + AddressVerificationNodeData nodeData = ADDRESS_DATA.get(key); + assertNotNull(key + " maps to null value.", nodeData); + assertNotNull("Id is required", nodeData.get(AddressDataKey.ID)); } - - public void testCaData() { - AddressVerificationNodeData nodeData = ADDRESS_DATA.get("data/CA"); - String names = nodeData.get(AddressDataKey.SUB_NAMES); - String keys = nodeData.get(AddressDataKey.SUB_KEYS); - - assertEquals("data/CA", nodeData.get(AddressDataKey.ID)); - assertEquals("en", nodeData.get(AddressDataKey.LANG)); - - assertEquals("AB~BC~MB~NB~NL~NT~NS~NU~ON~PE~QC~SK~YT", keys); - assertEquals("Alberta~British Columbia~Manitoba~New Brunswick" + - "~Newfoundland and Labrador~Northwest Territories~Nova Scotia~Nunavut" + - "~Ontario~Prince Edward Island~Quebec~Saskatchewan~Yukon", - names); - } - - public void testCaFrenchData() { - AddressVerificationNodeData nodeData = ADDRESS_DATA.get("data/CA--fr"); - String names = nodeData.get(AddressDataKey.SUB_NAMES); - String keys = nodeData.get(AddressDataKey.SUB_KEYS); - - assertEquals("data/CA--fr", nodeData.get(AddressDataKey.ID)); - assertEquals("fr", nodeData.get(AddressDataKey.LANG)); - assertEquals("AB~BC~PE~MB~NB~NS~NU~ON~QC~SK~NL~NT~YT", keys); - assertTrue(names.contains("Colombie")); - } - - public void testBackSlashUnEscaped() { - for (String lookupKey : ADDRESS_DATA.keys()) { - AddressVerificationNodeData nodeData = ADDRESS_DATA.get(lookupKey); - for (AddressDataKey dataKey : AddressDataKey.values()) { - String val = nodeData.get(dataKey); - if (val != null) { - assertFalse("Backslashes need to be unescaped: " + val, val.contains("\\\\")); - } - } + } + + public void testLoadingCountries() { + AddressVerificationNodeData nodeData = ADDRESS_DATA.get("data"); + String[] countries = nodeData.get(AddressDataKey.COUNTRIES).split("~"); + assertTrue(countries.length > 0); + } + + public void testUsData() { + AddressVerificationNodeData nodeData = ADDRESS_DATA.get("data/US"); + assertEquals("data/US", nodeData.get(AddressDataKey.ID)); + assertNotNull(nodeData.get(AddressDataKey.SUB_KEYS)); + assertNotNull(nodeData.get(AddressDataKey.SUB_NAMES)); + assertEquals("en", nodeData.get(AddressDataKey.LANG)); + } + + public void testCaData() { + AddressVerificationNodeData nodeData = ADDRESS_DATA.get("data/CA"); + String names = nodeData.get(AddressDataKey.SUB_NAMES); + String keys = nodeData.get(AddressDataKey.SUB_KEYS); + + assertEquals("data/CA", nodeData.get(AddressDataKey.ID)); + assertEquals("en", nodeData.get(AddressDataKey.LANG)); + + assertEquals("AB~BC~MB~NB~NL~NT~NS~NU~ON~PE~QC~SK~YT", keys); + assertEquals("Alberta~British Columbia~Manitoba~New Brunswick" + + "~Newfoundland and Labrador~Northwest Territories~Nova Scotia~Nunavut" + + "~Ontario~Prince Edward Island~Quebec~Saskatchewan~Yukon", + names); + } + + public void testCaFrenchData() { + AddressVerificationNodeData nodeData = ADDRESS_DATA.get("data/CA--fr"); + String names = nodeData.get(AddressDataKey.SUB_NAMES); + String keys = nodeData.get(AddressDataKey.SUB_KEYS); + + assertEquals("data/CA--fr", nodeData.get(AddressDataKey.ID)); + assertEquals("fr", nodeData.get(AddressDataKey.LANG)); + assertEquals("AB~BC~PE~MB~NB~NS~NU~ON~QC~SK~NL~NT~YT", keys); + assertTrue(names.contains("Colombie")); + } + + public void testBackSlashUnEscaped() { + for (String lookupKey : ADDRESS_DATA.keys()) { + AddressVerificationNodeData nodeData = ADDRESS_DATA.get(lookupKey); + for (AddressDataKey dataKey : AddressDataKey.values()) { + String val = nodeData.get(dataKey); + if (val != null) { + assertFalse("Backslashes need to be unescaped: " + val, val.contains("\\\\")); } - - // Spot check. - assertEquals("Kazhakstan's postal code pattern mismatched", "\\d{6}", - ADDRESS_DATA.get("data/KZ").get(AddressDataKey.ZIP)); + } } - public void testExampleData() { - assertNotNull("Expects example data.", AddressDataMapLoader.DATA.get("examples")); - assertNotNull("Expects example US address.", - AddressDataMapLoader.DATA.get("examples/US/local/en")); - assertEquals("'examples/TW/local/zh_Hant' and 'examples/TW/local/_default' should " + - "return same value.", - AddressDataMapLoader.DATA.get("examples/TW/local/zh_Hant"), - AddressDataMapLoader.DATA.get("examples/TW/local/_default")); - } + // Spot check. + assertEquals("Kazhakstan's postal code pattern mismatched", "\\d{6}", + ADDRESS_DATA.get("data/KZ").get(AddressDataKey.ZIP)); + } + + public void testExampleData() { + assertNotNull("Expects example data.", AddressDataMapLoader.DATA.get("examples")); + assertNotNull("Expects example US address.", + AddressDataMapLoader.DATA.get("examples/US/local/en")); + assertEquals("'examples/TW/local/zh_Hant' and 'examples/TW/local/_default' should " + + "return same value.", + AddressDataMapLoader.DATA.get("examples/TW/local/zh_Hant"), + AddressDataMapLoader.DATA.get("examples/TW/local/_default")); + } } diff --git a/java/test/com/android/i18n/addressinput/AddressWidgetUiComponentProviderTest.java b/java/test/com/android/i18n/addressinput/AddressWidgetUiComponentProviderTest.java index aa07aa3..d519728 100644 --- a/java/test/com/android/i18n/addressinput/AddressWidgetUiComponentProviderTest.java +++ b/java/test/com/android/i18n/addressinput/AddressWidgetUiComponentProviderTest.java @@ -35,119 +35,117 @@ import junit.framework.Assert; * Test class for {@link AddressWidgetUiComponentProvider}. */ public class AddressWidgetUiComponentProviderTest - extends ActivityInstrumentationTestCase2 { - private AddressWidget widget; - private AddressWidgetUiComponentProvider componentProvider; - private LinearLayout container; - private AddressData address; - private Context context; - private int customTextViewCounter; - private int customProgressDialogCounter; - - public AddressWidgetUiComponentProviderTest() { - super(TestActivity.class); + extends ActivityInstrumentationTestCase2 { + private AddressWidget widget; + private AddressWidgetUiComponentProvider componentProvider; + private LinearLayout container; + private AddressData address; + private Context context; + private int customTextViewCounter; + private int customProgressDialogCounter; + + public AddressWidgetUiComponentProviderTest() { + super(TestActivity.class); + } + + @Override + protected void setUp() throws Exception { + super.setUp(); + AddressData.Builder builder = new AddressData.Builder() + .setCountry("US") + .setLanguageCode("en") + .setAddressLine1("1098 Alta Ave") + .setAdminArea("CA"); + address = builder.build(); + context = getActivity(); + container = new LinearLayout(context); + } + + public void testCustomWidgets() { + customTextViewCounter = 0; + customProgressDialogCounter = 0; + componentProvider = new TestComponentProvider(context); + widget = new AddressWidget(context, container, new FormOptions.Builder().build(), + new SimpleClientCacheManager(), componentProvider); + widget.renderFormWithSavedAddress(address); + + for (AddressField field : AddressField.values()) { + if (field.equals(AddressField.COUNTRY)) { + continue; + } + + View view = widget.getViewForField(field); + if (view instanceof EditText) { + assertTrue("Field " + field + " does not use customized edit text widget.", + view instanceof CustomEditText); + } else if (view instanceof Spinner) { + assertTrue("Field " + field + " does not use customized spinner widget.", + view instanceof CustomSpinner); + assertTrue("Field " + field + " does not use customized ArrayAdapter.", + ((Spinner) view).getAdapter() instanceof CustomArrayAdapter); + } } - @Override - protected void setUp() throws Exception { - super.setUp(); - AddressData.Builder builder = new AddressData.Builder() - .setCountry("US") - .setLanguageCode("en") - .setAddressLine1("1098 Alta Ave") - .setAdminArea("CA"); - address = builder.build(); - context = getActivity(); - container = new LinearLayout(context); + assertTrue("Custom TextView label not used.", customTextViewCounter > 0); + assertTrue("Custom ProgressDialog not used.", customProgressDialogCounter > 0); + } + + private void increaseTextViewCounter() { + customTextViewCounter++; + } + + private void increaseProgressDialogCounter() { + customProgressDialogCounter++; + } + + private class CustomEditText extends EditText { + CustomEditText(Context context) { + super(context); } + } - public void testCustomWidgets() { - customTextViewCounter = 0; - customProgressDialogCounter = 0; - componentProvider = new TestComponentProvider(context); - widget = new AddressWidget(context, container, new FormOptions.Builder().build(), - new SimpleClientCacheManager(), componentProvider); - widget.renderFormWithSavedAddress(address); - - for (AddressField field : AddressField.values()) { - if (field.equals(AddressField.COUNTRY)) { - continue; - } - - View view = widget.getViewForField(field); - if (view instanceof EditText) { - assertTrue("Field " + field + " does not use customized edit text widget.", - view instanceof CustomEditText); - } else if (view instanceof Spinner) { - assertTrue("Field " + field + " does not use customized spinner widget.", - view instanceof CustomSpinner); - assertTrue("Field " + field + " does not use customized ArrayAdapter.", - ((Spinner) view).getAdapter() instanceof CustomArrayAdapter); - } - } - - assertTrue("Custom TextView label not used.", customTextViewCounter > 0); - assertTrue("Custom ProgressDialog not used.", customProgressDialogCounter > 0); + private class CustomSpinner extends Spinner { + CustomSpinner(Context context) { + super(context); } + } - private void increaseTextViewCounter() { - customTextViewCounter++; + private class CustomArrayAdapter extends ArrayAdapter { + CustomArrayAdapter(Context context, int id) { + super(context, id); } + } - private void increaseProgressDialogCounter() { - customProgressDialogCounter++; + private class TestComponentProvider extends AddressWidgetUiComponentProvider { + TestComponentProvider(Context context) { + super(context); } - private class CustomEditText extends EditText { - CustomEditText(Context context) { - super(context); - } + protected TextView createUiLabel(CharSequence label, AddressField.WidthType widthType) { + TextView result = new TextView(mContext); + result.setText(label); + AddressWidgetUiComponentProviderTest.this.increaseTextViewCounter(); + return result; } - private class CustomSpinner extends Spinner { - CustomSpinner(Context context) { - super(context); - } + protected EditText createUiTextField(AddressField.WidthType widthType) { + return new CustomEditText(mContext); } - private class CustomArrayAdapter extends ArrayAdapter { - CustomArrayAdapter(Context context, int id) { - super(context, id); - } + protected Spinner createUiPickerSpinner(AddressField.WidthType widthType) { + return new CustomSpinner(mContext); } - private class TestComponentProvider extends AddressWidgetUiComponentProvider { - TestComponentProvider(Context context) { - super(context); - } - - protected TextView createUiLabel(CharSequence label, AddressField.WidthType widthType) { - TextView result = new TextView(mContext); - result.setText(label); - AddressWidgetUiComponentProviderTest.this.increaseTextViewCounter(); - return result; - } - - protected EditText createUiTextField(AddressField.WidthType widthType) { - return new CustomEditText(mContext); - } - - protected Spinner createUiPickerSpinner(AddressField.WidthType widthType) { - return new CustomSpinner(mContext); - } - - protected ArrayAdapter createUiPickerAdapter(AddressField.WidthType widthType) { - ArrayAdapter result = - new CustomArrayAdapter( - mContext, android.R.layout.simple_spinner_item); - result.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); - return result; - } - - protected ProgressDialog getUiActivityIndicatorView() { - AddressWidgetUiComponentProviderTest.this.increaseProgressDialogCounter(); - return super.getUiActivityIndicatorView(); - } + protected ArrayAdapter createUiPickerAdapter(AddressField.WidthType widthType) { + ArrayAdapter result = new CustomArrayAdapter( + context, android.R.layout.simple_spinner_item); + result.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); + return result; } -} + protected ProgressDialog getUiActivityIndicatorView() { + AddressWidgetUiComponentProviderTest.this.increaseProgressDialogCounter(); + return super.getUiActivityIndicatorView(); + } + } +} diff --git a/java/test/com/android/i18n/addressinput/AsyncTestCaseTest.java b/java/test/com/android/i18n/addressinput/AsyncTestCaseTest.java index 23fad88..495f937 100644 --- a/java/test/com/android/i18n/addressinput/AsyncTestCaseTest.java +++ b/java/test/com/android/i18n/addressinput/AsyncTestCaseTest.java @@ -25,41 +25,41 @@ import java.util.concurrent.TimeoutException; public class AsyncTestCaseTest extends AsyncTestCase { public void testSuccess() { - delayTestFinish(1000); - AsyncCallback.execute(500, new Runnable() { - @Override - public void run() { - finishTest(); - } - }); + delayTestFinish(1000); + AsyncCallback.execute(500, new Runnable() { + @Override + public void run() { + finishTest(); + } + }); } public void testFailure() { - expectTimeout = true; - delayTestFinish(1000); - AsyncCallback.execute(1500, new Runnable() { - @Override - public void run() { - finishTest(); - } - }); + expectTimeout = true; + delayTestFinish(1000); + AsyncCallback.execute(1500, new Runnable() { + @Override + public void run() { + finishTest(); + } + }); } @Override protected void runTest() throws Throwable { - expectTimeout = false; - try { - super.runTest(); - } catch (TimeoutException e) { - if (expectTimeout) { - return; - } else { - throw e; - } - } + expectTimeout = false; + try { + super.runTest(); + } catch (TimeoutException e) { if (expectTimeout) { - throw new AssertionFailedError("Test case did not time out."); + return; + } else { + throw e; } + } + if (expectTimeout) { + throw new AssertionFailedError("Test case did not time out."); + } } private boolean expectTimeout; @@ -68,28 +68,28 @@ public class AsyncTestCaseTest extends AsyncTestCase { * Helper class to perform an asynchronous callback after a specified delay. */ private static class AsyncCallback extends Thread { - public static void execute(long waitMillis, Runnable callback) { - (new AsyncCallback(waitMillis, callback)).start(); - } + public static void execute(long waitMillis, Runnable callback) { + (new AsyncCallback(waitMillis, callback)).start(); + } - @Override - public void run() { - try { - synchronized (this) { - wait(mWaitMillis); - } + @Override + public void run() { + try { + synchronized (this) { + wait(waitMillis); + } } catch (InterruptedException e) { - throw new RuntimeException(e); + throw new RuntimeException(e); } - mCallback.run(); + callback.run(); } private AsyncCallback(long waitMillis, Runnable callback) { - this.mWaitMillis = waitMillis; - this.mCallback = callback; + this.waitMillis = waitMillis; + this.callback = callback; } - private long mWaitMillis; - private Runnable mCallback; + private long waitMillis; + private Runnable callback; } } diff --git a/java/test/com/android/i18n/addressinput/CacheDataTest.java b/java/test/com/android/i18n/addressinput/CacheDataTest.java index c346882..7b72e47 100644 --- a/java/test/com/android/i18n/addressinput/CacheDataTest.java +++ b/java/test/com/android/i18n/addressinput/CacheDataTest.java @@ -23,304 +23,304 @@ import org.json.JSONException; import org.json.JSONObject; public class CacheDataTest extends AsyncTestCase { - private CacheData cache; + private CacheData cache; - private static final String DELIM = "~"; + private static final String DELIM = "~"; - private static final String CANADA_KEY = "data/CA"; + private static final String CANADA_KEY = "data/CA"; - private static final String US_KEY = "data/US"; + private static final String US_KEY = "data/US"; - private static final String CALIFORNIA_KEY = "data/US/CA"; + private static final String CALIFORNIA_KEY = "data/US/CA"; - private static final String RANDOM_COUNTRY_KEY = "data/asIOSDxcowW"; + private static final String RANDOM_COUNTRY_KEY = "data/asIOSDxcowW"; - private static final String EXAMPLE_LOCAL_US_KEY = "examples/US/local/_default"; + private static final String EXAMPLE_LOCAL_US_KEY = "examples/US/local/_default"; - // Data key for Da-an District, Taipei Taiwan - private static final String TW_KEY = "data/TW/\u53F0\u5317\u5E02/\u5927\u5B89\u5340"; + // Data key for Da-an District, Taipei Taiwan + private static final String TW_KEY = "data/TW/\u53F0\u5317\u5E02/\u5927\u5B89\u5340"; - private static final String FRANCE_KEY = "data/FR"; + private static final String FRANCE_KEY = "data/FR"; - private static Integer listenerInvokeCount = 0; + private static Integer listenerInvokeCount = 0; - private static boolean reachedMaxCount = false; + private static boolean reachedMaxCount = false; - @Override - public void setUp() { - cache = new CacheData(); - } - - public void testJsonConstructor() { - // Creating cache with content. - String id = "data/CA"; - JSONObject jsonObject = null; - try { - jsonObject = new JSONObject(AddressDataMapLoader.DATA.get(id)); - } catch (JSONException jsonException) { - // If this throws an exception the test fails. - fail("Can't parse json object"); - } - cache.addToJsoMap(id, jsonObject); - String toBackup = cache.getJsonString(); - - // Creating cache from saved data. - cache = new CacheData(toBackup); - assertTrue(cache.containsKey(id)); - } - - public void testJsonConstructorTruncatedProperString() { - // Creating cache with content. - String id = "data/CA"; - try { - JSONObject jsonObject = new JSONObject(AddressDataMapLoader.DATA.get(id)); - String jsonString = jsonObject.toString(); - jsonString = jsonString.substring(0, jsonString.length() / 2); - - cache = new CacheData(jsonString); - assertTrue(cache.toString(), cache.isEmpty()); - } catch (JSONException jsonException) { - // If this throws an exception the test fails. - fail("Can't parse json object"); - } - } - - public void testSimpleFetching() { - final LookupKey key = new LookupKey.Builder(CANADA_KEY).build(); - - delayTestFinish(10000); - - cache.fetchDynamicData(key, null, new DataLoadListener() { - boolean beginCalled = false; - - @Override - public void dataLoadingBegin() { - beginCalled = true; - } - - @Override - public void dataLoadingEnd() { - assertTrue("dataLoadingBegin should be called", beginCalled); - JsoMap map = cache.getObj(CANADA_KEY); - - assertTrue(map.containsKey(AddressDataKey.ID.name().toLowerCase())); - assertTrue(map.containsKey(AddressDataKey.LANG.name().toLowerCase())); - assertTrue(map.containsKey(AddressDataKey.ZIP.name().toLowerCase())); - assertTrue(map.containsKey(AddressDataKey.FMT.name().toLowerCase())); - assertTrue(map.containsKey(AddressDataKey.SUB_KEYS.name().toLowerCase())); - assertTrue(map.containsKey(AddressDataKey.SUB_NAMES.name().toLowerCase())); - assertFalse(map.containsKey(AddressDataKey.SUB_LNAMES.name().toLowerCase())); - - int namesSize = - map.get(AddressDataKey.SUB_NAMES.name().toLowerCase()).split(DELIM).length; - int keysSize = - map.get(AddressDataKey.SUB_KEYS.name().toLowerCase()).split(DELIM).length; - - assertEquals("Expect 13 states in Canada.", 13, namesSize); - assertEquals(namesSize, keysSize); - finishTest(); - } - }); - } - - public void testFetchingTaiwanData() { - final LookupKey key = new LookupKey.Builder(TW_KEY).build(); - - delayTestFinish(10000); - - cache.fetchDynamicData(key, null, new DataLoadListener() { - boolean beginCalled = false; - - @Override - public void dataLoadingBegin() { - beginCalled = true; - } - - @Override - public void dataLoadingEnd() { - assertTrue("dataLoadingBegin should be called", beginCalled); - - JsoMap map = cache.getObj(TW_KEY); - - assertTrue(map.containsKey(AddressDataKey.ID.name().toLowerCase())); - assertTrue(map.containsKey(AddressDataKey.KEY.name().toLowerCase())); - assertTrue(map.containsKey(AddressDataKey.LANG.name().toLowerCase())); - assertTrue(map.containsKey(AddressDataKey.ZIP.name().toLowerCase())); - assertFalse(map.containsKey(AddressDataKey.FMT.name().toLowerCase())); - assertFalse(map.containsKey(AddressDataKey.SUB_KEYS.name().toLowerCase())); - assertFalse(map.containsKey(AddressDataKey.SUB_NAMES.name().toLowerCase())); - assertFalse(map.containsKey(AddressDataKey.SUB_LNAMES.name().toLowerCase())); - - // Da-an district. - assertEquals("\u5927\u5B89\u5340", - map.get(AddressDataKey.KEY.name().toLowerCase())); + @Override + public void setUp() { + cache = new CacheData(); + } - assertEquals("zh-hant", map.get(AddressDataKey.LANG.name().toLowerCase())); - - finishTest(); - } - }); + public void testJsonConstructor() { + // Creating cache with content. + String id = "data/CA"; + JSONObject jsonObject = null; + try { + jsonObject = new JSONObject(AddressDataMapLoader.DATA.get(id)); + } catch (JSONException jsonException) { + // If this throws an exception the test fails. + fail("Can't parse json object"); } - - public void testFetchingExamples() { - final LookupKey key = new LookupKey.Builder(EXAMPLE_LOCAL_US_KEY).build(); - - delayTestFinish(10000); - - cache.fetchDynamicData(key, null, new DataLoadListener() { - boolean beginCalled = false; - - @Override - public void dataLoadingBegin() { - beginCalled = true; - } - - @Override - public void dataLoadingEnd() { - assertTrue("dataLoadingBegin should be called", beginCalled); - - JsoMap map = cache.getObj(EXAMPLE_LOCAL_US_KEY); - assertTrue(map.containsKey("name")); - finishTest(); - } - }); + cache.addToJsoMap(id, jsonObject); + String toBackup = cache.getJsonString(); + + // Creating cache from saved data. + cache = new CacheData(toBackup); + assertTrue(cache.containsKey(id)); + } + + public void testJsonConstructorTruncatedProperString() { + // Creating cache with content. + String id = "data/CA"; + try { + JSONObject jsonObject = new JSONObject(AddressDataMapLoader.DATA.get(id)); + String jsonString = jsonObject.toString(); + jsonString = jsonString.substring(0, jsonString.length() / 2); + + cache = new CacheData(jsonString); + assertTrue(cache.toString(), cache.isEmpty()); + } catch (JSONException jsonException) { + // If this throws an exception the test fails. + fail("Can't parse json object"); } + } + + public void testSimpleFetching() { + final LookupKey key = new LookupKey.Builder(CANADA_KEY).build(); + + delayTestFinish(10000); - public void testFetchingOneKeyManyTimes() { - final LookupKey key = new LookupKey.Builder(CALIFORNIA_KEY).build(); - final int maxCount = 10; - - class CounterListener implements DataLoadListener { - @Override - public void dataLoadingBegin() { - listenerInvokeCount++; - if (listenerInvokeCount == maxCount) { - reachedMaxCount = true; - } - assertTrue("CounterListener's dataLoadingBegin should not be invoked for more " + - "than " + maxCount + " times", - listenerInvokeCount <= maxCount); - } - - @Override - public void dataLoadingEnd() { - listenerInvokeCount--; - assertTrue(listenerInvokeCount >= 0); - if (listenerInvokeCount == 0) { - assertTrue("Expect to see key " + key + " cached when CounterListener's " + - " dataLoadingEnd is invoked", - cache.containsKey(key.toString())); - assertTrue("Expect CounterListener's dataLoadingEnd to be triggered " + - maxCount + " times in total", reachedMaxCount); - finishTest(); - } - } + cache.fetchDynamicData(key, null, new DataLoadListener() { + boolean beginCalled = false; + + @Override + public void dataLoadingBegin() { + beginCalled = true; + } + + @Override + public void dataLoadingEnd() { + assertTrue("dataLoadingBegin should be called", beginCalled); + JsoMap map = cache.getObj(CANADA_KEY); + + assertTrue(map.containsKey(AddressDataKey.ID.name().toLowerCase())); + assertTrue(map.containsKey(AddressDataKey.LANG.name().toLowerCase())); + assertTrue(map.containsKey(AddressDataKey.ZIP.name().toLowerCase())); + assertTrue(map.containsKey(AddressDataKey.FMT.name().toLowerCase())); + assertTrue(map.containsKey(AddressDataKey.SUB_KEYS.name().toLowerCase())); + assertTrue(map.containsKey(AddressDataKey.SUB_NAMES.name().toLowerCase())); + assertFalse(map.containsKey(AddressDataKey.SUB_LNAMES.name().toLowerCase())); + + int namesSize = + map.get(AddressDataKey.SUB_NAMES.name().toLowerCase()).split(DELIM).length; + int keysSize = + map.get(AddressDataKey.SUB_KEYS.name().toLowerCase()).split(DELIM).length; + + assertEquals("Expect 13 states in Canada.", 13, namesSize); + assertEquals(namesSize, keysSize); + finishTest(); + } + }); + } + + public void testFetchingTaiwanData() { + final LookupKey key = new LookupKey.Builder(TW_KEY).build(); + + delayTestFinish(10000); + + cache.fetchDynamicData(key, null, new DataLoadListener() { + boolean beginCalled = false; + + @Override + public void dataLoadingBegin() { + beginCalled = true; + } + + @Override + public void dataLoadingEnd() { + assertTrue("dataLoadingBegin should be called", beginCalled); + + JsoMap map = cache.getObj(TW_KEY); + + assertTrue(map.containsKey(AddressDataKey.ID.name().toLowerCase())); + assertTrue(map.containsKey(AddressDataKey.KEY.name().toLowerCase())); + assertTrue(map.containsKey(AddressDataKey.LANG.name().toLowerCase())); + assertTrue(map.containsKey(AddressDataKey.ZIP.name().toLowerCase())); + assertFalse(map.containsKey(AddressDataKey.FMT.name().toLowerCase())); + assertFalse(map.containsKey(AddressDataKey.SUB_KEYS.name().toLowerCase())); + assertFalse(map.containsKey(AddressDataKey.SUB_NAMES.name().toLowerCase())); + assertFalse(map.containsKey(AddressDataKey.SUB_LNAMES.name().toLowerCase())); + + // Da-an district. + assertEquals("\u5927\u5B89\u5340", + map.get(AddressDataKey.KEY.name().toLowerCase())); + + assertEquals("zh-hant", map.get(AddressDataKey.LANG.name().toLowerCase())); + + finishTest(); + } + }); + } + + public void testFetchingExamples() { + final LookupKey key = new LookupKey.Builder(EXAMPLE_LOCAL_US_KEY).build(); + + delayTestFinish(10000); + + cache.fetchDynamicData(key, null, new DataLoadListener() { + boolean beginCalled = false; + + @Override + public void dataLoadingBegin() { + beginCalled = true; + } + + @Override + public void dataLoadingEnd() { + assertTrue("dataLoadingBegin should be called", beginCalled); + + JsoMap map = cache.getObj(EXAMPLE_LOCAL_US_KEY); + assertTrue(map.containsKey("name")); + finishTest(); + } + }); + } + + public void testFetchingOneKeyManyTimes() { + final LookupKey key = new LookupKey.Builder(CALIFORNIA_KEY).build(); + final int maxCount = 10; + + class CounterListener implements DataLoadListener { + @Override + public void dataLoadingBegin() { + listenerInvokeCount++; + if (listenerInvokeCount == maxCount) { + reachedMaxCount = true; } - - delayTestFinish(10000); - - for (int i = 0; i < maxCount; ++i) { - cache.fetchDynamicData(key, null, new CounterListener()); + assertTrue("CounterListener's dataLoadingBegin should not be invoked for more " + + "than " + maxCount + " times", + listenerInvokeCount <= maxCount); + } + + @Override + public void dataLoadingEnd() { + listenerInvokeCount--; + assertTrue(listenerInvokeCount >= 0); + if (listenerInvokeCount == 0) { + assertTrue("Expect to see key " + key + " cached when CounterListener's " + + " dataLoadingEnd is invoked", + cache.containsKey(key.toString())); + assertTrue("Expect CounterListener's dataLoadingEnd to be triggered " + + maxCount + " times in total", reachedMaxCount); + finishTest(); } - - // Null listeners should not affect results. - cache.fetchDynamicData(key, null, null); - cache.fetchDynamicData(key, null, null); - cache.fetchDynamicData(key, null, null); + } } - public void testFetchAgainRightAfterOneFetchStart() { - final LookupKey key = new LookupKey.Builder(US_KEY).build(); + delayTestFinish(10000); - delayTestFinish(10000); + for (int i = 0; i < maxCount; ++i) { + cache.fetchDynamicData(key, null, new CounterListener()); + } - cache.fetchDynamicData(key, null, null); + // Null listeners should not affect results. + cache.fetchDynamicData(key, null, null); + cache.fetchDynamicData(key, null, null); + cache.fetchDynamicData(key, null, null); + } - cache.fetchDynamicData(key, null, new DataLoadListener() { - boolean beginCalled = false; - - @Override - public void dataLoadingBegin() { - assertFalse("data for key " + key + " should not be fetched yet", - cache.containsKey(key.toString())); - beginCalled = true; - } - - @Override - public void dataLoadingEnd() { - assertTrue("dataLoadingBegin should be called", beginCalled); - - assertTrue(cache.containsKey(key.toString())); - - cache.fetchDynamicData(key, null, new DataLoadListener() { - boolean beginCalled2 = false; - - @Override - public void dataLoadingBegin() { - beginCalled2 = true; - } - - @Override - public void dataLoadingEnd() { - assertTrue("dataLoadingBegin should be called", beginCalled2); - - assertTrue(cache.containsKey(key.toString())); - finishTest(); - } - }); - } - }); - } + public void testFetchAgainRightAfterOneFetchStart() { + final LookupKey key = new LookupKey.Builder(US_KEY).build(); - public void testInvalidKey() { - final LookupKey key = new LookupKey.Builder(RANDOM_COUNTRY_KEY).build(); + delayTestFinish(10000); - delayTestFinish(15000); + cache.fetchDynamicData(key, null, null); - cache.fetchDynamicData(key, null, new DataLoadListener() { - boolean beginCalled = false; + cache.fetchDynamicData(key, null, new DataLoadListener() { + boolean beginCalled = false; - @Override - public void dataLoadingBegin() { - beginCalled = true; - } + @Override + public void dataLoadingBegin() { + assertFalse("data for key " + key + " should not be fetched yet", + cache.containsKey(key.toString())); + beginCalled = true; + } - @Override - public void dataLoadingEnd() { - assertTrue("dataLoadingBegin should be called", beginCalled); - assertFalse(cache.containsKey(key.toString())); + @Override + public void dataLoadingEnd() { + assertTrue("dataLoadingBegin should be called", beginCalled); - finishTest(); - } - }); - } + assertTrue(cache.containsKey(key.toString())); - public void testSetUrl() { - final LookupKey key = new LookupKey.Builder(FRANCE_KEY).build(); - final String originalUrl = cache.getUrl(); + cache.fetchDynamicData(key, null, new DataLoadListener() { + boolean beginCalled2 = false; - assertFalse(FRANCE_KEY + " should not be in the cache. Do you request it before this test?", - cache.containsKey(key.toString())); + @Override + public void dataLoadingBegin() { + beginCalled2 = true; + } - delayTestFinish(10000); - // Something that is not an URL. - cache.setUrl("FDSSfdfdsfasdfadsf"); + @Override + public void dataLoadingEnd() { + assertTrue("dataLoadingBegin should be called", beginCalled2); - cache.fetchDynamicData(key, null, new DataLoadListener() { - boolean beginCalled = false; - - @Override - public void dataLoadingBegin() { - beginCalled = true; - } - - @Override - public void dataLoadingEnd() { - assertTrue("dataLoadingBegin should be called", beginCalled); - assertFalse(cache.containsKey(key.toString())); - cache.setUrl(originalUrl); - finishTest(); - } + assertTrue(cache.containsKey(key.toString())); + finishTest(); + } }); - } + } + }); + } + + public void testInvalidKey() { + final LookupKey key = new LookupKey.Builder(RANDOM_COUNTRY_KEY).build(); + + delayTestFinish(15000); + + cache.fetchDynamicData(key, null, new DataLoadListener() { + boolean beginCalled = false; + + @Override + public void dataLoadingBegin() { + beginCalled = true; + } + + @Override + public void dataLoadingEnd() { + assertTrue("dataLoadingBegin should be called", beginCalled); + assertFalse(cache.containsKey(key.toString())); + + finishTest(); + } + }); + } + + public void testSetUrl() { + final LookupKey key = new LookupKey.Builder(FRANCE_KEY).build(); + final String originalUrl = cache.getUrl(); + + assertFalse(FRANCE_KEY + " should not be in the cache. Do you request it before this test?", + cache.containsKey(key.toString())); + + delayTestFinish(10000); + // Something that is not an URL. + cache.setUrl("FDSSfdfdsfasdfadsf"); + + cache.fetchDynamicData(key, null, new DataLoadListener() { + boolean beginCalled = false; + + @Override + public void dataLoadingBegin() { + beginCalled = true; + } + + @Override + public void dataLoadingEnd() { + assertTrue("dataLoadingBegin should be called", beginCalled); + assertFalse(cache.containsKey(key.toString())); + cache.setUrl(originalUrl); + finishTest(); + } + }); + } } diff --git a/java/test/com/android/i18n/addressinput/ClientDataTest.java b/java/test/com/android/i18n/addressinput/ClientDataTest.java index b18d726..c665a3b 100644 --- a/java/test/com/android/i18n/addressinput/ClientDataTest.java +++ b/java/test/com/android/i18n/addressinput/ClientDataTest.java @@ -23,61 +23,61 @@ import com.android.i18n.addressinput.testing.AsyncTestCase; * server and recovers if no data is present. */ public class ClientDataTest extends AsyncTestCase { - private ClientData client; + private ClientData client; - @Override - public void setUp() { - client = new ClientData(new CacheData()); - } + @Override + public void setUp() { + client = new ClientData(new CacheData()); + } - public void testGet() { - AddressVerificationNodeData data = client.get("data"); - assertNotNull(data); - } + public void testGet() { + AddressVerificationNodeData data = client.get("data"); + assertNotNull(data); + } - public void testGet2() { - AddressVerificationNodeData data; + public void testGet2() { + AddressVerificationNodeData data; - data = client.get("data"); - assertNotNull(data); + data = client.get("data"); + assertNotNull(data); - data = client.get("data"); - assertNotNull(data); - } + data = client.get("data"); + assertNotNull(data); + } - public void testPrefetchCountry() { - delayTestFinish(60000); + public void testPrefetchCountry() { + delayTestFinish(60000); - client.prefetchCountry("TW", new DataLoadListener() { - boolean beginCalled = false; + client.prefetchCountry("TW", new DataLoadListener() { + boolean beginCalled = false; - @Override - public void dataLoadingBegin() { - beginCalled = true; - } + @Override + public void dataLoadingBegin() { + beginCalled = true; + } - @Override - public void dataLoadingEnd() { - assertTrue("dataLoadingBegin should be called", beginCalled); - // Currently this test only tests that the execution doesn't crash and eventually - // terminates. TODO: Write test cases to verify that correct data is loaded. - finishTest(); - } - }); - } + @Override + public void dataLoadingEnd() { + assertTrue("dataLoadingBegin should be called", beginCalled); + // Currently this test only tests that the execution doesn't crash and eventually + // terminates. TODO: Write test cases to verify that correct data is loaded. + finishTest(); + } + }); + } - public void testFetchDataWithBadServer() { - CacheData badCache = new CacheData(); - badCache.setUrl("http://www.google.com"); - ClientData badServerClient = new ClientData(badCache); + public void testFetchDataWithBadServer() { + CacheData badCache = new CacheData(); + badCache.setUrl("http://www.google.com"); + ClientData badServerClient = new ClientData(badCache); - AddressVerificationNodeData data = badServerClient.get("data/US"); + AddressVerificationNodeData data = badServerClient.get("data/US"); - // No data was available on the server or in the cache - it should check - // that there is nothing in region data constants, and should return the - // data from there. - assertNotNull(data); - String unitedStatesFormatInfo = data.get(AddressDataKey.FMT); - assertEquals("%N%n%O%n%A%n%C, %S %Z", unitedStatesFormatInfo); - } + // No data was available on the server or in the cache - it should check + // that there is nothing in region data constants, and should return the + // data from there. + assertNotNull(data); + String unitedStatesFormatInfo = data.get(AddressDataKey.FMT); + assertEquals("%N%n%O%n%A%n%C, %S %Z", unitedStatesFormatInfo); + } } diff --git a/java/test/com/android/i18n/addressinput/FieldVerifierTest.java b/java/test/com/android/i18n/addressinput/FieldVerifierTest.java index bc09905..2988691 100644 --- a/java/test/com/android/i18n/addressinput/FieldVerifierTest.java +++ b/java/test/com/android/i18n/addressinput/FieldVerifierTest.java @@ -31,284 +31,284 @@ import java.util.Set; */ public class FieldVerifierTest extends TestCase { - private static final StandardAddressVerifier VERIFIER = - new StandardAddressVerifier(new FieldVerifier( - new AddressVerificationData(AddressDataMapLoader.DATA))); - - private AddressProblems problems = new AddressProblems(); - - @Override - protected void setUp() { - problems.clear(); - } - - public void testUnitedStatesOk() { - AddressData addr = new AddressData.Builder().setCountry("US") - .setAdminArea("CA") - .setLocality("Mountain View") - .setAddress("1234 Somewhere") - .setPostalCode("94025").build(); - VERIFIER.verify(addr, problems); - assertTrue(problems.toString(), problems.isEmpty()); // no mismatch - } - - public void testUnitedStatesZipMismatch() { - AddressData addr = new AddressData.Builder().setCountry("US") - .setAdminArea("CA") - .setLocality("Mountain View") - .setPostalCode("12345").build(); - VERIFIER.verify(addr, problems); - - assertEquals(AddressProblemType.MISMATCHING_VALUE, - problems.getProblem(AddressField.POSTAL_CODE)); - } - - public void testUnitedStatesNotOk() { - AddressData addr = new AddressData.Builder().setCountry("US") - .setAdminArea("CA") - .setLocality(null) - .setDependentLocality("Foo Bar") - .setPostalCode("12345").build(); - VERIFIER.verify(addr, problems); - - assertEquals(AddressProblemType.MISMATCHING_VALUE, - problems.getProblem(AddressField.POSTAL_CODE)); - assertEquals(AddressProblemType.MISSING_REQUIRED_FIELD, - problems.getProblem(AddressField.LOCALITY)); - } - - public void testChinaOk() { - AddressData addr = new AddressData.Builder().setCountry("CN") - .setAdminArea("Beijing Shi") - .setLocality("Xicheng Qu") - .setAddress("Yitiao Lu") - .setPostalCode("123456").build(); - VERIFIER.verify(addr, problems); - assertTrue(problems.isEmpty()); - } - - public void testGermanAddress() { - AddressData addr = new AddressData.Builder().setCountry("DE") - .setLocality("Berlin") - .setAddress("Huttenstr. 50") - .setPostalCode("10553") - .setOrganization("BMW AG Niederkassung Berlin") - .setRecipient("Herr Diefendorf").build(); - - VERIFIER.verify(addr, problems); - assertTrue(problems.isEmpty()); - - // Clones address but leave city empty. - addr = new AddressData.Builder().set(addr).setLocality(null).build(); - - VERIFIER.verify(addr, problems); - assertEquals(AddressProblemType.MISSING_REQUIRED_FIELD, - problems.getProblem(AddressField.LOCALITY)); - } - - public void testIrishAddress() { - AddressData addr = new AddressData.Builder().setCountry("IE") - .setLocality("Dublin") - .setAdminArea("Co. Dublin") - .setAddress("7424 118 Avenue NW") - .setRecipient("Conan O'Brien").build(); - - VERIFIER.verify(addr, problems); - assertTrue(problems.toString(), problems.isEmpty()); - - // Clones address but leave county empty. This address should be valid - // since county is not required. - addr = new AddressData.Builder().set(addr).setAdminArea(null).build(); - - VERIFIER.verify(addr, problems); - assertTrue(problems.toString(), problems.isEmpty()); - } - - public void testChinaPostalCodeBadFormat() { - AddressData addr = new AddressData.Builder().setCountry("CN") - .setAdminArea("Beijing Shi") - .setLocality("Xicheng Qu") - .setPostalCode("12345").build(); - VERIFIER.verify(addr, problems); - - assertEquals(AddressProblemType.UNRECOGNIZED_FORMAT, - problems.getProblem(AddressField.POSTAL_CODE)); - } - - /** - * If there is a postal code pattern for a certain country, and the input postal code is empty, - * it should not be reported as bad postal code format. Whether empty postal code is ok should - * be determined by checks for required fields. - */ - public void testEmptyPostalCodeReportedAsGoodFormat() { - // Chilean address has a postal code format pattern, but does not require - // postal code. The following address is valid. - AddressData addr = new AddressData.Builder().setCountry("CL") - .setAddressLine1("GUSTAVO LE PAIGE ST #159") - .setAdminArea("Atacama") - .setLocality("San Pedro") - .setPostalCode("") - .build(); - VERIFIER.verify(addr, problems); - assertTrue(problems.toString(), problems.isEmpty()); - - problems.clear(); - - // Now check for US addresses, which require a postal code. The following - // address's postal code is wrong because it is missing a required field, not - // because it doesn't match the expected postal code pattern. - addr = new AddressData.Builder().setCountry("US").setPostalCode("").build(); - problems.clear(); - VERIFIER.verify(addr, problems); - - assertEquals(AddressProblemType.MISSING_REQUIRED_FIELD, - problems.getProblem(AddressField.POSTAL_CODE)); - } - - public void testChinaTaiwanOk() { - AddressData addr = new AddressData.Builder().setCountry("CN") - .setAdminArea("Taiwan") - .setLocality("Taichung City") - .setDependentLocality("Situn District") - .setAddress("12345 Yitiao Lu") - .setPostalCode("407").build(); - VERIFIER.verify(addr, problems); - assertTrue(problems.isEmpty()); - } - - public void testChinaTaiwanUnknownDistrict() { - AddressData addr = new AddressData.Builder().setCountry("CN") - .setAdminArea("Taiwan") - .setLocality("Taichung City") - .setDependentLocality("Foo Bar") - .setPostalCode("400").build(); - VERIFIER.verify(addr, problems); - - assertEquals(AddressProblemType.UNKNOWN_VALUE, - problems.getProblem(AddressField.DEPENDENT_LOCALITY)); - } - - public void testStreetVerification() { - // Missing street address - AddressData addr = new AddressData.Builder().setCountry("US") - .setAdminArea("CA") - .setLocality("Mountain View") - .setPostalCode("94025").build(); - - assertNull(addr.getAddressLine1()); - assertNull(addr.getAddressLine2()); - - VERIFIER.verify(addr, problems); - - assertEquals(AddressProblemType.MISSING_REQUIRED_FIELD, - problems.getProblem(AddressField.STREET_ADDRESS)); - } - - // Tests The Bahamas' address - public void failingtestBahamas() { - final AddressData address = - new AddressData.Builder().setAddress("Abaco Beach Resort & Boat Habour") - .setLocality("Treasure Cay") - .setAdminArea("Abaco") - .setCountry("BS").build(); - VERIFIER.verify(address, problems); - assertTrue(problems.isEmpty()); - } - - public void testJapan() { - // Added AdminArea since address verification can't infer it from Kyoto City - // Commented out dependent locality since we don't have the data for this and in fact say - // that it shouldn't be used for Japan. - // TODO: support inference of higher levels from lower ones - final AddressData address = new AddressData.Builder() - .setRecipient("\u5BAE\u672C \u8302") // SHIGERU_MIYAMOTO - .setAddress("\u4E0A\u9CE5\u7FBD\u927E\u7ACB\u753A11\u756A\u5730") - .setAdminArea("\u4eac\u90fd\u5e9c") // Kyoto prefecture, added - .setLocality("\u4EAC\u90FD\u5E02") // Kyoto city - // .setDependentLocality("\u5357\u533A") - .setCountry("JP") - .setPostalCode("601-8501").build(); - VERIFIER.verify(address, problems); - assertTrue(problems.toString(), problems.isEmpty()); - } - - public void testJapanLatin() { - // added AdminArea since address verification can't infer it from Kyoto City - // commented out dependent locality since address verification doesn't use it - final AddressData address = new AddressData.Builder() - .setRecipient("Shigeru Miyamoto") // SHIGERU_MIYAMOTO_ENGLISH - .setAddress("11-1 Kamitoba-hokotate-cho") - .setAdminArea("KYOTO") // added - .setLocality("Kyoto") - // .setDependentLocality("Minami-ku") - .setLanguageCode("ja_Latn") - .setCountry("JP") - .setPostalCode("601-8501").build(); - VERIFIER.verify(address, problems); - assertTrue(problems.isEmpty()); - } - - public void testJapanLatinInvalidAdmin() { - final AddressData address = new AddressData.Builder() - .setRecipient("Shigeru Miyamoto") // SHIGERU_MIYAMOTO_ENGLISH - .setAddress("11-1 Kamitoba-hokotate-cho") - .setAdminArea("Fake Admin") - .setLocality("Kyoto") - .setLanguageCode("ja_Latn") - .setCountry("JP") - .setPostalCode("601-8501").build(); - VERIFIER.verify(address, problems); - assertFalse(problems.isEmpty()); - assertEquals(AddressProblemType.UNKNOWN_VALUE, - problems.getProblem(AddressField.ADMIN_AREA)); - } - - public void testCanadaMixedCasePostcode() { - final AddressData address = new AddressData.Builder() - .setRecipient("Joe Bloggs") - .setAddress("11 East St") - .setLocality("Montreal") - .setAdminArea("Quebec") - .setCountry("CA") - .setPostalCode("H2b 2y5").build(); - VERIFIER.verify(address, problems); - assertTrue(problems.isEmpty()); - } - - public void testMultipleAddressLines() { - final AddressData address = new AddressData.Builder() - .setCountry("US") - .setAdminArea("CA") - .setLocality("Mountain View") - .setAddressLine1("Somewhere") - .setAddressLine2("1234") - .setPostalCode("94025").build(); - VERIFIER.verify(address, problems); - assertTrue(problems.isEmpty()); - } - - public void testFieldVerifierUsesRegionDataConstantsForFmtAndRequire() { - Map map = new EnumMap(AddressDataKey.class); - // Values for format and require are deliberately different from RegionDataConstants so that - // we can test that the RDC's version is preferred. - map.put(AddressDataKey.FMT, "%N%n%O"); - map.put(AddressDataKey.REQUIRE, "A"); - map.put(AddressDataKey.SUB_KEYS, "Test"); - map.put(AddressDataKey.ID, "data/FM"); - AddressVerificationNodeData testNode = new AddressVerificationNodeData(map); - FieldVerifier fieldVerifier = new FieldVerifier(VERIFIER.mRootVerifier, testNode); - - // Used and required obtained from RegionDataConstants for FM. - Set expectedPossibleFields = EnumSet.of(AddressField.RECIPIENT, - AddressField.ORGANIZATION, AddressField.STREET_ADDRESS, AddressField.LOCALITY, - AddressField.ADMIN_AREA, AddressField.POSTAL_CODE, AddressField.COUNTRY); - Set expectedRequiredField = EnumSet.of(AddressField.STREET_ADDRESS, - AddressField.LOCALITY, AddressField.ADMIN_AREA, AddressField.POSTAL_CODE, - AddressField.COUNTRY); - assertEquals(expectedPossibleFields, fieldVerifier.mPossiblyUsedFields); - assertEquals(expectedRequiredField, fieldVerifier.mRequired); - assertEquals("data/FM", fieldVerifier.mId); - // Keys should be populated from the test node. - assertEquals("[Test]", Arrays.toString(fieldVerifier.mKeys)); - } + private static final StandardAddressVerifier VERIFIER = + new StandardAddressVerifier(new FieldVerifier( + new AddressVerificationData(AddressDataMapLoader.DATA))); + + private AddressProblems problems = new AddressProblems(); + + @Override + protected void setUp() { + problems.clear(); + } + + public void testUnitedStatesOk() { + AddressData addr = new AddressData.Builder().setCountry("US") + .setAdminArea("CA") + .setLocality("Mountain View") + .setAddress("1234 Somewhere") + .setPostalCode("94025").build(); + VERIFIER.verify(addr, problems); + assertTrue(problems.toString(), problems.isEmpty()); // no mismatch + } + + public void testUnitedStatesZipMismatch() { + AddressData addr = new AddressData.Builder().setCountry("US") + .setAdminArea("CA") + .setLocality("Mountain View") + .setPostalCode("12345").build(); + VERIFIER.verify(addr, problems); + + assertEquals(AddressProblemType.MISMATCHING_VALUE, + problems.getProblem(AddressField.POSTAL_CODE)); + } + + public void testUnitedStatesNotOk() { + AddressData addr = new AddressData.Builder().setCountry("US") + .setAdminArea("CA") + .setLocality(null) + .setDependentLocality("Foo Bar") + .setPostalCode("12345").build(); + VERIFIER.verify(addr, problems); + + assertEquals(AddressProblemType.MISMATCHING_VALUE, + problems.getProblem(AddressField.POSTAL_CODE)); + assertEquals(AddressProblemType.MISSING_REQUIRED_FIELD, + problems.getProblem(AddressField.LOCALITY)); + } + + public void testChinaOk() { + AddressData addr = new AddressData.Builder().setCountry("CN") + .setAdminArea("Beijing Shi") + .setLocality("Xicheng Qu") + .setAddress("Yitiao Lu") + .setPostalCode("123456").build(); + VERIFIER.verify(addr, problems); + assertTrue(problems.isEmpty()); + } + + public void testGermanAddress() { + AddressData addr = new AddressData.Builder().setCountry("DE") + .setLocality("Berlin") + .setAddress("Huttenstr. 50") + .setPostalCode("10553") + .setOrganization("BMW AG Niederkassung Berlin") + .setRecipient("Herr Diefendorf").build(); + + VERIFIER.verify(addr, problems); + assertTrue(problems.isEmpty()); + + // Clones address but leave city empty. + addr = new AddressData.Builder().set(addr).setLocality(null).build(); + + VERIFIER.verify(addr, problems); + assertEquals(AddressProblemType.MISSING_REQUIRED_FIELD, + problems.getProblem(AddressField.LOCALITY)); + } + + public void testIrishAddress() { + AddressData addr = new AddressData.Builder().setCountry("IE") + .setLocality("Dublin") + .setAdminArea("Co. Dublin") + .setAddress("7424 118 Avenue NW") + .setRecipient("Conan O'Brien").build(); + + VERIFIER.verify(addr, problems); + assertTrue(problems.toString(), problems.isEmpty()); + + // Clones address but leave county empty. This address should be valid + // since county is not required. + addr = new AddressData.Builder().set(addr).setAdminArea(null).build(); + + VERIFIER.verify(addr, problems); + assertTrue(problems.toString(), problems.isEmpty()); + } + + public void testChinaPostalCodeBadFormat() { + AddressData addr = new AddressData.Builder().setCountry("CN") + .setAdminArea("Beijing Shi") + .setLocality("Xicheng Qu") + .setPostalCode("12345").build(); + VERIFIER.verify(addr, problems); + + assertEquals(AddressProblemType.UNRECOGNIZED_FORMAT, + problems.getProblem(AddressField.POSTAL_CODE)); + } + + /** + * If there is a postal code pattern for a certain country, and the input postal code is empty, + * it should not be reported as bad postal code format. Whether empty postal code is ok should + * be determined by checks for required fields. + */ + public void testEmptyPostalCodeReportedAsGoodFormat() { + // Chilean address has a postal code format pattern, but does not require + // postal code. The following address is valid. + AddressData addr = new AddressData.Builder().setCountry("CL") + .setAddressLine1("GUSTAVO LE PAIGE ST #159") + .setAdminArea("Atacama") + .setLocality("San Pedro") + .setPostalCode("") + .build(); + VERIFIER.verify(addr, problems); + assertTrue(problems.toString(), problems.isEmpty()); + + problems.clear(); + + // Now check for US addresses, which require a postal code. The following + // address's postal code is wrong because it is missing a required field, not + // because it doesn't match the expected postal code pattern. + addr = new AddressData.Builder().setCountry("US").setPostalCode("").build(); + problems.clear(); + VERIFIER.verify(addr, problems); + + assertEquals(AddressProblemType.MISSING_REQUIRED_FIELD, + problems.getProblem(AddressField.POSTAL_CODE)); + } + + public void testChinaTaiwanOk() { + AddressData addr = new AddressData.Builder().setCountry("CN") + .setAdminArea("Taiwan") + .setLocality("Taichung City") + .setDependentLocality("Situn District") + .setAddress("12345 Yitiao Lu") + .setPostalCode("407").build(); + VERIFIER.verify(addr, problems); + assertTrue(problems.isEmpty()); + } + + public void testChinaTaiwanUnknownDistrict() { + AddressData addr = new AddressData.Builder().setCountry("CN") + .setAdminArea("Taiwan") + .setLocality("Taichung City") + .setDependentLocality("Foo Bar") + .setPostalCode("400").build(); + VERIFIER.verify(addr, problems); + + assertEquals(AddressProblemType.UNKNOWN_VALUE, + problems.getProblem(AddressField.DEPENDENT_LOCALITY)); + } + + public void testStreetVerification() { + // Missing street address + AddressData addr = new AddressData.Builder().setCountry("US") + .setAdminArea("CA") + .setLocality("Mountain View") + .setPostalCode("94025").build(); + + assertNull(addr.getAddressLine1()); + assertNull(addr.getAddressLine2()); + + VERIFIER.verify(addr, problems); + + assertEquals(AddressProblemType.MISSING_REQUIRED_FIELD, + problems.getProblem(AddressField.STREET_ADDRESS)); + } + + // Tests The Bahamas' address + public void failingtestBahamas() { + final AddressData address = + new AddressData.Builder().setAddress("Abaco Beach Resort & Boat Habour") + .setLocality("Treasure Cay") + .setAdminArea("Abaco") + .setCountry("BS").build(); + VERIFIER.verify(address, problems); + assertTrue(problems.isEmpty()); + } + + public void testJapan() { + // Added AdminArea since address verification can't infer it from Kyoto City + // Commented out dependent locality since we don't have the data for this and in fact say + // that it shouldn't be used for Japan. + // TODO: support inference of higher levels from lower ones + final AddressData address = new AddressData.Builder() + .setRecipient("\u5BAE\u672C \u8302") // SHIGERU_MIYAMOTO + .setAddress("\u4E0A\u9CE5\u7FBD\u927E\u7ACB\u753A11\u756A\u5730") + .setAdminArea("\u4eac\u90fd\u5e9c") // Kyoto prefecture, added + .setLocality("\u4EAC\u90FD\u5E02") // Kyoto city + // .setDependentLocality("\u5357\u533A") + .setCountry("JP") + .setPostalCode("601-8501").build(); + VERIFIER.verify(address, problems); + assertTrue(problems.toString(), problems.isEmpty()); + } + + public void testJapanLatin() { + // added AdminArea since address verification can't infer it from Kyoto City + // commented out dependent locality since address verification doesn't use it + final AddressData address = new AddressData.Builder() + .setRecipient("Shigeru Miyamoto") // SHIGERU_MIYAMOTO_ENGLISH + .setAddress("11-1 Kamitoba-hokotate-cho") + .setAdminArea("KYOTO") // added + .setLocality("Kyoto") + // .setDependentLocality("Minami-ku") + .setLanguageCode("ja_Latn") + .setCountry("JP") + .setPostalCode("601-8501").build(); + VERIFIER.verify(address, problems); + assertTrue(problems.isEmpty()); + } + + public void testJapanLatinInvalidAdmin() { + final AddressData address = new AddressData.Builder() + .setRecipient("Shigeru Miyamoto") // SHIGERU_MIYAMOTO_ENGLISH + .setAddress("11-1 Kamitoba-hokotate-cho") + .setAdminArea("Fake Admin") + .setLocality("Kyoto") + .setLanguageCode("ja_Latn") + .setCountry("JP") + .setPostalCode("601-8501").build(); + VERIFIER.verify(address, problems); + assertFalse(problems.isEmpty()); + assertEquals(AddressProblemType.UNKNOWN_VALUE, + problems.getProblem(AddressField.ADMIN_AREA)); + } + + public void testCanadaMixedCasePostcode() { + final AddressData address = new AddressData.Builder() + .setRecipient("Joe Bloggs") + .setAddress("11 East St") + .setLocality("Montreal") + .setAdminArea("Quebec") + .setCountry("CA") + .setPostalCode("H2b 2y5").build(); + VERIFIER.verify(address, problems); + assertTrue(problems.isEmpty()); + } + + public void testMultipleAddressLines() { + final AddressData address = new AddressData.Builder() + .setCountry("US") + .setAdminArea("CA") + .setLocality("Mountain View") + .setAddressLine1("Somewhere") + .setAddressLine2("1234") + .setPostalCode("94025").build(); + VERIFIER.verify(address, problems); + assertTrue(problems.isEmpty()); + } + + public void testFieldVerifierUsesRegionDataConstantsForFmtAndRequire() { + Map map = new EnumMap(AddressDataKey.class); + // Values for format and require are deliberately different from RegionDataConstants so that + // we can test that the RDC's version is preferred. + map.put(AddressDataKey.FMT, "%N%n%O"); + map.put(AddressDataKey.REQUIRE, "A"); + map.put(AddressDataKey.SUB_KEYS, "Test"); + map.put(AddressDataKey.ID, "data/FM"); + AddressVerificationNodeData testNode = new AddressVerificationNodeData(map); + FieldVerifier fieldVerifier = new FieldVerifier(VERIFIER.rootVerifier, testNode); + + // Used and required obtained from RegionDataConstants for FM. + Set expectedPossibleFields = EnumSet.of(AddressField.RECIPIENT, + AddressField.ORGANIZATION, AddressField.STREET_ADDRESS, AddressField.LOCALITY, + AddressField.ADMIN_AREA, AddressField.POSTAL_CODE, AddressField.COUNTRY); + Set expectedRequiredField = EnumSet.of(AddressField.STREET_ADDRESS, + AddressField.LOCALITY, AddressField.ADMIN_AREA, AddressField.POSTAL_CODE, + AddressField.COUNTRY); + assertEquals(expectedPossibleFields, fieldVerifier.possiblyUsedFields); + assertEquals(expectedRequiredField, fieldVerifier.required); + assertEquals("data/FM", fieldVerifier.id); + // Keys should be populated from the test node. + assertEquals("[Test]", Arrays.toString(fieldVerifier.keys)); + } } diff --git a/java/test/com/android/i18n/addressinput/FormControllerTest.java b/java/test/com/android/i18n/addressinput/FormControllerTest.java index 23b798f..c0fa877 100644 --- a/java/test/com/android/i18n/addressinput/FormControllerTest.java +++ b/java/test/com/android/i18n/addressinput/FormControllerTest.java @@ -26,126 +26,126 @@ import java.util.List; */ public class FormControllerTest extends AsyncTestCase { - private static final AddressData US_CA_ADDRESS; - private static final AddressData US_ADDRESS; - private ClientData clientData; - - static { - US_CA_ADDRESS = new AddressData.Builder().setCountry("US") - .setAdminArea("CA") - .setLocality("Mt View") - .setAddressLine1("1098 Alta Ave") - .setPostalCode("94043") - .build(); - US_ADDRESS = new AddressData.Builder().setCountry("US").build(); - } - - @Override - public void setUp() { - clientData = new ClientData(new CacheData()); - } - - public void testRequestDataForAddress() { - final FormController controller = new FormController(clientData, "en", "US"); - - delayTestFinish(15000); - - controller.requestDataForAddress(US_CA_ADDRESS, new DataLoadListener() { - boolean beginCalled = false; - @Override - public void dataLoadingBegin() { - beginCalled = true; - } - - @Override - public void dataLoadingEnd() { - assertTrue("dataLoadingBegin should be called before dataLoadingEnd", - beginCalled); - LookupKey usCaMtvKey = new LookupKey.Builder(KeyType.DATA) - .setAddressData(US_CA_ADDRESS).build(); - LookupKey usKey = usCaMtvKey.getKeyForUpperLevelField( - AddressField.COUNTRY); - LookupKey usCaKey = usCaMtvKey.getKeyForUpperLevelField( - AddressField.ADMIN_AREA); - assertNotNull("key should be data/US/CA", usCaKey); - assertNotNull("key should be data/US/CA/Mt View", usCaMtvKey); - assertNotNull(clientData.get(usKey.toString())); - assertNotNull(clientData.get(usCaKey.toString())); - assertNull(clientData.get(usCaMtvKey.toString())); - finishTest(); - } - }); - } - - public void testRequestDataForBadAddress() { - final AddressData address = new AddressData.Builder(US_CA_ADDRESS) - .setAdminArea("FOOBAR") - .setLocality("KarKar") - .build(); - - final FormController controller = new FormController(clientData, "en", "US"); - - delayTestFinish(15000); - - controller.requestDataForAddress(address, new DataLoadListener() { - boolean beginCalled = false; - @Override - public void dataLoadingBegin() { - beginCalled = true; - } - - @Override - public void dataLoadingEnd() { - assertTrue("dataLoadingBegin should be called before dataLoadingEnd", - beginCalled); - LookupKey badKey = new LookupKey.Builder(KeyType.DATA) - .setAddressData(address).build(); - LookupKey usKey = badKey.getKeyForUpperLevelField(AddressField.COUNTRY); - - List rdata = controller.getRegionData(usKey); - assertTrue(rdata.size() > 0); - String subkey = rdata.get(0).getKey(); - assertNotNull("Should be the first US state", subkey); - LookupKey usFirstStateKey = - new LookupKey.Builder(usKey.toString() + "/" + subkey).build(); - - assertNotNull(clientData.get(usKey.toString())); - assertNotNull(clientData.get(usFirstStateKey.toString())); - assertNull(clientData.get(badKey.toString())); - finishTest(); - } - }); - } - - public void testRequestDataForCountry() { - final FormController controller = new FormController(clientData, "en", "US"); - - delayTestFinish(15000); - - controller.requestDataForAddress(US_ADDRESS, new DataLoadListener() { - boolean beginCalled = false; - @Override - public void dataLoadingBegin() { - beginCalled = true; - } - - @Override - public void dataLoadingEnd() { - assertTrue("dataLoadingBegin should be called before dataLoadingEnd", - beginCalled); - LookupKey usKey = new LookupKey.Builder(KeyType.DATA) - .setAddressData(US_ADDRESS).build(); - assertNotNull("key should be data/US", usKey); - List rdata = controller.getRegionData(usKey); - assertTrue(rdata.size() > 0); - String subkey = rdata.get(0).getKey(); - assertNotNull("Should be the first US state", subkey); - LookupKey usFirstStateKey = - new LookupKey.Builder(usKey.toString() + "/" + subkey).build(); - assertNotNull(clientData.get(usKey.toString())); - assertNotNull(clientData.get(usFirstStateKey.toString())); - finishTest(); - } - }); - } + private static final AddressData US_CA_ADDRESS; + private static final AddressData US_ADDRESS; + private ClientData clientData; + + static { + US_CA_ADDRESS = new AddressData.Builder().setCountry("US") + .setAdminArea("CA") + .setLocality("Mt View") + .setAddressLine1("1098 Alta Ave") + .setPostalCode("94043") + .build(); + US_ADDRESS = new AddressData.Builder().setCountry("US").build(); + } + + @Override + public void setUp() { + clientData = new ClientData(new CacheData()); + } + + public void testRequestDataForAddress() { + final FormController controller = new FormController(clientData, "en", "US"); + + delayTestFinish(15000); + + controller.requestDataForAddress(US_CA_ADDRESS, new DataLoadListener() { + boolean beginCalled = false; + @Override + public void dataLoadingBegin() { + beginCalled = true; + } + + @Override + public void dataLoadingEnd() { + assertTrue("dataLoadingBegin should be called before dataLoadingEnd", + beginCalled); + LookupKey usCaMtvKey = new LookupKey.Builder(KeyType.DATA) + .setAddressData(US_CA_ADDRESS).build(); + LookupKey usKey = usCaMtvKey.getKeyForUpperLevelField( + AddressField.COUNTRY); + LookupKey usCaKey = usCaMtvKey.getKeyForUpperLevelField( + AddressField.ADMIN_AREA); + assertNotNull("key should be data/US/CA", usCaKey); + assertNotNull("key should be data/US/CA/Mt View", usCaMtvKey); + assertNotNull(clientData.get(usKey.toString())); + assertNotNull(clientData.get(usCaKey.toString())); + assertNull(clientData.get(usCaMtvKey.toString())); + finishTest(); + } + }); + } + + public void testRequestDataForBadAddress() { + final AddressData address = new AddressData.Builder(US_CA_ADDRESS) + .setAdminArea("FOOBAR") + .setLocality("KarKar") + .build(); + + final FormController controller = new FormController(clientData, "en", "US"); + + delayTestFinish(15000); + + controller.requestDataForAddress(address, new DataLoadListener() { + boolean beginCalled = false; + @Override + public void dataLoadingBegin() { + beginCalled = true; + } + + @Override + public void dataLoadingEnd() { + assertTrue("dataLoadingBegin should be called before dataLoadingEnd", + beginCalled); + LookupKey badKey = new LookupKey.Builder(KeyType.DATA) + .setAddressData(address).build(); + LookupKey usKey = badKey.getKeyForUpperLevelField(AddressField.COUNTRY); + + List rdata = controller.getRegionData(usKey); + assertTrue(rdata.size() > 0); + String subkey = rdata.get(0).getKey(); + assertNotNull("Should be the first US state", subkey); + LookupKey usFirstStateKey = + new LookupKey.Builder(usKey.toString() + "/" + subkey).build(); + + assertNotNull(clientData.get(usKey.toString())); + assertNotNull(clientData.get(usFirstStateKey.toString())); + assertNull(clientData.get(badKey.toString())); + finishTest(); + } + }); + } + + public void testRequestDataForCountry() { + final FormController controller = new FormController(clientData, "en", "US"); + + delayTestFinish(15000); + + controller.requestDataForAddress(US_ADDRESS, new DataLoadListener() { + boolean beginCalled = false; + @Override + public void dataLoadingBegin() { + beginCalled = true; + } + + @Override + public void dataLoadingEnd() { + assertTrue("dataLoadingBegin should be called before dataLoadingEnd", + beginCalled); + LookupKey usKey = new LookupKey.Builder(KeyType.DATA) + .setAddressData(US_ADDRESS).build(); + assertNotNull("key should be data/US", usKey); + List rdata = controller.getRegionData(usKey); + assertTrue(rdata.size() > 0); + String subkey = rdata.get(0).getKey(); + assertNotNull("Should be the first US state", subkey); + LookupKey usFirstStateKey = + new LookupKey.Builder(usKey.toString() + "/" + subkey).build(); + assertNotNull(clientData.get(usKey.toString())); + assertNotNull(clientData.get(usFirstStateKey.toString())); + finishTest(); + } + }); + } } diff --git a/java/test/com/android/i18n/addressinput/FormOptionsTest.java b/java/test/com/android/i18n/addressinput/FormOptionsTest.java index 5f8e8c3..5e4fc6e 100644 --- a/java/test/com/android/i18n/addressinput/FormOptionsTest.java +++ b/java/test/com/android/i18n/addressinput/FormOptionsTest.java @@ -22,23 +22,23 @@ import junit.framework.TestCase; * Test for building form options. */ public class FormOptionsTest extends TestCase { - public void testRequiredField() throws Exception { - FormOptions options = new FormOptions.Builder().required(AddressField.COUNTRY).build(); - assertTrue(options.isRequired(AddressField.COUNTRY)); - assertFalse(options.isRequired(AddressField.LOCALITY)); - assertTrue(options.getRequiredFields().contains(AddressField.COUNTRY)); - assertFalse(options.getRequiredFields().contains(AddressField.LOCALITY)); - } + public void testRequiredField() throws Exception { + FormOptions options = new FormOptions.Builder().required(AddressField.COUNTRY).build(); + assertTrue(options.isRequired(AddressField.COUNTRY)); + assertFalse(options.isRequired(AddressField.LOCALITY)); + assertTrue(options.getRequiredFields().contains(AddressField.COUNTRY)); + assertFalse(options.getRequiredFields().contains(AddressField.LOCALITY)); + } - public void testReadonlyField() throws Exception { - FormOptions options = new FormOptions.Builder().readonly(AddressField.COUNTRY).build(); - assertTrue(options.isReadonly(AddressField.COUNTRY)); - assertFalse(options.isReadonly(AddressField.LOCALITY)); - } + public void testReadonlyField() throws Exception { + FormOptions options = new FormOptions.Builder().readonly(AddressField.COUNTRY).build(); + assertTrue(options.isReadonly(AddressField.COUNTRY)); + assertFalse(options.isReadonly(AddressField.LOCALITY)); + } - public void testHiddenField() throws Exception { - FormOptions options = new FormOptions.Builder().hide(AddressField.COUNTRY).build(); - assertTrue(options.isHidden(AddressField.COUNTRY)); - assertFalse(options.isHidden(AddressField.LOCALITY)); - } + public void testHiddenField() throws Exception { + FormOptions options = new FormOptions.Builder().hide(AddressField.COUNTRY).build(); + assertTrue(options.isHidden(AddressField.COUNTRY)); + assertFalse(options.isHidden(AddressField.LOCALITY)); + } } diff --git a/java/test/com/android/i18n/addressinput/FormatInterpreterTest.java b/java/test/com/android/i18n/addressinput/FormatInterpreterTest.java index f5bac79..3efd37b 100644 --- a/java/test/com/android/i18n/addressinput/FormatInterpreterTest.java +++ b/java/test/com/android/i18n/addressinput/FormatInterpreterTest.java @@ -27,206 +27,206 @@ import junit.framework.TestCase; * Tests for the FormatInterpreter class. */ public class FormatInterpreterTest extends TestCase { - private static final AddressData US_CA_ADDRESS; - private static final AddressData TW_ADDRESS; - - private FormatInterpreter formatInterpreter; - - static { - US_CA_ADDRESS = new AddressData.Builder().setCountry("US") - .setAdminArea("CA") - .setLocality("Mt View") - .setAddressLine1("1098 Alta Ave") - .setPostalCode("94043") - .build(); - - TW_ADDRESS = new AddressData.Builder().setCountry("TW") - .setAdminArea("\u53F0\u5317\u5E02") // Taipei city - .setLocality("\u5927\u5B89\u5340") // Da-an district - .setAddressLine1("Sec. 3 Hsin-yi Rd.") - .setPostalCode("106") - .setOrganization("Giant Bike Store") - .setRecipient("Mr. Liu") - .build(); - } + private static final AddressData US_CA_ADDRESS; + private static final AddressData TW_ADDRESS; + + private FormatInterpreter formatInterpreter; + + static { + US_CA_ADDRESS = new AddressData.Builder().setCountry("US") + .setAdminArea("CA") + .setLocality("Mt View") + .setAddressLine1("1098 Alta Ave") + .setPostalCode("94043") + .build(); + + TW_ADDRESS = new AddressData.Builder().setCountry("TW") + .setAdminArea("\u53F0\u5317\u5E02") // Taipei city + .setLocality("\u5927\u5B89\u5340") // Da-an district + .setAddressLine1("Sec. 3 Hsin-yi Rd.") + .setPostalCode("106") + .setOrganization("Giant Bike Store") + .setRecipient("Mr. Liu") + .build(); + } - @Override - public void setUp() { - formatInterpreter = new FormatInterpreter(new FormOptions.Builder().build()); - } + @Override + public void setUp() { + formatInterpreter = new FormatInterpreter(new FormOptions.Builder().build()); + } - public void testIterateUsAddressFields() { - AddressField[] format = { - AddressField.RECIPIENT, - AddressField.ORGANIZATION, - AddressField.ADDRESS_LINE_1, - AddressField.ADDRESS_LINE_2, - AddressField.LOCALITY, - AddressField.ADMIN_AREA, - AddressField.POSTAL_CODE - }; - - int currIndex = 0; - for (AddressField field : formatInterpreter.getAddressFieldOrder(ScriptType.LOCAL, "US")) { - assertEquals("index " + currIndex + " should have matched", - format[currIndex].getChar(), field.getChar()); - currIndex++; - } + public void testIterateUsAddressFields() { + AddressField[] format = { + AddressField.RECIPIENT, + AddressField.ORGANIZATION, + AddressField.ADDRESS_LINE_1, + AddressField.ADDRESS_LINE_2, + AddressField.LOCALITY, + AddressField.ADMIN_AREA, + AddressField.POSTAL_CODE + }; + + int currIndex = 0; + for (AddressField field : formatInterpreter.getAddressFieldOrder(ScriptType.LOCAL, "US")) { + assertEquals("index " + currIndex + " should have matched", + format[currIndex].getChar(), field.getChar()); + currIndex++; } + } - /** - * Tests that this works for the case of Vanuatu, since we have no country-specific formatting - * data for that country. Should fall back to the default region. - */ - public void testIterateVuAddressFields() { - AddressField[] format = { - AddressField.RECIPIENT, - AddressField.ORGANIZATION, - AddressField.ADDRESS_LINE_1, - AddressField.ADDRESS_LINE_2, - AddressField.LOCALITY, - }; - - int currIndex = 0; - for (AddressField field : formatInterpreter.getAddressFieldOrder(ScriptType.LOCAL, "VU")) { - assertEquals("index " + currIndex + " should have matched", - format[currIndex].getChar(), field.getChar()); - currIndex++; - } + /** + * Tests that this works for the case of Vanuatu, since we have no country-specific formatting + * data for that country. Should fall back to the default region. + */ + public void testIterateVuAddressFields() { + AddressField[] format = { + AddressField.RECIPIENT, + AddressField.ORGANIZATION, + AddressField.ADDRESS_LINE_1, + AddressField.ADDRESS_LINE_2, + AddressField.LOCALITY, + }; + + int currIndex = 0; + for (AddressField field : formatInterpreter.getAddressFieldOrder(ScriptType.LOCAL, "VU")) { + assertEquals("index " + currIndex + " should have matched", + format[currIndex].getChar(), field.getChar()); + currIndex++; } + } - public void testOverrideFieldOrder() { - AddressField[] expectedOrder = { - AddressField.ADMIN_AREA, - AddressField.ORGANIZATION, - AddressField.ADDRESS_LINE_1, - AddressField.ADDRESS_LINE_2, - AddressField.LOCALITY, - AddressField.RECIPIENT, - AddressField.POSTAL_CODE - }; - - FormatInterpreter myInterpreter = new FormatInterpreter( - new FormOptions.Builder().customizeFieldOrder("US", - AddressField.ADMIN_AREA, - AddressField.RECIPIENT, - AddressField.SORTING_CODE, - AddressField.POSTAL_CODE).build()); - - int currIndex = 0; - for (AddressField field : myInterpreter.getAddressFieldOrder(ScriptType.LOCAL, "US")) { - assertEquals("Wrong field order for US on index " + currIndex + " of address fields.", - expectedOrder[currIndex], field); - - // Sorting code (CEDEX) is not in US address format and should be - // neglected even if it is specified in customizeFieldOrder(). - assertNotSame(AddressField.SORTING_CODE, field); - currIndex++; - } + public void testOverrideFieldOrder() { + AddressField[] expectedOrder = { + AddressField.ADMIN_AREA, + AddressField.ORGANIZATION, + AddressField.ADDRESS_LINE_1, + AddressField.ADDRESS_LINE_2, + AddressField.LOCALITY, + AddressField.RECIPIENT, + AddressField.POSTAL_CODE + }; + + FormatInterpreter myInterpreter = new FormatInterpreter( + new FormOptions.Builder().customizeFieldOrder("US", + AddressField.ADMIN_AREA, + AddressField.RECIPIENT, + AddressField.SORTING_CODE, + AddressField.POSTAL_CODE).build()); + + int currIndex = 0; + for (AddressField field : myInterpreter.getAddressFieldOrder(ScriptType.LOCAL, "US")) { + assertEquals("Wrong field order for US on index " + currIndex + " of address fields.", + expectedOrder[currIndex], field); + + // Sorting code (CEDEX) is not in US address format and should be + // neglected even if it is specified in customizeFieldOrder(). + assertNotSame(AddressField.SORTING_CODE, field); + currIndex++; } + } - public void testIterateTwLatinAddressFields() { - AddressField[] format = { - AddressField.RECIPIENT, - AddressField.ORGANIZATION, - AddressField.ADDRESS_LINE_1, - AddressField.ADDRESS_LINE_2, - AddressField.LOCALITY, - AddressField.ADMIN_AREA, - AddressField.POSTAL_CODE - }; - - int currIndex = 0; - for (AddressField field : formatInterpreter.getAddressFieldOrder(ScriptType.LATIN, "TW")) { - assertEquals("Unexpected field order -- mismatched on index " + currIndex, - format[currIndex].getChar(), field.getChar()); - currIndex++; - } + public void testIterateTwLatinAddressFields() { + AddressField[] format = { + AddressField.RECIPIENT, + AddressField.ORGANIZATION, + AddressField.ADDRESS_LINE_1, + AddressField.ADDRESS_LINE_2, + AddressField.LOCALITY, + AddressField.ADMIN_AREA, + AddressField.POSTAL_CODE + }; + + int currIndex = 0; + for (AddressField field : formatInterpreter.getAddressFieldOrder(ScriptType.LATIN, "TW")) { + assertEquals("Unexpected field order -- mismatched on index " + currIndex, + format[currIndex].getChar(), field.getChar()); + currIndex++; } + } - public void testUsEnvelopeAddress() { - List expected = new ArrayList(); - expected.add("1098 Alta Ave"); - expected.add("Mt View, CA 94043"); + public void testUsEnvelopeAddress() { + List expected = new ArrayList(); + expected.add("1098 Alta Ave"); + expected.add("Mt View, CA 94043"); - List real = formatInterpreter.getEnvelopeAddress(US_CA_ADDRESS); + List real = formatInterpreter.getEnvelopeAddress(US_CA_ADDRESS); - assertEquals(expected, real); - } + assertEquals(expected, real); + } - public void testTwEnvelopeAddress() { - // To be in this order, the whole address should really be in Traditional Chinese - for - // readability, only the neighbourhood and city are. - List expected = new ArrayList(); - expected.add("106"); - expected.add("\u53F0\u5317\u5E02\u5927\u5B89\u5340"); // Taipei city, Da-an district - expected.add("Sec. 3 Hsin-yi Rd."); - expected.add("Giant Bike Store"); - expected.add("Mr. Liu"); + public void testTwEnvelopeAddress() { + // To be in this order, the whole address should really be in Traditional Chinese - for + // readability, only the neighbourhood and city are. + List expected = new ArrayList(); + expected.add("106"); + expected.add("\u53F0\u5317\u5E02\u5927\u5B89\u5340"); // Taipei city, Da-an district + expected.add("Sec. 3 Hsin-yi Rd."); + expected.add("Giant Bike Store"); + expected.add("Mr. Liu"); - List real = formatInterpreter.getEnvelopeAddress(TW_ADDRESS); + List real = formatInterpreter.getEnvelopeAddress(TW_ADDRESS); - assertEquals(expected, real); - } + assertEquals(expected, real); + } - public void testEnvelopeAddressIncompleteAddress() { - List expected = new ArrayList(); - expected.add("1098 Alta Ave"); - expected.add("CA 94043"); + public void testEnvelopeAddressIncompleteAddress() { + List expected = new ArrayList(); + expected.add("1098 Alta Ave"); + expected.add("CA 94043"); - AddressData address = new AddressData.Builder().set(US_CA_ADDRESS) - .set(AddressField.LOCALITY, null).build(); + AddressData address = new AddressData.Builder().set(US_CA_ADDRESS) + .set(AddressField.LOCALITY, null).build(); - List real = formatInterpreter.getEnvelopeAddress(address); + List real = formatInterpreter.getEnvelopeAddress(address); - assertEquals(expected, real); - } + assertEquals(expected, real); + } - public void testEnvelopeAddressEmptyAddress() { - List expected = new ArrayList(); - AddressData address = new AddressData.Builder().setCountry("US").build(); + public void testEnvelopeAddressEmptyAddress() { + List expected = new ArrayList(); + AddressData address = new AddressData.Builder().setCountry("US").build(); - List real = formatInterpreter.getEnvelopeAddress(address); - assertEquals(expected, real); - } + List real = formatInterpreter.getEnvelopeAddress(address); + assertEquals(expected, real); + } public void testEnvelopeAddressLeadingPostPrefix() { - List expected = new ArrayList(); - expected.add("CH-8047 Herrliberg"); - AddressData address = new AddressData.Builder().setCountry("CH") - .setPostalCode("8047") - .setLocality("Herrliberg") - .build(); - - List real = formatInterpreter.getEnvelopeAddress(address); - assertEquals(expected, real); + List expected = new ArrayList(); + expected.add("CH-8047 Herrliberg"); + AddressData address = new AddressData.Builder().setCountry("CH") + .setPostalCode("8047") + .setLocality("Herrliberg") + .build(); + + List real = formatInterpreter.getEnvelopeAddress(address); + assertEquals(expected, real); } public void testSvAddress() { - final AddressData svAddress = new AddressData.Builder().setCountry("SV") - .setAdminArea("Ahuachapán") - .setLocality("Ahuachapán") - .setAddressLine1("Some Street 12") - .build(); - - List expected = new ArrayList(); - expected.add("Some Street 12"); - expected.add("Ahuachapán"); - expected.add("Ahuachapán"); - - List real = formatInterpreter.getEnvelopeAddress(svAddress); - assertEquals(expected, real); - - final AddressData svAddressWithPostCode = new AddressData.Builder(svAddress) - .setPostalCode("CP 2101") - .build(); - - expected = new ArrayList(); - expected.add("Some Street 12"); - expected.add("CP 2101-Ahuachapán"); - expected.add("Ahuachapán"); - - real = formatInterpreter.getEnvelopeAddress(svAddressWithPostCode); - assertEquals(expected, real); + final AddressData svAddress = new AddressData.Builder().setCountry("SV") + .setAdminArea("Ahuachapán") + .setLocality("Ahuachapán") + .setAddressLine1("Some Street 12") + .build(); + + List expected = new ArrayList(); + expected.add("Some Street 12"); + expected.add("Ahuachapán"); + expected.add("Ahuachapán"); + + List real = formatInterpreter.getEnvelopeAddress(svAddress); + assertEquals(expected, real); + + final AddressData svAddressWithPostCode = new AddressData.Builder(svAddress) + .setPostalCode("CP 2101") + .build(); + + expected = new ArrayList(); + expected.add("Some Street 12"); + expected.add("CP 2101-Ahuachapán"); + expected.add("Ahuachapán"); + + real = formatInterpreter.getEnvelopeAddress(svAddressWithPostCode); + assertEquals(expected, real); } } diff --git a/java/test/com/android/i18n/addressinput/JsoMapTest.java b/java/test/com/android/i18n/addressinput/JsoMapTest.java index 76bcbed..56e4d1e 100644 --- a/java/test/com/android/i18n/addressinput/JsoMapTest.java +++ b/java/test/com/android/i18n/addressinput/JsoMapTest.java @@ -30,218 +30,218 @@ import java.util.Set; */ public class JsoMapTest extends TestCase { - private static final String VALID_JSON = "{\"a\":\"b\",\"c\":1,\"d\":{\"e\":\"f\"}}"; - private static final String INVALID_JSON = "!"; - - public void testBuildJsoMap() throws Exception { - assertNotNull(JsoMap.buildJsoMap(VALID_JSON)); - - try { - JsoMap.buildJsoMap(INVALID_JSON); - fail("Expected JSONException."); - } catch (JSONException e) { - // Expected. - } - } - - public void testCreateEmptyJsoMap() throws Exception { - assertNotNull(JsoMap.createEmptyJsoMap()); - } + private static final String VALID_JSON = "{\"a\":\"b\",\"c\":1,\"d\":{\"e\":\"f\"}}"; + private static final String INVALID_JSON = "!"; - public void testDelKey() throws Exception { - JsoMap map = JsoMap.buildJsoMap(VALID_JSON); + public void testBuildJsoMap() throws Exception { + assertNotNull(JsoMap.buildJsoMap(VALID_JSON)); - assertEquals("b", map.get("a")); - map.delKey("a"); - assertNull(map.get("a")); - - map.delKey("b"); - map.delKey("c"); - map.delKey("d"); + try { + JsoMap.buildJsoMap(INVALID_JSON); + fail("Expected JSONException."); + } catch (JSONException e) { + // Expected. } - - public void testGet() throws Exception { - JsoMap map = JsoMap.buildJsoMap(VALID_JSON); - assertEquals("b", map.get("a")); - assertNull(map.get("b")); - - try { - map.get("c"); - fail("Expected IllegalArgumentException."); - } catch (IllegalArgumentException e) { - // Expected. - } - - try { - map.get("d"); - fail("Expected ClassCastException."); - } catch (ClassCastException e) { - // Expected. - } + } + + public void testCreateEmptyJsoMap() throws Exception { + assertNotNull(JsoMap.createEmptyJsoMap()); + } + + public void testDelKey() throws Exception { + JsoMap map = JsoMap.buildJsoMap(VALID_JSON); + + assertEquals("b", map.get("a")); + map.delKey("a"); + assertNull(map.get("a")); + + map.delKey("b"); + map.delKey("c"); + map.delKey("d"); + } + + public void testGet() throws Exception { + JsoMap map = JsoMap.buildJsoMap(VALID_JSON); + assertEquals("b", map.get("a")); + assertNull(map.get("b")); + + try { + map.get("c"); + fail("Expected IllegalArgumentException."); + } catch (IllegalArgumentException e) { + // Expected. } - public void testGetInt() throws Exception { - JsoMap map = JsoMap.buildJsoMap(VALID_JSON); - - try { - map.getInt("a"); - fail("Expected RuntimeException."); - } catch (RuntimeException e) { - // Expected. - } - - assertEquals(-1, map.getInt("b")); - assertEquals(1, map.getInt("c")); - - try { - map.getInt("d"); - fail("Expected RuntimeException."); - } catch (RuntimeException e) { - // Expected. - } + try { + map.get("d"); + fail("Expected ClassCastException."); + } catch (ClassCastException e) { + // Expected. } + } - public void testGetKeys() throws Exception { - JsoMap map = JsoMap.buildJsoMap(VALID_JSON); - JSONArray keys = map.getKeys(); - assertNotNull(keys); - assertEquals(3, keys.length()); - Set keySet = new HashSet(keys.length()); - for (int i = 0; i < keys.length(); i++) { - keySet.add(keys.getString(i)); - } - assertEquals(new HashSet(Arrays.asList("a", "c", "d")), keySet); - } - - public void testGetObj() throws Exception { - JsoMap map = JsoMap.buildJsoMap(VALID_JSON); + public void testGetInt() throws Exception { + JsoMap map = JsoMap.buildJsoMap(VALID_JSON); - try { - map.getObj("a"); - fail("Expected ClassCastException."); - } catch (ClassCastException e) { - // Expected. - } - - assertNull(map.getObj("b")); + try { + map.getInt("a"); + fail("Expected RuntimeException."); + } catch (RuntimeException e) { + // Expected. + } - try { - map.getObj("c"); - fail("Expected IllegalArgumentException."); - } catch (IllegalArgumentException e) { - // Expected. - } + assertEquals(-1, map.getInt("b")); + assertEquals(1, map.getInt("c")); - JsoMap obj = map.getObj("d"); - assertNotNull(obj); - assertEquals("f", obj.get("e")); + try { + map.getInt("d"); + fail("Expected RuntimeException."); + } catch (RuntimeException e) { + // Expected. } - - public void testContainsKey() throws Exception { - JsoMap map = JsoMap.buildJsoMap(VALID_JSON); - assertTrue(map.containsKey("a")); - assertFalse(map.containsKey("b")); - assertTrue(map.containsKey("c")); - assertTrue(map.containsKey("d")); + } + + public void testGetKeys() throws Exception { + JsoMap map = JsoMap.buildJsoMap(VALID_JSON); + JSONArray keys = map.getKeys(); + assertNotNull(keys); + assertEquals(3, keys.length()); + Set keySet = new HashSet(keys.length()); + for (int i = 0; i < keys.length(); i++) { + keySet.add(keys.getString(i)); } + assertEquals(new HashSet(Arrays.asList("a", "c", "d")), keySet); + } - public void testMergeData() throws Exception { - JsoMap mapA = JsoMap.createEmptyJsoMap(); - JsoMap mapB = JsoMap.createEmptyJsoMap(); - - mapA.putInt("a", 1); - mapA.putInt("b", 2); - - mapB.putInt("b", 3); - mapB.putInt("c", 4); + public void testGetObj() throws Exception { + JsoMap map = JsoMap.buildJsoMap(VALID_JSON); - mapA.mergeData(mapB); - assertEquals(1, mapA.getInt("a")); - assertEquals(2, mapA.getInt("b")); - assertEquals(4, mapA.getInt("c")); + try { + map.getObj("a"); + fail("Expected ClassCastException."); + } catch (ClassCastException e) { + // Expected. } - public void testPut() throws Exception { - JsoMap map = JsoMap.createEmptyJsoMap(); + assertNull(map.getObj("b")); - map.put("a", "b"); - assertEquals("b", map.get("a")); - - map.put("a", "c"); - assertEquals("c", map.get("a")); + try { + map.getObj("c"); + fail("Expected IllegalArgumentException."); + } catch (IllegalArgumentException e) { + // Expected. } - public void testPutInt() throws Exception { - JsoMap map = JsoMap.createEmptyJsoMap(); - - map.putInt("a", 1); - assertEquals(1, map.getInt("a")); - - map.putInt("a", 2); - assertEquals(2, map.getInt("a")); + JsoMap obj = map.getObj("d"); + assertNotNull(obj); + assertEquals("f", obj.get("e")); + } + + public void testContainsKey() throws Exception { + JsoMap map = JsoMap.buildJsoMap(VALID_JSON); + assertTrue(map.containsKey("a")); + assertFalse(map.containsKey("b")); + assertTrue(map.containsKey("c")); + assertTrue(map.containsKey("d")); + } + + public void testMergeData() throws Exception { + JsoMap mapA = JsoMap.createEmptyJsoMap(); + JsoMap mapB = JsoMap.createEmptyJsoMap(); + + mapA.putInt("a", 1); + mapA.putInt("b", 2); + + mapB.putInt("b", 3); + mapB.putInt("c", 4); + + mapA.mergeData(mapB); + assertEquals(1, mapA.getInt("a")); + assertEquals(2, mapA.getInt("b")); + assertEquals(4, mapA.getInt("c")); + } + + public void testPut() throws Exception { + JsoMap map = JsoMap.createEmptyJsoMap(); + + map.put("a", "b"); + assertEquals("b", map.get("a")); + + map.put("a", "c"); + assertEquals("c", map.get("a")); + } + + public void testPutInt() throws Exception { + JsoMap map = JsoMap.createEmptyJsoMap(); + + map.putInt("a", 1); + assertEquals(1, map.getInt("a")); + + map.putInt("a", 2); + assertEquals(2, map.getInt("a")); + } + + public void testPutObj() throws Exception { + JsoMap map = JsoMap.createEmptyJsoMap(); + JsoMap obj = JsoMap.createEmptyJsoMap(); + + obj.putInt("a", 1); + map.putObj("b", obj); + assertEquals(obj.toString(), map.getObj("b").toString()); + + obj.putInt("a", 2); + map.putObj("b", obj); + assertEquals(obj.toString(), map.getObj("b").toString()); + } + + public void testString() throws Exception { + JsoMap map = JsoMap.buildJsoMap(VALID_JSON); + + try { + // This should fail on the integer "c" or the map "d". + map.string(); + fail("Expected IllegalArgumentException."); + } catch (IllegalArgumentException e) { + // Expected. + } catch (ClassCastException e) { + // Expected. } - public void testPutObj() throws Exception { - JsoMap map = JsoMap.createEmptyJsoMap(); - JsoMap obj = JsoMap.createEmptyJsoMap(); - - obj.putInt("a", 1); - map.putObj("b", obj); - assertEquals(obj.toString(), map.getObj("b").toString()); - - obj.putInt("a", 2); - map.putObj("b", obj); - assertEquals(obj.toString(), map.getObj("b").toString()); + map.delKey("c"); + try { + // This should fail on the object "d". + map.string(); + fail("Expected ClassCastException."); + } catch (ClassCastException e) { + // Expected. } - public void testString() throws Exception { - JsoMap map = JsoMap.buildJsoMap(VALID_JSON); - - try { - // This should fail on the integer "c" or the map "d". - map.string(); - fail("Expected IllegalArgumentException."); - } catch (IllegalArgumentException e) { - // Expected. - } catch (ClassCastException e) { - // Expected. - } - - map.delKey("c"); - try { - // This should fail on the object "d". - map.string(); - fail("Expected ClassCastException."); - } catch (ClassCastException e) { - // Expected. - } - - map.delKey("d"); - assertEquals("JsoMap[\n(a:b)\n]", map.string()); + map.delKey("d"); + assertEquals("JsoMap[\n(a:b)\n]", map.string()); + } + + public void testMap() throws Exception { + JsoMap map = JsoMap.buildJsoMap(VALID_JSON); + try { + // This should fail on the string "a" or the integer "c". + map.map(); + fail("Expected ClassCastException."); + } catch (ClassCastException e) { + // Expected. + } catch (IllegalArgumentException e) { + // Expected. } - public void testMap() throws Exception { - JsoMap map = JsoMap.buildJsoMap(VALID_JSON); - try { - // This should fail on the string "a" or the integer "c". - map.map(); - fail("Expected ClassCastException."); - } catch (ClassCastException e) { - // Expected. - } catch (IllegalArgumentException e) { - // Expected. - } - - map.delKey("a"); - try { - // This should fail on the integer "c". - map.map(); - fail("Expected IllegalArgumentException."); - } catch (IllegalArgumentException e) { - // Expected. - } - - map.delKey("c"); - assertEquals("JsoMap[\n(d:JsoMap[\n(e:f)\n])\n]", map.map()); + map.delKey("a"); + try { + // This should fail on the integer "c". + map.map(); + fail("Expected IllegalArgumentException."); + } catch (IllegalArgumentException e) { + // Expected. } + + map.delKey("c"); + assertEquals("JsoMap[\n(d:JsoMap[\n(e:f)\n])\n]", map.map()); + } } diff --git a/java/test/com/android/i18n/addressinput/JsonpRequestBuilderTest.java b/java/test/com/android/i18n/addressinput/JsonpRequestBuilderTest.java index 392a68e..9a40d1a 100644 --- a/java/test/com/android/i18n/addressinput/JsonpRequestBuilderTest.java +++ b/java/test/com/android/i18n/addressinput/JsonpRequestBuilderTest.java @@ -27,131 +27,131 @@ import java.net.Socket; import java.net.SocketTimeoutException; public class JsonpRequestBuilderTest extends AsyncTestCase { - private JsonpRequestBuilder builder; - - @Override - public void setUp() { - builder = new JsonpRequestBuilder(); - } - - public void testRequestObject() throws Exception { - delayTestFinish(4000); - builder.setTimeout(2000); - - String url = HttpServer.execute(1000, "{\"id\": \"data\"}"); - - builder.requestObject(url, new AsyncCallback() { - @Override - public void onFailure(Throwable caught) { - fail(caught.toString()); - } - - @Override - public void onSuccess(JsoMap result) { - assertNotNull(result); - assertEquals("data", result.get("id")); - finishTest(); - } - }); - } - - public void testSetTimeout() throws Exception { - delayTestFinish(4000); - builder.setTimeout(1000); - - String url = HttpServer.execute(2000, "Fubar"); - - builder.requestObject(url, new AsyncCallback() { - @Override - public void onFailure(Throwable caught) { - assertNotNull(caught); - assertTrue(caught instanceof SocketTimeoutException); - finishTest(); - } - - @Override - public void onSuccess(JsoMap result) { - fail("The request should have timed out."); - } - }); - } - - public void testUrlEncoding() throws Exception { - delayTestFinish(4000); - builder.setTimeout(2000); - - String urlBase = HttpServer.execute(1000, "{\"id\": \"data\"}"); - String url = urlBase + "address/data/VN/B\u1EAFc K\u1EA1n"; - - builder.requestObject(url, new AsyncCallback() { - @Override - public void onFailure(Throwable caught) { - fail(caught.toString()); - } - - @Override - public void onSuccess(JsoMap result) { - assertNotNull(result); - assertEquals("data", result.get("id")); - finishTest(); - } - }); - } - + private JsonpRequestBuilder builder; + + @Override + public void setUp() { + builder = new JsonpRequestBuilder(); + } + + public void testRequestObject() throws Exception { + delayTestFinish(4000); + builder.setTimeout(2000); + + String url = HttpServer.execute(1000, "{\"id\": \"data\"}"); + + builder.requestObject(url, new AsyncCallback() { + @Override + public void onFailure(Throwable caught) { + fail(caught.toString()); + } + + @Override + public void onSuccess(JsoMap result) { + assertNotNull(result); + assertEquals("data", result.get("id")); + finishTest(); + } + }); + } + + public void testSetTimeout() throws Exception { + delayTestFinish(4000); + builder.setTimeout(1000); + + String url = HttpServer.execute(2000, "Fubar"); + + builder.requestObject(url, new AsyncCallback() { + @Override + public void onFailure(Throwable caught) { + assertNotNull(caught); + assertTrue(caught instanceof SocketTimeoutException); + finishTest(); + } + + @Override + public void onSuccess(JsoMap result) { + fail("The request should have timed out."); + } + }); + } + + public void testUrlEncoding() throws Exception { + delayTestFinish(4000); + builder.setTimeout(2000); + + String urlBase = HttpServer.execute(1000, "{\"id\": \"data\"}"); + String url = urlBase + "address/data/VN/B\u1EAFc K\u1EA1n"; + + builder.requestObject(url, new AsyncCallback() { + @Override + public void onFailure(Throwable caught) { + fail(caught.toString()); + } + + @Override + public void onSuccess(JsoMap result) { + assertNotNull(result); + assertEquals("data", result.get("id")); + finishTest(); + } + }); + } + + /** + * Simple implementation of an HTTP server. + */ + private static class HttpServer extends Thread { /** - * Simple implementation of an HTTP server. + * Start an HTTP server that will serve one request and then terminate. + * + * @param timeoutMillis + * Wait this long before answering a request. + * @param response + * Reply to any request with this response. + * @return The URL to the server. + * @throws IOException */ - private static class HttpServer extends Thread { - /** - * Start an HTTP server that will serve one request and then terminate. - * - * @param timeoutMillis - * Wait this long before answering a request. - * @param response - * Reply to any request with this response. - * @return The URL to the server. - * @throws IOException - */ - public static String execute(long timeoutMillis, String response) throws IOException { - HttpServer server = new HttpServer(timeoutMillis, response); - server.start(); - return "http://localhost:" + server.serverSocket.getLocalPort() + "/"; - } + public static String execute(long timeoutMillis, String response) throws IOException { + HttpServer server = new HttpServer(timeoutMillis, response); + server.start(); + return "http://localhost:" + server.serverSocket.getLocalPort() + "/"; + } - @Override - public void run() { - try { - Socket clientSocket = serverSocket.accept(); - try { - synchronized (this) { - wait(waitMillis); - } - } catch (InterruptedException e) { - throw new RuntimeException(e); - } - InputStream inputStream = clientSocket.getInputStream(); - inputStream.read(new byte[1024]); // Discard input. - OutputStream outputStream = clientSocket.getOutputStream(); - outputStream.write(response); - outputStream.close(); - inputStream.close(); - clientSocket.close(); - serverSocket.close(); - } catch (IOException e) { - throw new RuntimeException(e); - } + @Override + public void run() { + try { + Socket clientSocket = serverSocket.accept(); + try { + synchronized (this) { + wait(waitMillis); + } + } catch (InterruptedException e) { + throw new RuntimeException(e); } + InputStream inputStream = clientSocket.getInputStream(); + inputStream.read(new byte[1024]); // Discard input. + OutputStream outputStream = clientSocket.getOutputStream(); + outputStream.write(response); + outputStream.close(); + inputStream.close(); + clientSocket.close(); + serverSocket.close(); + } catch (IOException e) { + throw new RuntimeException(e); + } + } - private HttpServer(long waitMillis, String response) throws IOException { - this.waitMillis = waitMillis; - this.response = (header + response).getBytes(); - serverSocket = new ServerSocket(0); - } + private HttpServer(long waitMillis, String response) throws IOException { + this.waitMillis = waitMillis; + this.response = (header + response).getBytes(); + serverSocket = new ServerSocket(0); + } - private long waitMillis; - private byte[] response; - private ServerSocket serverSocket; + private long waitMillis; + private byte[] response; + private ServerSocket serverSocket; - private static final String header = "HTTP/1.0 200 OK\nContent-Type: text/plain\n\n"; - } + private static final String header = "HTTP/1.0 200 OK\nContent-Type: text/plain\n\n"; + } } diff --git a/java/test/com/android/i18n/addressinput/LookupKeyTest.java b/java/test/com/android/i18n/addressinput/LookupKeyTest.java index 608e076..fa07618 100644 --- a/java/test/com/android/i18n/addressinput/LookupKeyTest.java +++ b/java/test/com/android/i18n/addressinput/LookupKeyTest.java @@ -27,211 +27,211 @@ import junit.framework.TestCase; * Unit tests for the LookupKey class. */ public class LookupKeyTest extends TestCase { - private static final String ROOT_KEY = "data"; - private static final String ROOT_EXAMPLE_KEY = "examples"; - private static final String US_KEY = "data/US"; - private static final String CALIFORNIA_KEY = "data/US/CA"; - private static final String EXAMPLE_LOCAL_US_KEY = "examples/US/local/_default"; - - // Data key for Da-an District, Taipei Taiwan - private static final String TW_KEY = "data/TW/\u53F0\u5317\u5E02/\u5927\u5B89\u5340"; - - // Example key for TW's address (local script) - private static final String TW_EXAMPLE_LOCAL_KEY = "examples/TW/local/_default"; - - // Example key for TW's address (latin script) - private static final String TW_EXAMPLE_LATIN_KEY = "examples/TW/latin/_default"; - - private static final String RANDOM_KEY = "sdfIisooIFOOBAR"; - private static final String RANDOM_COUNTRY_KEY = "data/asIOSDxcowW"; - - public void testRootKey() { - LookupKey key = new LookupKey.Builder(KeyType.DATA).build(); - assertEquals(ROOT_KEY, key.toString()); - - LookupKey key2 = new LookupKey.Builder(key.toString()).build(); - assertEquals(ROOT_KEY, key2.toString()); + private static final String ROOT_KEY = "data"; + private static final String ROOT_EXAMPLE_KEY = "examples"; + private static final String US_KEY = "data/US"; + private static final String CALIFORNIA_KEY = "data/US/CA"; + private static final String EXAMPLE_LOCAL_US_KEY = "examples/US/local/_default"; + + // Data key for Da-an District, Taipei Taiwan + private static final String TW_KEY = "data/TW/\u53F0\u5317\u5E02/\u5927\u5B89\u5340"; + + // Example key for TW's address (local script) + private static final String TW_EXAMPLE_LOCAL_KEY = "examples/TW/local/_default"; + + // Example key for TW's address (latin script) + private static final String TW_EXAMPLE_LATIN_KEY = "examples/TW/latin/_default"; + + private static final String RANDOM_KEY = "sdfIisooIFOOBAR"; + private static final String RANDOM_COUNTRY_KEY = "data/asIOSDxcowW"; + + public void testRootKey() { + LookupKey key = new LookupKey.Builder(KeyType.DATA).build(); + assertEquals(ROOT_KEY, key.toString()); + + LookupKey key2 = new LookupKey.Builder(key.toString()).build(); + assertEquals(ROOT_KEY, key2.toString()); + } + + public void testDataKeys() { + LookupKey key = new LookupKey.Builder(US_KEY).build(); + assertEquals(US_KEY, key.toString()); + + LookupKey key2 = new LookupKey.Builder(CALIFORNIA_KEY).build(); + assertEquals(CALIFORNIA_KEY, key2.toString()); + } + + public void testExampleRootKeys() { + LookupKey key = new LookupKey.Builder(KeyType.EXAMPLES).build(); + assertEquals(ROOT_EXAMPLE_KEY, key.toString()); + } + + public void testExampleKeys() { + AddressData address = new AddressData.Builder().setCountry("US") + .setLanguageCode("en") + .build(); + + LookupKey key = new LookupKey.Builder(KeyType.EXAMPLES).setAddressData(address).build(); + assertEquals(EXAMPLE_LOCAL_US_KEY, key.toString()); + + key = new LookupKey.Builder(EXAMPLE_LOCAL_US_KEY).build(); + assertEquals(EXAMPLE_LOCAL_US_KEY, key.toString()); + } + + public void testKeyWithWrongScriptType() { + String wrongScript = "examples/US/asdfasdfasdf/_default"; + try { + new LookupKey.Builder(wrongScript).build(); + fail("should fail since the script type is wrong"); + } catch (RuntimeException e) { + // Expected. } - - public void testDataKeys() { - LookupKey key = new LookupKey.Builder(US_KEY).build(); - assertEquals(US_KEY, key.toString()); - - LookupKey key2 = new LookupKey.Builder(CALIFORNIA_KEY).build(); - assertEquals(CALIFORNIA_KEY, key2.toString()); - } - - public void testExampleRootKeys() { - LookupKey key = new LookupKey.Builder(KeyType.EXAMPLES).build(); - assertEquals(ROOT_EXAMPLE_KEY, key.toString()); + } + + public void testFallbackToCountry() { + // Admin Area is missing. + AddressData address = new AddressData.Builder().setCountry("US") + .setLocality("Mt View") + .build(); + + LookupKey key = new LookupKey.Builder(KeyType.DATA).setAddressData(address).build(); + + assertEquals("locality should be omitted since admin area is not specified", US_KEY, + key.toString()); + + // Tries key string with the same problem (missing Admin Area). + key = new LookupKey.Builder("data/US//Mt View").build(); + + assertEquals("locality should be omitted since admin area is not specified", US_KEY, + key.toString()); + } + + public void testNonUsAddress() { + AddressData address = new AddressData.Builder().setCountry("TW") + // Taipei City + .setAdminArea("\u53F0\u5317\u5E02") + // Da-an District + .setLocality("\u5927\u5B89\u5340") + .build(); + + LookupKey key = new LookupKey.Builder(KeyType.DATA).setAddressData(address).build(); + assertEquals(TW_KEY, key.toString()); + + key = new LookupKey.Builder(KeyType.EXAMPLES).setAddressData(address).build(); + assertEquals(TW_EXAMPLE_LOCAL_KEY, key.toString()); + + address = new AddressData.Builder(address).setLanguageCode("zh-latn").build(); + key = new LookupKey.Builder(KeyType.EXAMPLES).setAddressData(address).build(); + assertEquals(TW_EXAMPLE_LATIN_KEY, key.toString()); + } + + public void testGetKeyForUpperLevelFieldWithDataKey() { + AddressData address = new AddressData.Builder().setCountry("US") + .setAdminArea("CA") + .setLocality("Mt View") + .build(); + + LookupKey key = new LookupKey.Builder(KeyType.DATA).setAddressData(address).build(); + LookupKey newKey = key.getKeyForUpperLevelField(AddressField.COUNTRY); + assertNotNull("failed to get key for " + AddressField.COUNTRY, newKey); + assertEquals("data/US", newKey.toString()); + + newKey = key.getKeyForUpperLevelField(AddressField.ADMIN_AREA); + assertNotNull("failed to get key for " + AddressField.ADMIN_AREA, newKey); + assertEquals("data/US/CA", newKey.toString()); + assertEquals("original key should not be changed", "data/US/CA/Mt View", key.toString()); + + newKey = key.getKeyForUpperLevelField(AddressField.LOCALITY); + assertNotNull("failed to get key for " + AddressField.LOCALITY, newKey); + assertEquals("data/US/CA/Mt View", newKey.toString()); + + newKey = key.getKeyForUpperLevelField(AddressField.DEPENDENT_LOCALITY); + assertNull("should return null for field not contained in current key", newKey); + + newKey = key.getKeyForUpperLevelField(AddressField.RECIPIENT); + assertNull("should return null since field '" + AddressField.RECIPIENT + + "' is not in address hierarchy", newKey); + } + + public void testGetKeyForUpperLevelFieldWithExampleKey() { + LookupKey key = new LookupKey.Builder("examples/US/latin/_default").build(); + + try { + key.getKeyForUpperLevelField(AddressField.COUNTRY); + fail("should fail if you try to get parent key for an example key."); + } catch (RuntimeException e) { + // Expected. } + } - public void testExampleKeys() { - AddressData address = new AddressData.Builder().setCountry("US") - .setLanguageCode("en") - .build(); + public void testGetParentKey() { + AddressData address = new AddressData.Builder().setCountry("US") + .setAdminArea("CA") + .setLocality("Mt View") + .setDependentLocality("El Camino") + .build(); - LookupKey key = new LookupKey.Builder(KeyType.EXAMPLES).setAddressData(address).build(); - assertEquals(EXAMPLE_LOCAL_US_KEY, key.toString()); + LookupKey key = new LookupKey.Builder(KeyType.DATA).setAddressData(address).build(); + assertEquals("data/US/CA/Mt View/El Camino", key.toString()); - key = new LookupKey.Builder(EXAMPLE_LOCAL_US_KEY).build(); - assertEquals(EXAMPLE_LOCAL_US_KEY, key.toString()); - } + key = key.getParentKey(); + assertEquals("data/US/CA/Mt View", key.toString()); - public void testKeyWithWrongScriptType() { - String wrongScript = "examples/US/asdfasdfasdf/_default"; - try { - new LookupKey.Builder(wrongScript).build(); - fail("should fail since the script type is wrong"); - } catch (RuntimeException e) { - // Expected. - } - } + key = key.getParentKey(); + assertEquals("data/US/CA", key.toString()); - public void testFallbackToCountry() { - // Admin Area is missing. - AddressData address = new AddressData.Builder().setCountry("US") - .setLocality("Mt View") - .build(); + key = key.getParentKey(); + assertEquals("data/US", key.toString()); - LookupKey key = new LookupKey.Builder(KeyType.DATA).setAddressData(address).build(); + key = key.getParentKey(); + assertEquals("data", key.toString()); - assertEquals("locality should be omitted since admin area is not specified", US_KEY, - key.toString()); + key = key.getParentKey(); + assertNull("root key's parent should be null", key); + } - // Tries key string with the same problem (missing Admin Area). - key = new LookupKey.Builder("data/US//Mt View").build(); - - assertEquals("locality should be omitted since admin area is not specified", US_KEY, - key.toString()); - } - - public void testNonUsAddress() { - AddressData address = new AddressData.Builder().setCountry("TW") - // Taipei City - .setAdminArea("\u53F0\u5317\u5E02") - // Da-an District - .setLocality("\u5927\u5B89\u5340") - .build(); - - LookupKey key = new LookupKey.Builder(KeyType.DATA).setAddressData(address).build(); - assertEquals(TW_KEY, key.toString()); - - key = new LookupKey.Builder(KeyType.EXAMPLES).setAddressData(address).build(); - assertEquals(TW_EXAMPLE_LOCAL_KEY, key.toString()); - - address = new AddressData.Builder(address).setLanguageCode("zh-latn").build(); - key = new LookupKey.Builder(KeyType.EXAMPLES).setAddressData(address).build(); - assertEquals(TW_EXAMPLE_LATIN_KEY, key.toString()); + public void testInvalidKeyTypeWillFail() { + try { + new LookupKey.Builder(RANDOM_KEY).build(); + fail("Should fail if key string does not start with a valid key type"); + } catch (RuntimeException e) { + // Expected. } - - public void testGetKeyForUpperLevelFieldWithDataKey() { - AddressData address = new AddressData.Builder().setCountry("US") - .setAdminArea("CA") - .setLocality("Mt View") - .build(); - - LookupKey key = new LookupKey.Builder(KeyType.DATA).setAddressData(address).build(); - LookupKey newKey = key.getKeyForUpperLevelField(AddressField.COUNTRY); - assertNotNull("failed to get key for " + AddressField.COUNTRY, newKey); - assertEquals("data/US", newKey.toString()); - - newKey = key.getKeyForUpperLevelField(AddressField.ADMIN_AREA); - assertNotNull("failed to get key for " + AddressField.ADMIN_AREA, newKey); - assertEquals("data/US/CA", newKey.toString()); - assertEquals("original key should not be changed", "data/US/CA/Mt View", key.toString()); - - newKey = key.getKeyForUpperLevelField(AddressField.LOCALITY); - assertNotNull("failed to get key for " + AddressField.LOCALITY, newKey); - assertEquals("data/US/CA/Mt View", newKey.toString()); - - newKey = key.getKeyForUpperLevelField(AddressField.DEPENDENT_LOCALITY); - assertNull("should return null for field not contained in current key", newKey); - - newKey = key.getKeyForUpperLevelField(AddressField.RECIPIENT); - assertNull("should return null since field '" + AddressField.RECIPIENT + - "' is not in address hierarchy", newKey); - } - - public void testGetKeyForUpperLevelFieldWithExampleKey() { - LookupKey key = new LookupKey.Builder("examples/US/latin/_default").build(); - - try { - key.getKeyForUpperLevelField(AddressField.COUNTRY); - fail("should fail if you try to get parent key for an example key."); - } catch (RuntimeException e) { - // Expected. - } - } - - public void testGetParentKey() { - AddressData address = new AddressData.Builder().setCountry("US") - .setAdminArea("CA") - .setLocality("Mt View") - .setDependentLocality("El Camino") - .build(); - - LookupKey key = new LookupKey.Builder(KeyType.DATA).setAddressData(address).build(); - assertEquals("data/US/CA/Mt View/El Camino", key.toString()); - - key = key.getParentKey(); - assertEquals("data/US/CA/Mt View", key.toString()); - - key = key.getParentKey(); - assertEquals("data/US/CA", key.toString()); - - key = key.getParentKey(); - assertEquals("data/US", key.toString()); - - key = key.getParentKey(); - assertEquals("data", key.toString()); - - key = key.getParentKey(); - assertNull("root key's parent should be null", key); - } - - public void testInvalidKeyTypeWillFail() { - try { - new LookupKey.Builder(RANDOM_KEY).build(); - fail("Should fail if key string does not start with a valid key type"); - } catch (RuntimeException e) { - // Expected. - } - } - - /** - * Ensures that even when the input key string is random, we still create a key. (We do not - * verify if the key maps to an real world entity like a city or country). - */ - public void testWeDontVerifyKeyName() { - LookupKey key = new LookupKey.Builder(RANDOM_COUNTRY_KEY).build(); - assertEquals(RANDOM_COUNTRY_KEY, key.toString()); - } - - public void testHash() { - String keys[] = { ROOT_KEY, ROOT_EXAMPLE_KEY, US_KEY, CALIFORNIA_KEY }; - Map map = new HashMap(); - - for (String key : keys) { - map.put(new LookupKey.Builder(key).build(), key); - } - - for (String key : keys) { - assertTrue(map.containsKey(new LookupKey.Builder(key).build())); - assertEquals(key, map.get(new LookupKey.Builder(key).build())); - } - assertFalse(map.containsKey(new LookupKey.Builder(RANDOM_COUNTRY_KEY).build())); - } - - public void testGetValueForUpperLevelField() { - LookupKey key = new LookupKey.Builder("data/US/CA").build(); - assertEquals("US", key.getValueForUpperLevelField(AddressField.COUNTRY)); + } + + /** + * Ensures that even when the input key string is random, we still create a key. (We do not + * verify if the key maps to an real world entity like a city or country). + */ + public void testWeDontVerifyKeyName() { + LookupKey key = new LookupKey.Builder(RANDOM_COUNTRY_KEY).build(); + assertEquals(RANDOM_COUNTRY_KEY, key.toString()); + } + + public void testHash() { + String keys[] = { ROOT_KEY, ROOT_EXAMPLE_KEY, US_KEY, CALIFORNIA_KEY }; + Map map = new HashMap(); + + for (String key : keys) { + map.put(new LookupKey.Builder(key).build(), key); } - public void testGetValueForUpperLevelFieldInvalid() { - LookupKey key = new LookupKey.Builder("data").build(); - assertEquals("", key.getValueForUpperLevelField(AddressField.COUNTRY)); - LookupKey key2 = new LookupKey.Builder("data/").build(); - assertEquals("", key2.getValueForUpperLevelField(AddressField.COUNTRY)); + for (String key : keys) { + assertTrue(map.containsKey(new LookupKey.Builder(key).build())); + assertEquals(key, map.get(new LookupKey.Builder(key).build())); } + assertFalse(map.containsKey(new LookupKey.Builder(RANDOM_COUNTRY_KEY).build())); + } + + public void testGetValueForUpperLevelField() { + LookupKey key = new LookupKey.Builder("data/US/CA").build(); + assertEquals("US", key.getValueForUpperLevelField(AddressField.COUNTRY)); + } + + public void testGetValueForUpperLevelFieldInvalid() { + LookupKey key = new LookupKey.Builder("data").build(); + assertEquals("", key.getValueForUpperLevelField(AddressField.COUNTRY)); + LookupKey key2 = new LookupKey.Builder("data/").build(); + assertEquals("", key2.getValueForUpperLevelField(AddressField.COUNTRY)); + } } diff --git a/java/test/com/android/i18n/addressinput/RegionDataConstantsTest.java b/java/test/com/android/i18n/addressinput/RegionDataConstantsTest.java index f623146..d268c5f 100644 --- a/java/test/com/android/i18n/addressinput/RegionDataConstantsTest.java +++ b/java/test/com/android/i18n/addressinput/RegionDataConstantsTest.java @@ -23,22 +23,22 @@ import junit.framework.TestCase; * and converted into the appropriate format. */ public class RegionDataConstantsTest extends TestCase { - public void testDataLoad() throws Exception { - assertFalse("The list of countries should not be empty", - RegionDataConstants.getCountryFormatMap().isEmpty()); - } + public void testDataLoad() throws Exception { + assertFalse("The list of countries should not be empty", + RegionDataConstants.getCountryFormatMap().isEmpty()); + } - public void testZZRegion() throws Exception { - assertNotNull("Data for 'ZZ' is missing (needed for default region info.)", - RegionDataConstants.getCountryFormatMap().get("ZZ")); - } + public void testZZRegion() throws Exception { + assertNotNull("Data for 'ZZ' is missing (needed for default region info.)", + RegionDataConstants.getCountryFormatMap().get("ZZ")); + } - public void testStringsAreConvertedIntoJson() throws Exception { - String[] input = { "key", "value", "key2", "value2" }; - // Input order is not maintained, since we build this using JSON objects. This is - // unimportant, so long as the key-value mappings are maintained. - String expectedOutput = "{\"key2\":\"value2\",\"key\":\"value\"}"; - String actualOutput = RegionDataConstants.convertArrayToJsonString(input); - assertEquals(expectedOutput, actualOutput); - } + public void testStringsAreConvertedIntoJson() throws Exception { + String[] input = { "key", "value", "key2", "value2" }; + // Input order is not maintained, since we build this using JSON objects. This is + // unimportant, so long as the key-value mappings are maintained. + String expectedOutput = "{\"key2\":\"value2\",\"key\":\"value\"}"; + String actualOutput = RegionDataConstants.convertArrayToJsonString(input); + assertEquals(expectedOutput, actualOutput); + } } diff --git a/java/test/com/android/i18n/addressinput/RegionDataTest.java b/java/test/com/android/i18n/addressinput/RegionDataTest.java index 547f934..4731e4d 100644 --- a/java/test/com/android/i18n/addressinput/RegionDataTest.java +++ b/java/test/com/android/i18n/addressinput/RegionDataTest.java @@ -22,28 +22,28 @@ import junit.framework.TestCase; * Small unit tests for the RegionData class. */ public class RegionDataTest extends TestCase { - public void testBuilder() throws Exception { - RegionData data = new RegionData.Builder().setKey("CA").setName("California").build(); - assertEquals("CA", data.getKey()); - assertEquals("California", data.getName()); - assertTrue(data.isValidName("CA")); - // Should match either the key or the name. - assertTrue(data.isValidName("California")); - // Matching should be case-insensitive. - assertTrue(data.isValidName("ca")); - assertFalse(data.isValidName("Cat")); - } + public void testBuilder() throws Exception { + RegionData data = new RegionData.Builder().setKey("CA").setName("California").build(); + assertEquals("CA", data.getKey()); + assertEquals("California", data.getName()); + assertTrue(data.isValidName("CA")); + // Should match either the key or the name. + assertTrue(data.isValidName("California")); + // Matching should be case-insensitive. + assertTrue(data.isValidName("ca")); + assertFalse(data.isValidName("Cat")); + } - public void testBuilderNoName() throws Exception { - RegionData data = new RegionData.Builder().setKey("CA").build(); - assertEquals("CA", data.getKey()); - assertEquals(null, data.getName()); - } + public void testBuilderNoName() throws Exception { + RegionData data = new RegionData.Builder().setKey("CA").build(); + assertEquals("CA", data.getKey()); + assertEquals(null, data.getName()); + } - public void testBuilderWhitespaceName() throws Exception { - RegionData data = new RegionData.Builder().setKey("CA").setName(" ").build(); - assertEquals("CA", data.getKey()); - assertEquals(null, data.getName()); - assertEquals("CA", data.getDisplayName()); - } + public void testBuilderWhitespaceName() throws Exception { + RegionData data = new RegionData.Builder().setKey("CA").setName(" ").build(); + assertEquals("CA", data.getKey()); + assertEquals(null, data.getName()); + assertEquals("CA", data.getDisplayName()); + } } diff --git a/java/test/com/android/i18n/addressinput/StandardAddressVerifierTest.java b/java/test/com/android/i18n/addressinput/StandardAddressVerifierTest.java index 1949608..f47e64f 100644 --- a/java/test/com/android/i18n/addressinput/StandardAddressVerifierTest.java +++ b/java/test/com/android/i18n/addressinput/StandardAddressVerifierTest.java @@ -23,235 +23,235 @@ import junit.framework.TestCase; */ public class StandardAddressVerifierTest extends TestCase { - private AddressProblems problems = new AddressProblems(); - private StandardAddressVerifier verifier; - - @Override - protected void setUp() { - problems.clear(); - verifier = new StandardAddressVerifier(new FieldVerifier(new ClientData(new CacheData())), - StandardChecks.PROBLEM_MAP); - } - - public void testUnitedStatesOk() { - AddressData addr = new AddressData.Builder().setCountry("US") - .setAdminArea("CA") - .setLocality("Mountain View") - .setAddress("1234 Somewhere") - .setPostalCode("94025") - .build(); - verifier.verify(addr, problems); - assertTrue(problems.toString(), problems.isEmpty()); // no mismatch - } - - public void testUnitedStatesZipMismatch() { - AddressData addr = new AddressData.Builder().setCountry("US") - .setAdminArea("CA") - .setLocality("Mountain View") - .setPostalCode("12345") - .build(); - verifier.verify(addr, problems); - - assertEquals(AddressProblemType.MISMATCHING_VALUE, - problems.getProblem(AddressField.POSTAL_CODE)); - } - - public void testUnitedStatesNotOk() { - AddressData addr = new AddressData.Builder().setCountry("US") - .setAdminArea("CA") - .setLocality(null) - .setDependentLocality("Foo Bar") - .setPostalCode("12345") - .build(); - verifier.verify(addr, problems); - - assertEquals(AddressProblemType.MISMATCHING_VALUE, - problems.getProblem(AddressField.POSTAL_CODE)); - assertEquals(AddressProblemType.MISSING_REQUIRED_FIELD, - problems.getProblem(AddressField.LOCALITY)); - } - - public void testChinaOk() { - AddressData addr = new AddressData.Builder().setCountry("CN") - .setAdminArea("Beijing Shi") - .setLocality("Xicheng Qu") - .setAddress("Yitiao Lu") - .setPostalCode("123456") - .build(); - verifier.verify(addr, problems); - assertTrue(problems.toString(), problems.isEmpty()); - } - - public void testGermanAddress() { - AddressData addr = new AddressData.Builder().setCountry("DE") - .setLocality("Berlin") - .setAddress("Huttenstr. 50") - .setPostalCode("10553") - .setOrganization("BMW AG Niederkassung Berlin") - .setRecipient("Herr Diefendorf") - .build(); - - verifier.verify(addr, problems); - assertTrue(problems.toString(), problems.isEmpty()); - - // Clones address but leave city empty. - addr = new AddressData.Builder().set(addr).setLocality(null).build(); - - verifier.verify(addr, problems); - assertEquals(AddressProblemType.MISSING_REQUIRED_FIELD, - problems.getProblem(AddressField.LOCALITY)); - } - - public void testIrishAddress() { - AddressData addr = new AddressData.Builder().setCountry("IE") - .setLocality("Dublin") - .setAdminArea("Co. Dublin") - .setAddress("7424 118 Avenue NW") - .setRecipient("Conan O'Brien") - .build(); - - verifier.verify(addr, problems); - assertTrue(problems.toString(), problems.isEmpty()); - - // Clones address but leave county empty. This address should be valid - // since county is not required. - addr = new AddressData.Builder().set(addr).setAdminArea(null).build(); - - verifier.verify(addr, problems); - assertTrue(problems.toString(), problems.isEmpty()); - } - - public void testChinaPostalCodeBadFormat() { - AddressData addr = new AddressData.Builder().setCountry("CN") - .setAdminArea("Beijing Shi") - .setLocality("Xicheng Qu") - .setPostalCode("12345") - .build(); - verifier.verify(addr, problems); - - // ensure problem is unrecognized format and problem is in POSTAL_CODE - assertEquals(AddressProblemType.UNRECOGNIZED_FORMAT, - problems.getProblem(AddressField.POSTAL_CODE)); - } - - /** - * If there is a postal code pattern for a certain country, and the input postal code is empty, - * it should not be reported as bad postal code format. Whether an empty postal code is ok - * should be determined by checks for required fields. - */ - public void testEmptyPostalCodeReportedAsGoodFormat() { - // Chilean address has a postal code format pattern, but does not require - // postal code. The following address is valid. - AddressData addr = new AddressData.Builder().setCountry("CL") - .setAddressLine1("GUSTAVO LE PAIGE ST #159") - .setAdminArea("Atacama") - .setLocality("Alto del Carmen") - .setPostalCode("") - .build(); - verifier.verify(addr, problems); - assertTrue(problems.toString(), problems.isEmpty()); - - problems.clear(); - - // Now checks for US addresses, which requires postal code. The following - // address's postal code is wrong because it misses required field, not - // because it mismatches expected postal code pattern. - addr = new AddressData.Builder().setCountry("US").setPostalCode("").build(); - problems.clear(); - verifier.verify(addr, problems); - - assertEquals(AddressProblemType.MISSING_REQUIRED_FIELD, - problems.getProblem(AddressField.POSTAL_CODE)); - } - - public void testChinaTaiwanOk() { - AddressData addr = new AddressData.Builder().setCountry("CN") - .setAdminArea("Taiwan") - .setLocality("Taichung City") - .setDependentLocality("Situn District") - .setAddress("12345 Yitiao Lu") - .setPostalCode("407") - .build(); - verifier.verify(addr, problems); - assertTrue(problems.toString(), problems.isEmpty()); - } - - public void testChinaTaiwanUnknownDistrict() { - AddressData addr = new AddressData.Builder().setCountry("CN") - .setAdminArea("Taiwan") - .setLocality("Taichung City") - .setDependentLocality("Foo Bar") - .setPostalCode("400") - .build(); - verifier.verify(addr, problems); - - assertEquals(AddressProblemType.UNKNOWN_VALUE, - problems.getProblem(AddressField.DEPENDENT_LOCALITY)); - } - - public void testStreetVerification() { - // missing street address - AddressData addr = new AddressData.Builder().setCountry("US") - .setAdminArea("CA") - .setLocality("Mountain View") - .setPostalCode("94025") - .build(); - - assertNull(addr.getAddressLine1()); - assertNull(addr.getAddressLine2()); - - verifier.verify(addr, problems); - - assertEquals(AddressProblemType.MISSING_REQUIRED_FIELD, - problems.getProblem(AddressField.STREET_ADDRESS)); - } - - // Tests The Bahamas' address - public void failingtestBahamas() { - final AddressData address = - new AddressData.Builder().setAddress("Abaco Beach Resort & Boat Habour") - .setLocality("Treasure Cay") - .setAdminArea("Abaco") - .setCountry("BS") - .build(); - verifier.verify(address, problems); - assertTrue(problems.toString(), problems.isEmpty()); - } - - public void testJapan() { - // added AdminArea since address verification can't infer it from Kyoto City - // commented out dependent locality since address verification doesn't use it - // TODO: support inference of higher levels from lower ones - // TODO: add dependent locality support for japan addresses - final AddressData address = - new AddressData.Builder() - .setRecipient("\u5BAE\u672C \u8302") // SHIGERU_MIYAMOTO - .setAddress("\u4E0A\u9CE5\u7FBD\u927E\u7ACB\u753A11\u756A\u5730") - .setAdminArea("\u4eac\u90fd\u5e9c") // Kyoto prefecture, added - .setLocality("\u4EAC\u90FD\u5E02") // Kyoto city - // .setDependentLocality("\u5357\u533A") - .setCountry("JP") - .setPostalCode("601-8501") - .build(); - verifier.verify(address, problems); - assertTrue(problems.toString(), problems.isEmpty()); - } - - public void testJapanLatin() { - // added AdminArea since address verification can't infer it from Kyoto City - // commented out dependent locality since address verification doesn't use it - final AddressData address = - new AddressData.Builder() - .setRecipient("Shigeru Miyamoto") // SHIGERU_MIYAMOTO_ENGLISH - .setAddress("11-1 Kamitoba-hokotate-cho") - .setAdminArea("KYOTO") // Kyoto prefecture, added - .setLocality("Kyoto") // Kyoto city - // .setDependentLocality("Minami-ku") - .setLanguageCode("ja_Latn") - .setCountry("JP") - .setPostalCode("601-8501") - .build(); - verifier.verify(address, problems); - assertTrue(problems.toString(), problems.isEmpty()); - } + private AddressProblems problems = new AddressProblems(); + private StandardAddressVerifier verifier; + + @Override + protected void setUp() { + problems.clear(); + verifier = new StandardAddressVerifier(new FieldVerifier(new ClientData(new CacheData())), + StandardChecks.PROBLEM_MAP); + } + + public void testUnitedStatesOk() { + AddressData addr = new AddressData.Builder().setCountry("US") + .setAdminArea("CA") + .setLocality("Mountain View") + .setAddress("1234 Somewhere") + .setPostalCode("94025") + .build(); + verifier.verify(addr, problems); + assertTrue(problems.toString(), problems.isEmpty()); // no mismatch + } + + public void testUnitedStatesZipMismatch() { + AddressData addr = new AddressData.Builder().setCountry("US") + .setAdminArea("CA") + .setLocality("Mountain View") + .setPostalCode("12345") + .build(); + verifier.verify(addr, problems); + + assertEquals(AddressProblemType.MISMATCHING_VALUE, + problems.getProblem(AddressField.POSTAL_CODE)); + } + + public void testUnitedStatesNotOk() { + AddressData addr = new AddressData.Builder().setCountry("US") + .setAdminArea("CA") + .setLocality(null) + .setDependentLocality("Foo Bar") + .setPostalCode("12345") + .build(); + verifier.verify(addr, problems); + + assertEquals(AddressProblemType.MISMATCHING_VALUE, + problems.getProblem(AddressField.POSTAL_CODE)); + assertEquals(AddressProblemType.MISSING_REQUIRED_FIELD, + problems.getProblem(AddressField.LOCALITY)); + } + + public void testChinaOk() { + AddressData addr = new AddressData.Builder().setCountry("CN") + .setAdminArea("Beijing Shi") + .setLocality("Xicheng Qu") + .setAddress("Yitiao Lu") + .setPostalCode("123456") + .build(); + verifier.verify(addr, problems); + assertTrue(problems.toString(), problems.isEmpty()); + } + + public void testGermanAddress() { + AddressData addr = new AddressData.Builder().setCountry("DE") + .setLocality("Berlin") + .setAddress("Huttenstr. 50") + .setPostalCode("10553") + .setOrganization("BMW AG Niederkassung Berlin") + .setRecipient("Herr Diefendorf") + .build(); + + verifier.verify(addr, problems); + assertTrue(problems.toString(), problems.isEmpty()); + + // Clones address but leave city empty. + addr = new AddressData.Builder().set(addr).setLocality(null).build(); + + verifier.verify(addr, problems); + assertEquals(AddressProblemType.MISSING_REQUIRED_FIELD, + problems.getProblem(AddressField.LOCALITY)); + } + + public void testIrishAddress() { + AddressData addr = new AddressData.Builder().setCountry("IE") + .setLocality("Dublin") + .setAdminArea("Co. Dublin") + .setAddress("7424 118 Avenue NW") + .setRecipient("Conan O'Brien") + .build(); + + verifier.verify(addr, problems); + assertTrue(problems.toString(), problems.isEmpty()); + + // Clones address but leave county empty. This address should be valid + // since county is not required. + addr = new AddressData.Builder().set(addr).setAdminArea(null).build(); + + verifier.verify(addr, problems); + assertTrue(problems.toString(), problems.isEmpty()); + } + + public void testChinaPostalCodeBadFormat() { + AddressData addr = new AddressData.Builder().setCountry("CN") + .setAdminArea("Beijing Shi") + .setLocality("Xicheng Qu") + .setPostalCode("12345") + .build(); + verifier.verify(addr, problems); + + // ensure problem is unrecognized format and problem is in POSTAL_CODE + assertEquals(AddressProblemType.UNRECOGNIZED_FORMAT, + problems.getProblem(AddressField.POSTAL_CODE)); + } + + /** + * If there is a postal code pattern for a certain country, and the input postal code is empty, + * it should not be reported as bad postal code format. Whether an empty postal code is ok + * should be determined by checks for required fields. + */ + public void testEmptyPostalCodeReportedAsGoodFormat() { + // Chilean address has a postal code format pattern, but does not require + // postal code. The following address is valid. + AddressData addr = new AddressData.Builder().setCountry("CL") + .setAddressLine1("GUSTAVO LE PAIGE ST #159") + .setAdminArea("Atacama") + .setLocality("Alto del Carmen") + .setPostalCode("") + .build(); + verifier.verify(addr, problems); + assertTrue(problems.toString(), problems.isEmpty()); + + problems.clear(); + + // Now checks for US addresses, which requires postal code. The following + // address's postal code is wrong because it misses required field, not + // because it mismatches expected postal code pattern. + addr = new AddressData.Builder().setCountry("US").setPostalCode("").build(); + problems.clear(); + verifier.verify(addr, problems); + + assertEquals(AddressProblemType.MISSING_REQUIRED_FIELD, + problems.getProblem(AddressField.POSTAL_CODE)); + } + + public void testChinaTaiwanOk() { + AddressData addr = new AddressData.Builder().setCountry("CN") + .setAdminArea("Taiwan") + .setLocality("Taichung City") + .setDependentLocality("Situn District") + .setAddress("12345 Yitiao Lu") + .setPostalCode("407") + .build(); + verifier.verify(addr, problems); + assertTrue(problems.toString(), problems.isEmpty()); + } + + public void testChinaTaiwanUnknownDistrict() { + AddressData addr = new AddressData.Builder().setCountry("CN") + .setAdminArea("Taiwan") + .setLocality("Taichung City") + .setDependentLocality("Foo Bar") + .setPostalCode("400") + .build(); + verifier.verify(addr, problems); + + assertEquals(AddressProblemType.UNKNOWN_VALUE, + problems.getProblem(AddressField.DEPENDENT_LOCALITY)); + } + + public void testStreetVerification() { + // missing street address + AddressData addr = new AddressData.Builder().setCountry("US") + .setAdminArea("CA") + .setLocality("Mountain View") + .setPostalCode("94025") + .build(); + + assertNull(addr.getAddressLine1()); + assertNull(addr.getAddressLine2()); + + verifier.verify(addr, problems); + + assertEquals(AddressProblemType.MISSING_REQUIRED_FIELD, + problems.getProblem(AddressField.STREET_ADDRESS)); + } + + // Tests The Bahamas' address + public void failingtestBahamas() { + final AddressData address = + new AddressData.Builder().setAddress("Abaco Beach Resort & Boat Habour") + .setLocality("Treasure Cay") + .setAdminArea("Abaco") + .setCountry("BS") + .build(); + verifier.verify(address, problems); + assertTrue(problems.toString(), problems.isEmpty()); + } + + public void testJapan() { + // added AdminArea since address verification can't infer it from Kyoto City + // commented out dependent locality since address verification doesn't use it + // TODO: support inference of higher levels from lower ones + // TODO: add dependent locality support for japan addresses + final AddressData address = + new AddressData.Builder() + .setRecipient("\u5BAE\u672C \u8302") // SHIGERU_MIYAMOTO + .setAddress("\u4E0A\u9CE5\u7FBD\u927E\u7ACB\u753A11\u756A\u5730") + .setAdminArea("\u4eac\u90fd\u5e9c") // Kyoto prefecture, added + .setLocality("\u4EAC\u90FD\u5E02") // Kyoto city + // .setDependentLocality("\u5357\u533A") + .setCountry("JP") + .setPostalCode("601-8501") + .build(); + verifier.verify(address, problems); + assertTrue(problems.toString(), problems.isEmpty()); + } + + public void testJapanLatin() { + // added AdminArea since address verification can't infer it from Kyoto City + // commented out dependent locality since address verification doesn't use it + final AddressData address = + new AddressData.Builder() + .setRecipient("Shigeru Miyamoto") // SHIGERU_MIYAMOTO_ENGLISH + .setAddress("11-1 Kamitoba-hokotate-cho") + .setAdminArea("KYOTO") // Kyoto prefecture, added + .setLocality("Kyoto") // Kyoto city + // .setDependentLocality("Minami-ku") + .setLanguageCode("ja_Latn") + .setCountry("JP") + .setPostalCode("601-8501") + .build(); + verifier.verify(address, problems); + assertTrue(problems.toString(), problems.isEmpty()); + } } diff --git a/java/test/com/android/i18n/addressinput/UtilTest.java b/java/test/com/android/i18n/addressinput/UtilTest.java index d552062..73a7956 100644 --- a/java/test/com/android/i18n/addressinput/UtilTest.java +++ b/java/test/com/android/i18n/addressinput/UtilTest.java @@ -26,129 +26,129 @@ import java.util.Map; */ public class UtilTest extends TestCase { - public void testIsExplicitLatinScript() throws Exception { - // Should recognise Latin script in a variety of forms. - assertTrue(Util.isExplicitLatinScript("zh-Latn")); - assertTrue(Util.isExplicitLatinScript("ja_LATN")); - assertTrue(Util.isExplicitLatinScript("und_LATN")); - assertTrue(Util.isExplicitLatinScript("ja_LATN-JP")); - assertTrue(Util.isExplicitLatinScript("ko-latn_JP")); - } + public void testIsExplicitLatinScript() throws Exception { + // Should recognise Latin script in a variety of forms. + assertTrue(Util.isExplicitLatinScript("zh-Latn")); + assertTrue(Util.isExplicitLatinScript("ja_LATN")); + assertTrue(Util.isExplicitLatinScript("und_LATN")); + assertTrue(Util.isExplicitLatinScript("ja_LATN-JP")); + assertTrue(Util.isExplicitLatinScript("ko-latn_JP")); + } - public void testIsExplicitLatinScriptNonLatin() throws Exception { - assertFalse(Util.isExplicitLatinScript("ko")); - assertFalse(Util.isExplicitLatinScript("KO")); - assertFalse(Util.isExplicitLatinScript("ja")); - assertFalse(Util.isExplicitLatinScript("ja-JP")); - assertFalse(Util.isExplicitLatinScript("zh-Hans")); - assertFalse(Util.isExplicitLatinScript("zh-Hans-CN")); - assertFalse(Util.isExplicitLatinScript("zh-Hant")); - assertFalse(Util.isExplicitLatinScript("zh-TW")); - assertFalse(Util.isExplicitLatinScript("zh_TW")); - assertFalse(Util.isExplicitLatinScript("ko")); - assertFalse(Util.isExplicitLatinScript("ko_KR")); - assertFalse(Util.isExplicitLatinScript("en")); - assertFalse(Util.isExplicitLatinScript("EN")); - assertFalse(Util.isExplicitLatinScript("ru")); - } + public void testIsExplicitLatinScriptNonLatin() throws Exception { + assertFalse(Util.isExplicitLatinScript("ko")); + assertFalse(Util.isExplicitLatinScript("KO")); + assertFalse(Util.isExplicitLatinScript("ja")); + assertFalse(Util.isExplicitLatinScript("ja-JP")); + assertFalse(Util.isExplicitLatinScript("zh-Hans")); + assertFalse(Util.isExplicitLatinScript("zh-Hans-CN")); + assertFalse(Util.isExplicitLatinScript("zh-Hant")); + assertFalse(Util.isExplicitLatinScript("zh-TW")); + assertFalse(Util.isExplicitLatinScript("zh_TW")); + assertFalse(Util.isExplicitLatinScript("ko")); + assertFalse(Util.isExplicitLatinScript("ko_KR")); + assertFalse(Util.isExplicitLatinScript("en")); + assertFalse(Util.isExplicitLatinScript("EN")); + assertFalse(Util.isExplicitLatinScript("ru")); + } - public void testGetLanguageSubtag() throws Exception { - assertEquals("zh", Util.getLanguageSubtag("zh-Latn")); - assertEquals("ja", Util.getLanguageSubtag("ja_LATN")); - assertEquals("und", Util.getLanguageSubtag("und_LATN")); - assertEquals("ja", Util.getLanguageSubtag("ja_LATN-JP")); - assertEquals("ko", Util.getLanguageSubtag("ko")); - assertEquals("ko", Util.getLanguageSubtag("KO")); - assertEquals("ko", Util.getLanguageSubtag("ko-KR")); - assertEquals("ko", Util.getLanguageSubtag("ko_kr")); - assertEquals("und", Util.getLanguageSubtag("Not a language")); - } + public void testGetLanguageSubtag() throws Exception { + assertEquals("zh", Util.getLanguageSubtag("zh-Latn")); + assertEquals("ja", Util.getLanguageSubtag("ja_LATN")); + assertEquals("und", Util.getLanguageSubtag("und_LATN")); + assertEquals("ja", Util.getLanguageSubtag("ja_LATN-JP")); + assertEquals("ko", Util.getLanguageSubtag("ko")); + assertEquals("ko", Util.getLanguageSubtag("KO")); + assertEquals("ko", Util.getLanguageSubtag("ko-KR")); + assertEquals("ko", Util.getLanguageSubtag("ko_kr")); + assertEquals("und", Util.getLanguageSubtag("Not a language")); + } - public void testTrimToNull() throws Exception { - assertEquals("Trimmed String", Util.trimToNull(" Trimmed String ")); - assertEquals("Trimmed String", Util.trimToNull(" Trimmed String")); - assertEquals("Trimmed String", Util.trimToNull("Trimmed String")); - assertEquals(null, Util.trimToNull(" ")); - assertEquals(null, Util.trimToNull(null)); - } + public void testTrimToNull() throws Exception { + assertEquals("Trimmed String", Util.trimToNull(" Trimmed String ")); + assertEquals("Trimmed String", Util.trimToNull(" Trimmed String")); + assertEquals("Trimmed String", Util.trimToNull("Trimmed String")); + assertEquals(null, Util.trimToNull(" ")); + assertEquals(null, Util.trimToNull(null)); + } - public void testJoinAndSkipNulls() throws Exception { - String first = "String 1"; - String second = "String 2"; - String expectedString = "String 1-String 2"; - String nullString = null; - assertEquals(expectedString, Util.joinAndSkipNulls("-", first, second)); - assertEquals(expectedString, Util.joinAndSkipNulls("-", first, second, nullString)); - assertEquals(expectedString, Util.joinAndSkipNulls("-", first, nullString, second)); - assertEquals(expectedString, Util.joinAndSkipNulls("-", first, nullString, " ", second)); - assertEquals(first, Util.joinAndSkipNulls("-", first, nullString)); - assertEquals(first, Util.joinAndSkipNulls("-", nullString, first)); + public void testJoinAndSkipNulls() throws Exception { + String first = "String 1"; + String second = "String 2"; + String expectedString = "String 1-String 2"; + String nullString = null; + assertEquals(expectedString, Util.joinAndSkipNulls("-", first, second)); + assertEquals(expectedString, Util.joinAndSkipNulls("-", first, second, nullString)); + assertEquals(expectedString, Util.joinAndSkipNulls("-", first, nullString, second)); + assertEquals(expectedString, Util.joinAndSkipNulls("-", first, nullString, " ", second)); + assertEquals(first, Util.joinAndSkipNulls("-", first, nullString)); + assertEquals(first, Util.joinAndSkipNulls("-", nullString, first)); - assertEquals(null, Util.joinAndSkipNulls("-", nullString)); - assertEquals(null, Util.joinAndSkipNulls("-", nullString, nullString)); - assertEquals(null, Util.joinAndSkipNulls("-", nullString, "", nullString)); - } + assertEquals(null, Util.joinAndSkipNulls("-", nullString)); + assertEquals(null, Util.joinAndSkipNulls("-", nullString, nullString)); + assertEquals(null, Util.joinAndSkipNulls("-", nullString, "", nullString)); + } - public void testGetWidgetCompatibleLanguageCodeCjkCountry() throws Exception { - Locale canadianFrench = new Locale("fr", "CA"); - // Latin language, CJK country. Need explicit Latin tag, and country should be retained. - assertEquals("fr_latn_CA", Util.getWidgetCompatibleLanguageCode(canadianFrench, "CN")); - Locale canadianFrenchUpper = new Locale("FR", "CA"); - // Test that the locale returns the same language code, regardless of the case of the - // initial input. - assertEquals("fr_latn_CA", Util.getWidgetCompatibleLanguageCode(canadianFrenchUpper, "CN")); - // No country in the Locale language. - assertEquals("fr_latn", Util.getWidgetCompatibleLanguageCode(Locale.FRENCH, "CN")); - // CJK language - but wrong country. - assertEquals("ko_latn", - Util.getWidgetCompatibleLanguageCode(Locale.KOREAN, "CN")); - Locale chineseChina = new Locale("zh", "CN"); - assertEquals("zh_CN", Util.getWidgetCompatibleLanguageCode(chineseChina, "CN")); - } + public void testGetWidgetCompatibleLanguageCodeCjkCountry() throws Exception { + Locale canadianFrench = new Locale("fr", "CA"); + // Latin language, CJK country. Need explicit Latin tag, and country should be retained. + assertEquals("fr_latn_CA", Util.getWidgetCompatibleLanguageCode(canadianFrench, "CN")); + Locale canadianFrenchUpper = new Locale("FR", "CA"); + // Test that the locale returns the same language code, regardless of the case of the + // initial input. + assertEquals("fr_latn_CA", Util.getWidgetCompatibleLanguageCode(canadianFrenchUpper, "CN")); + // No country in the Locale language. + assertEquals("fr_latn", Util.getWidgetCompatibleLanguageCode(Locale.FRENCH, "CN")); + // CJK language - but wrong country. + assertEquals("ko_latn", + Util.getWidgetCompatibleLanguageCode(Locale.KOREAN, "CN")); + Locale chineseChina = new Locale("zh", "CN"); + assertEquals("zh_CN", Util.getWidgetCompatibleLanguageCode(chineseChina, "CN")); + } - public void testGetWidgetCompatibleLanguageCodeThailand() throws Exception { - Locale thai = new Locale("th", "TH"); - assertEquals("th_TH", Util.getWidgetCompatibleLanguageCode(thai, "TH")); - // However, we assume Thai users prefer Latin names for China. - assertEquals("th_latn_TH", Util.getWidgetCompatibleLanguageCode(thai, "CN")); - } + public void testGetWidgetCompatibleLanguageCodeThailand() throws Exception { + Locale thai = new Locale("th", "TH"); + assertEquals("th_TH", Util.getWidgetCompatibleLanguageCode(thai, "TH")); + // However, we assume Thai users prefer Latin names for China. + assertEquals("th_latn_TH", Util.getWidgetCompatibleLanguageCode(thai, "CN")); + } - public void testGetWidgetCompatibleLanguageCodeNonCjkCountry() throws Exception { - // Nothing should be changed for non-CJK countries, since their form layout is the same - // regardless of language. - Locale canadianFrench = new Locale("fr", "CA"); - assertEquals("fr_CA", Util.getWidgetCompatibleLanguageCode(canadianFrench, "US")); - // No country in the Locale language. - assertEquals(Locale.FRENCH.toString(), - Util.getWidgetCompatibleLanguageCode(Locale.FRENCH, "US")); - // CJK language - should be unaltered too. - assertEquals(Locale.KOREAN.toString(), - Util.getWidgetCompatibleLanguageCode(Locale.KOREAN, "US")); - } + public void testGetWidgetCompatibleLanguageCodeNonCjkCountry() throws Exception { + // Nothing should be changed for non-CJK countries, since their form layout is the same + // regardless of language. + Locale canadianFrench = new Locale("fr", "CA"); + assertEquals("fr_CA", Util.getWidgetCompatibleLanguageCode(canadianFrench, "US")); + // No country in the Locale language. + assertEquals(Locale.FRENCH.toString(), + Util.getWidgetCompatibleLanguageCode(Locale.FRENCH, "US")); + // CJK language - should be unaltered too. + assertEquals(Locale.KOREAN.toString(), + Util.getWidgetCompatibleLanguageCode(Locale.KOREAN, "US")); + } - public void testBuildNameToKeyMap() throws Exception { - String names[] = {"", "", "", "", "NEW PROVIDENCE" }; - // We have one more key than name here. - String keys[] = {"AB", "AC", "AD", "AE", "NP", "XX"}; - Map result = Util.buildNameToKeyMap(keys, names, null); - // We should have the six keys, and the one name, in the end result. No empty-string names - // should be present. - assertEquals(keys.length + 1, result.size()); - // The empty string should not be present. - assertFalse(result.containsKey("")); + public void testBuildNameToKeyMap() throws Exception { + String names[] = {"", "", "", "", "NEW PROVIDENCE" }; + // We have one more key than name here. + String keys[] = {"AB", "AC", "AD", "AE", "NP", "XX"}; + Map result = Util.buildNameToKeyMap(keys, names, null); + // We should have the six keys, and the one name, in the end result. No empty-string names + // should be present. + assertEquals(keys.length + 1, result.size()); + // The empty string should not be present. + assertFalse(result.containsKey("")); - // Try with Latin names instead. - Map resultWithLatin = Util.buildNameToKeyMap(keys, null, names); - // We should have the six keys and the one Latin-script name in the end result. - assertEquals(keys.length + 1, resultWithLatin.size()); - String lnames[] = { "Other name" }; - resultWithLatin = Util.buildNameToKeyMap(keys, names, lnames); - // We should have the keys, plus the names in lnames and names. - assertEquals(keys.length + 2, resultWithLatin.size()); - assertTrue(resultWithLatin.containsKey("other name")); - assertTrue(resultWithLatin.containsKey("new providence")); - assertTrue(resultWithLatin.containsKey("xx")); - // The empty string should not be present. - assertFalse(resultWithLatin.containsKey("")); - } + // Try with Latin names instead. + Map resultWithLatin = Util.buildNameToKeyMap(keys, null, names); + // We should have the six keys and the one Latin-script name in the end result. + assertEquals(keys.length + 1, resultWithLatin.size()); + String lnames[] = { "Other name" }; + resultWithLatin = Util.buildNameToKeyMap(keys, names, lnames); + // We should have the keys, plus the names in lnames and names. + assertEquals(keys.length + 2, resultWithLatin.size()); + assertTrue(resultWithLatin.containsKey("other name")); + assertTrue(resultWithLatin.containsKey("new providence")); + assertTrue(resultWithLatin.containsKey("xx")); + // The empty string should not be present. + assertFalse(resultWithLatin.containsKey("")); + } } -- cgit v1.2.3 From b6bf3a8c83b1ceb0bd11fcd89833ecbc18580ed2 Mon Sep 17 00:00:00 2001 From: Lara Scheidegger Date: Wed, 22 Oct 2014 21:13:33 +0200 Subject: More whitespace/line-break changes, fixed tests by using this where appropriate. --- .../i18n/addressinput/AddressUiComponent.java | 20 +++++++------- .../android/i18n/addressinput/AddressWidget.java | 31 ++++++++++------------ .../AddressWidgetUiComponentProvider.java | 4 +-- .../android/i18n/addressinput/FieldVerifier.java | 2 +- .../android/i18n/addressinput/FormController.java | 6 ++--- .../com/android/i18n/addressinput/FormOptions.java | 2 +- .../i18n/addressinput/JsonpRequestBuilder.java | 4 +-- .../i18n/addressinput/NotifyingListener.java | 4 +-- .../i18n/addressinput/StandardAddressVerifier.java | 17 +++++------- .../i18n/addressinput/AsyncTestCaseTest.java | 20 +++++++------- 10 files changed, 52 insertions(+), 58 deletions(-) diff --git a/java/src/com/android/i18n/addressinput/AddressUiComponent.java b/java/src/com/android/i18n/addressinput/AddressUiComponent.java index d0aa4c8..5e07799 100644 --- a/java/src/com/android/i18n/addressinput/AddressUiComponent.java +++ b/java/src/com/android/i18n/addressinput/AddressUiComponent.java @@ -55,10 +55,10 @@ class AddressUiComponent { } AddressUiComponent(AddressField id) { - id = id; + this.id = id; // By default, an AddressUiComponent doesn't depend on anything else. - parentId = null; - uiType = UiComponent.EDIT; + this.parentId = null; + this.uiType = UiComponent.EDIT; } /** @@ -66,7 +66,7 @@ class AddressUiComponent { * @param candidatesList */ void initializeCandidatesList(List candidatesList) { - candidatesList = candidatesList; + this.candidatesList = candidatesList; if (candidatesList.size() > 1) { uiType = UiComponent.SPINNER; switch (id) { @@ -111,7 +111,7 @@ class AddressUiComponent { } void setFieldName(String fieldName) { - fieldName = fieldName; + this.fieldName = fieldName; } UiComponent getUiType() { @@ -119,7 +119,7 @@ class AddressUiComponent { } void setUiType(UiComponent uiType) { - uiType = uiType; + this.uiType = uiType; } List getCandidatesList() { @@ -127,7 +127,7 @@ class AddressUiComponent { } void setCandidatesList(List candidatesList) { - candidatesList = candidatesList; + this.candidatesList = candidatesList; } AddressField getId() { @@ -135,7 +135,7 @@ class AddressUiComponent { } void setId(AddressField id) { - id = id; + this.id = id; } AddressField getParentId() { @@ -143,11 +143,11 @@ class AddressUiComponent { } void setParentId(AddressField parentId) { - parentId = parentId; + this.parentId = parentId; } void setView(View view) { - view = view; + this.view = view; } View getView() { diff --git a/java/src/com/android/i18n/addressinput/AddressWidget.java b/java/src/com/android/i18n/addressinput/AddressWidget.java index 8c6b7d4..3a7267b 100644 --- a/java/src/com/android/i18n/addressinput/AddressWidget.java +++ b/java/src/com/android/i18n/addressinput/AddressWidget.java @@ -167,10 +167,10 @@ public class AddressWidget implements AdapterView.OnItemSelectedListener { @SuppressWarnings("unchecked") public AddressSpinnerInfo(Spinner view, AddressField id, AddressField parentId) { - view = view; - id = id; - parentId = parentId; - adapter = (ArrayAdapter) view.getAdapter(); + this.view = view; + this.id = id; + this.parentId = parentId; + this.adapter = (ArrayAdapter) view.getAdapter(); } public void setSpinnerList(List list, String defaultKey) { @@ -599,8 +599,7 @@ public class AddressWidget implements AdapterView.OnItemSelectedListener { } private void initializeFieldsWithAddress(AddressData savedAddress) { - for (AddressField field : formatInterpreter.getAddressFieldOrder(script, - currentRegion)) { + for (AddressField field : formatInterpreter.getAddressFieldOrder(script, currentRegion)) { String value = savedAddress.getFieldValue(field); if (value == null) { value = ""; @@ -615,17 +614,15 @@ public class AddressWidget implements AdapterView.OnItemSelectedListener { private void init(Context context, ViewGroup rootView, FormOptions formOptions, ClientCacheManager cacheManager) { - context = context; - rootView = rootView; - formOptions = formOptions; - cacheData = new CacheData(cacheManager); - inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); - formController = - new FormController(new ClientData(cacheData), - widgetLocale, currentRegion); - formatInterpreter = new FormatInterpreter(formOptions); - verifier = new StandardAddressVerifier( - new FieldVerifier(new ClientData(cacheData))); + this.context = context; + this.rootView = rootView; + this.formOptions = formOptions; + this.cacheData = new CacheData(cacheManager); + this.inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); + this.formController = + new FormController(new ClientData(cacheData), widgetLocale, currentRegion); + this.formatInterpreter = new FormatInterpreter(formOptions); + this.verifier = new StandardAddressVerifier(new FieldVerifier(new ClientData(cacheData))); if (!formOptions.isHidden(AddressField.COUNTRY)) { buildCountryListBox(); createView(rootView, inputWidgets.get(AddressField.COUNTRY), diff --git a/java/src/com/android/i18n/addressinput/AddressWidgetUiComponentProvider.java b/java/src/com/android/i18n/addressinput/AddressWidgetUiComponentProvider.java index 670c6c6..31160b9 100644 --- a/java/src/com/android/i18n/addressinput/AddressWidgetUiComponentProvider.java +++ b/java/src/com/android/i18n/addressinput/AddressWidgetUiComponentProvider.java @@ -41,8 +41,8 @@ public class AddressWidgetUiComponentProvider { protected LayoutInflater inflater; public AddressWidgetUiComponentProvider(Context context) { - context = context; - inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); + this.context = context; + this.inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); } /** diff --git a/java/src/com/android/i18n/addressinput/FieldVerifier.java b/java/src/com/android/i18n/addressinput/FieldVerifier.java index 17a71e0..9dee8de 100644 --- a/java/src/com/android/i18n/addressinput/FieldVerifier.java +++ b/java/src/com/android/i18n/addressinput/FieldVerifier.java @@ -70,7 +70,7 @@ public class FieldVerifier { * Creates the root field verifier for a particular data source. */ public FieldVerifier(DataSource dataSource) { - dataSource = dataSource; + this.dataSource = dataSource; populateRootVerifier(); } diff --git a/java/src/com/android/i18n/addressinput/FormController.java b/java/src/com/android/i18n/addressinput/FormController.java index 68deed7..63c69ab 100644 --- a/java/src/com/android/i18n/addressinput/FormController.java +++ b/java/src/com/android/i18n/addressinput/FormController.java @@ -56,7 +56,7 @@ class FormController { */ FormController(ClientData integratedData, String languageCode, String currentCountry) { Util.checkNotNull(integratedData, "null data not allowed"); - languageCode = languageCode; + this.languageCode = languageCode; this.currentCountry = currentCountry; AddressData address = new AddressData.Builder().setCountry(DEFAULT_REGION_CODE).build(); @@ -70,11 +70,11 @@ class FormController { } void setLanguageCode(String languageCode) { - languageCode = languageCode; + this.languageCode = languageCode; } void setCurrentCountry(String currentCountry) { - currentCountry = currentCountry; + this.currentCountry = currentCountry; } private ScriptType getScriptType() { diff --git a/java/src/com/android/i18n/addressinput/FormOptions.java b/java/src/com/android/i18n/addressinput/FormOptions.java index 2b9bee6..ffa8c10 100644 --- a/java/src/com/android/i18n/addressinput/FormOptions.java +++ b/java/src/com/android/i18n/addressinput/FormOptions.java @@ -154,7 +154,7 @@ public class FormOptions { if (baseId == null) { throw new RuntimeException("baseId cannot be null."); } - baseId = baseId; + this.baseId = baseId; return this; } diff --git a/java/src/com/android/i18n/addressinput/JsonpRequestBuilder.java b/java/src/com/android/i18n/addressinput/JsonpRequestBuilder.java index b21fded..d5bc608 100644 --- a/java/src/com/android/i18n/addressinput/JsonpRequestBuilder.java +++ b/java/src/com/android/i18n/addressinput/JsonpRequestBuilder.java @@ -72,8 +72,8 @@ class JsonpRequestBuilder { private AsyncCallback callback; protected AsyncHttp(HttpUriRequest request, AsyncCallback callback) { - request = request; - callback = callback; + this.request = request; + this.callback = callback; } @Override diff --git a/java/src/com/android/i18n/addressinput/NotifyingListener.java b/java/src/com/android/i18n/addressinput/NotifyingListener.java index 4e64d2d..038a069 100644 --- a/java/src/com/android/i18n/addressinput/NotifyingListener.java +++ b/java/src/com/android/i18n/addressinput/NotifyingListener.java @@ -24,8 +24,8 @@ public class NotifyingListener implements DataLoadListener { private boolean done; NotifyingListener(Object sleeper) { - sleeper = sleeper; - done = false; + this.sleeper = sleeper; + this.done = false; } @Override diff --git a/java/src/com/android/i18n/addressinput/StandardAddressVerifier.java b/java/src/com/android/i18n/addressinput/StandardAddressVerifier.java index 1b547c1..96cf684 100644 --- a/java/src/com/android/i18n/addressinput/StandardAddressVerifier.java +++ b/java/src/com/android/i18n/addressinput/StandardAddressVerifier.java @@ -105,9 +105,9 @@ public class StandardAddressVerifier { private DataLoadListener listener; Verifier(AddressData address, AddressProblems problems, DataLoadListener listener) { - address = address; - problems = problems; - listener = listener; + this.address = address; + this.problems = problems; + this.listener = listener; } @Override @@ -165,17 +165,15 @@ public class StandardAddressVerifier { * Hook to perform any final processing using the final verifier. Default does no additional * verification. */ - protected void postVerify(FieldVerifier verifier, AddressData address, - AddressProblems problems) { + protected void postVerify(FieldVerifier verifier, AddressData address, AddressProblems problems) { } /** * Hook called by verify with each verifiable field, in order. Override to provide pre- or * post-checks for all fields. */ - protected boolean verifyField(LookupKey.ScriptType script, - FieldVerifier verifier, AddressField field, String value, - AddressProblems problems) { + protected boolean verifyField(LookupKey.ScriptType script, FieldVerifier verifier, + AddressField field, String value, AddressProblems problems) { Iterator iter = getProblemIterator(field); while (iter.hasNext()) { AddressProblemType prob = iter.next(); @@ -220,8 +218,7 @@ public class StandardAddressVerifier { /** * Refines the verifier. This delegates to the verifier to perform the refinement. */ - public FieldVerifier refineVerifier(FieldVerifier v, AddressField field, - String subkey) { + public FieldVerifier refineVerifier(FieldVerifier v, AddressField field, String subkey) { return v.refineVerifier(subkey); } diff --git a/java/test/com/android/i18n/addressinput/AsyncTestCaseTest.java b/java/test/com/android/i18n/addressinput/AsyncTestCaseTest.java index 495f937..36833b8 100644 --- a/java/test/com/android/i18n/addressinput/AsyncTestCaseTest.java +++ b/java/test/com/android/i18n/addressinput/AsyncTestCaseTest.java @@ -68,6 +68,14 @@ public class AsyncTestCaseTest extends AsyncTestCase { * Helper class to perform an asynchronous callback after a specified delay. */ private static class AsyncCallback extends Thread { + private long waitMillis; + private Runnable callback; + + private AsyncCallback(long waitMillis, Runnable callback) { + this.waitMillis = waitMillis; + this.callback = callback; + } + public static void execute(long waitMillis, Runnable callback) { (new AsyncCallback(waitMillis, callback)).start(); } @@ -76,20 +84,12 @@ public class AsyncTestCaseTest extends AsyncTestCase { public void run() { try { synchronized (this) { - wait(waitMillis); + wait(this.waitMillis); } } catch (InterruptedException e) { throw new RuntimeException(e); } - callback.run(); + this.callback.run(); } - - private AsyncCallback(long waitMillis, Runnable callback) { - this.waitMillis = waitMillis; - this.callback = callback; - } - - private long waitMillis; - private Runnable callback; } } -- cgit v1.2.3