2 * Copyright (C) 2010 Google Inc.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 package com.android.i18n.addressinput;
19 import java.util.HashMap;
23 * A simple data structure for international postal addresses.
25 * Addresses may seem simple, but even within the US there are many quirks (hyphenated street
26 * addresses, etc.), and internationally addresses vary a great deal. The most sane and complete in
27 * many ways is the OASIS "extensible Address Language", xAL, which is a published and documented
30 * http://www.oasis-open.org/committees/ciq/download.shtml
32 * We have not represented all the fields, but the intent is that if you need to add something, you
33 * should follow the OASIS standard.
36 * <p>postalCountry: US</p>
37 * <p>addressLine1: 1098 Alta Ave</p>
38 * <p>addressLine2:</p>
39 * <p>adminstrativeArea: CA</p>
40 * <p>locality: Mountain View</p>
41 * <p>dependentLocality:</p>
42 * <p>postalCode: 94043</p>
44 * <p>organization: Google</p>
45 * <p>recipient: Chen-Kang Yang</p>
46 * <p>language code: en</p>
48 * Note that sub-administrative area is NOT used in Address Widget. Sub-administrative Area is
49 * second-level administrative subdivision of this country. For examples: US county, IT province, UK
50 * county. This level of geo information is not required to fill out address form, therefore is
53 * All values stored in this class are trimmed. Also, if you try to set a field with an empty string
54 * or a string consists of only spaces, it will not be set.
56 public class AddressData {
57 // CLDR (Common Locale Data Repository) country code.
58 // For example, "US" for United States.
59 // (Note: Use "GB", not "UK", for Great Britain)
60 private final String postalCountry;
62 // street street, line 1
63 private final String addressLine1;
65 // street street, line 2
66 private final String addressLine2;
68 // Top-level administrative subdivision of this country.
69 // Examples: US state, IT region, UK constituent nation, JP prefecture.
70 private final String administrativeArea;
72 // Locality. A fuzzy term, but it generally refers to
73 // the city/town portion of an address. In regions of the world where
74 // localities are not well defined or do not fit into this structure well
75 // (for example, Japan and China), leave locality empty and use
77 // Examples: US city, IT comune, UK post town.
78 private final String locality;
80 // Dependent locality or sublocality. Used for UK dependent localities,
81 // or neighborhoods or boroughs in other locations. If trying to
82 // represent a UK double-dependent locality, include both the
83 // double-dependent locality and the dependent locality in this field,
84 // e.g. "Whaley, Langwith".
85 private final String dependentLocality;
87 // Postal Code. values are frequently alphanumeric.
88 // Examples: "94043", "94043-1351", "SW1W", "SW1W 9TQ".
89 private final String postalCode;
91 // Sorting code - use is very country-specific.
92 // This corresponds to the SortingCode sub-element of the xAL
93 // PostalServiceElements element.
94 // Examples: FR CEDEX.
95 private final String sortingCode;
97 // The firm or organization. This goes at a finer granularity than
98 // address lines in the address. Omit if not needed.
99 private final String organization;
101 // The recipient. This goes at a finer granularity than address lines
102 // in the address. Not present in xAL. Omit if not needed.
103 private final String recipient;
105 // Language code of the address. Can be set to null. See its getter and setter
106 // for more information.
107 private final String languageCode;
110 * Use {@link Builder} to create instances.
112 private AddressData(Builder builder) {
113 postalCountry = builder.values.get(AddressField.COUNTRY);
114 administrativeArea = builder.values.get(AddressField.ADMIN_AREA);
115 locality = builder.values.get(AddressField.LOCALITY);
116 dependentLocality = builder.values.get(AddressField.DEPENDENT_LOCALITY);
117 postalCode = builder.values.get(AddressField.POSTAL_CODE);
118 sortingCode = builder.values.get(AddressField.SORTING_CODE);
119 organization = builder.values.get(AddressField.ORGANIZATION);
120 recipient = builder.values.get(AddressField.RECIPIENT);
121 addressLine1 = builder.values.get(AddressField.ADDRESS_LINE_1);
122 addressLine2 = builder.values.get(AddressField.ADDRESS_LINE_2);
123 languageCode = builder.language;
127 * Returns the postal country.
129 * <p>The returned value is not user-presentable. For example, {@code getPostalCountry()} may
130 * return {@code "GB"}, while addresses in Great Britain should be displayed using "UK".
132 public String getPostalCountry() {
133 return postalCountry;
136 public String getAddressLine1() {
140 public String getAddressLine2() {
145 * Returns the top-level administrative subdivision of this country. Different postal countries
146 * use different names to refer to their administrative areas. For example, this is called
147 * "state" in the United States, "region" in Italy, "constituent nation" in Great Britain, or
148 * "prefecture" in Japan.
150 public String getAdministrativeArea() {
151 return administrativeArea;
155 * Returns the locality. The usage of this field varies by region, but it generally refers to
156 * the "city" or "town" of the address. Some regions do not use this field; their address lines
157 * are sufficient to locate an address within a sub-administrative area. For example, this is
158 * called "city" in the United States, "comune" in Italy, or "post town" in Great Britain.
160 public String getLocality() {
165 * Returns the dependent locality.
167 * <p>This is used for Great Britain dependent localities, or neighborhoods or boroughs in other
170 * <p>In cases such as Great Britain, this field may contain a double-dependent locality, such
171 * as "Whaley, Langwith".
173 public String getDependentLocality() {
174 return dependentLocality;
178 * Returns the firm or organization.
180 public String getOrganization() {
185 * Returns the recipient. Examples: "Jesse Wilson" or "Jesse Wilson c/o Apurva Mathad".
187 public String getRecipient() {
192 * Returns the country-specific postal code. Examples: "94043", "94043-1351", "SW1W",
195 public String getPostalCode() {
200 * Returns the country-specific sorting code. For example, the
201 * <a href="http://en.wikipedia.org/wiki/List_of_postal_codes_in_France"> French CEDEX</a>
203 public String getSortingCode() {
207 public String getFieldValue(AddressField field) {
210 return postalCountry;
212 return administrativeArea;
215 case DEPENDENT_LOCALITY:
216 return dependentLocality;
230 throw new IllegalArgumentException("unrecognized key: " + field);
235 * Returns the language of the text of this address. Languages are used to guide how the address
236 * is <a href="http://en.wikipedia.org/wiki/Mailing_address_format_by_country"> formatted for
237 * display</a>. The same address may have different {@link AddressData} representations in
238 * different languages. For example, the French name of "New Mexico" is "Nouveau-Mexique".
240 public String getLanguageCode() {
245 * Builder for AddressData
247 public static class Builder {
249 private final Map<AddressField, String> values;
251 private String language = null;
254 values = new HashMap<AddressField, String>();
258 * A constructor that sets address field with input data. Street fields will be normalized
259 * in the process. I.e., after copy, there will not be any empty street line in front of
260 * non-empty ones. For example, if input data's street line 1 is null but street line 2
261 * has a value, this method will copy street line 2's value and set it to street line 1.
263 public Builder(AddressData addr) {
264 values = new HashMap<AddressField, String>();
268 public Builder setCountry(String value) {
269 return set(AddressField.COUNTRY, value);
272 public Builder setAdminArea(String value) {
273 return set(AddressField.ADMIN_AREA, value);
276 public Builder setLocality(String value) {
277 return set(AddressField.LOCALITY, value);
280 public Builder setDependentLocality(String value) {
281 return set(AddressField.DEPENDENT_LOCALITY, value);
284 public Builder setPostalCode(String value) {
285 return set(AddressField.POSTAL_CODE, value);
288 public Builder setSortingCode(String value) {
289 return set(AddressField.SORTING_CODE, value);
293 * Sets the language code.
295 * @param languageCode the language to use, or {@code null} for no specified language.
297 public Builder setLanguageCode(String languageCode) {
298 this.language = languageCode;
303 * Sets address lines 1 and 2 (if necessary) from a string that may contain multiple lines.
305 * <p> Example: Input " \n \n1600 Amphitheatre Ave\n\nRoom 122" will set the following
306 * values:<br/> line 1: 1600 Amphitheatre Ave<br/> line 2: Room 122<br/> </p>
308 * @param value a street string
310 public Builder setAddress(String value) {
311 setAddressLine1(value);
316 * Sets address by copying from input address data. Street fields will be normalized in the
317 * process. I.e., after copy, there will not be any empty street lines in front of non-empty
318 * ones. For example, if input data's street line 1 is null but street line 2 has a value,
319 * this method will copy street line 2's value and set it to street line 1.
321 public Builder set(AddressData data) {
323 for (AddressField addressField : AddressField.values()) {
324 if (addressField == AddressField.STREET_ADDRESS) {
325 continue; // Do nothing.
327 set(addressField, data.getFieldValue(addressField));
330 normalizeAddresses();
331 setLanguageCode(data.getLanguageCode());
335 public Builder setAddressLine1(String value) {
336 return set(AddressField.ADDRESS_LINE_1, value);
339 public Builder setAddressLine2(String value) {
340 return set(AddressField.ADDRESS_LINE_2, value);
343 public Builder setOrganization(String value) {
344 return set(AddressField.ORGANIZATION, value);
347 public Builder setRecipient(String value) {
348 return set(AddressField.RECIPIENT, value);
352 * Sets an address field with the specified value. If the value is empty (a null string,
353 * empty string, or a string that contains only spaces), the original value associated with
354 * the field will be removed.
356 public Builder set(AddressField field, String value) {
357 if (value == null || value.length() == 0) {
358 values.remove(field);
360 values.put(field, value.trim());
362 normalizeAddresses();
366 public AddressData build() {
367 return new AddressData(this);
371 * Parses content of address line fields.
372 * If address_line_1 is empty, address_line_2 will be used to populate address_line_1 if
373 * possible. If address_line_1 contains a new line, content after the new line will be
374 * saved in address_line_2.
376 private void normalizeAddresses() {
377 String address1 = values.get(AddressField.ADDRESS_LINE_1);
378 String address2 = values.get(AddressField.ADDRESS_LINE_2);
379 if (address1 == null || address1.trim().length() == 0) {
383 if (address1 != null) {
384 String[] addressLines = address1.split("\n");
385 if (addressLines.length > 1) {
386 address1 = addressLines[0];
387 address2 = addressLines[1];
390 values.put(AddressField.ADDRESS_LINE_1, address1);
391 values.put(AddressField.ADDRESS_LINE_2, address2);