Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / third_party / libaddressinput / src / java / src / com / android / i18n / addressinput / AddressWidget.java
index c377e2c..3a7267b 100644 (file)
@@ -51,727 +51,728 @@ 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 except for country.
-    private final EnumMap<AddressField, AddressUiComponent> mInputWidgets =
-        new EnumMap<AddressField, AddressUiComponent>(AddressField.class);
+  // A map for all address fields.
+  private final EnumMap<AddressField, AddressUiComponent> inputWidgets =
+      new EnumMap<AddressField, AddressUiComponent>(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 use 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;
 
-    // The appropriate label that should be applied to the locality (city) field of the current
-    // country.  Examples include "city" or "district".
-    private String mLocalityLabel;
+  // 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<String, Integer> 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<String, Integer> 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<String, Integer> SUBLOCALITY_LABELS;
 
-    // The appropriate label that should be applied to the admin area field of the current country.
-    // Examples include "state", "province", "emirate", etc.
-    private String mAdminLabel;
+  private static final FormOptions SHOW_ALL_FIELDS = new FormOptions.Builder().build();
 
-    private static final Map<String, Integer> ADMIN_LABELS;
-    private static final Map<String, Integer> LOCALITY_LABELS;
-    private static final Map<String, Integer> ADMIN_ERROR_MESSAGES;
+  // The appropriate label that should be applied to the zip code field of the current country.
+  private enum ZipLabel {
+    ZIP,
+    POSTAL
+  }
 
-    private static final FormOptions SHOW_ALL_FIELDS = new FormOptions.Builder().build();
+  private ZipLabel zipLabel;
 
-    // The appropriate label that should be applied to the zip code field of the current country.
-    private enum ZipLabel {
-        ZIP,
-        POSTAL
-    }
+  static {
+    Map<String, Integer> adminLabelMap = new HashMap<String, Integer>(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);
 
-    private ZipLabel mZipLabel;
+    Map<String, Integer> localityLabelMap = new HashMap<String, Integer>(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);
 
-    static {
-        Map<String, Integer> adminLabelMap = new HashMap<String, Integer>(15);
-        adminLabelMap.put("area", R.string.i18n_area);
-        adminLabelMap.put("county", R.string.i18n_county_label);
-        adminLabelMap.put("department", R.string.i18n_department);
-        adminLabelMap.put("district", R.string.i18n_dependent_locality_label);
-        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_label);
-        ADMIN_LABELS = Collections.unmodifiableMap(adminLabelMap);
+    Map<String, Integer> sublocalityLabelMap = new HashMap<String, Integer>(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);
+  }
 
-        Map<String, Integer> localityLabelMap = new HashMap<String, Integer>(2);
-        localityLabelMap.put("city", R.string.i18n_locality_label);
-        localityLabelMap.put("district", R.string.i18n_dependent_locality_label);
-        LOCALITY_LABELS = Collections.unmodifiableMap(localityLabelMap);
+  // Need handler for callbacks to the UI thread
+  final Handler handler = new Handler();
 
-        Map<String, Integer> adminErrorMap = new HashMap<String, Integer>(15);
-        adminErrorMap.put("area", R.string.invalid_area);
-        adminErrorMap.put("county", R.string.invalid_county_label);
-        adminErrorMap.put("department", R.string.invalid_department);
-        adminErrorMap.put("district", R.string.invalid_dependent_locality_label);
-        adminErrorMap.put("do_si", R.string.invalid_do_si);
-        adminErrorMap.put("emirate", R.string.invalid_emirate);
-        adminErrorMap.put("island", R.string.invalid_island);
-        adminErrorMap.put("oblast", R.string.invalid_oblast);
-        adminErrorMap.put("parish", R.string.invalid_parish);
-        adminErrorMap.put("prefecture", R.string.invalid_prefecture);
-        adminErrorMap.put("province", R.string.invalid_province);
-        adminErrorMap.put("state", R.string.invalid_state_label);
-        ADMIN_ERROR_MESSAGES = Collections.unmodifiableMap(adminErrorMap);
+  final Runnable updateMultipleFields = new Runnable() {
+    @Override
+    public void run() {
+      updateFields();
     }
+  };
 
-    // Need handler for callbacks to the UI thread
-    final Handler mHandler = new Handler();
-
-    final Runnable mUpdateMultipleFields = new Runnable() {
-        @Override
-        public void run() {
-            updateFields();
-        }
-    };
-
-    private class UpdateRunnable implements Runnable {
-        private AddressField myId;
+  private class UpdateRunnable implements Runnable {
+    private AddressField myId;
 
-        public UpdateRunnable(AddressField id) {
-            myId = id;
-        }
+    public UpdateRunnable(AddressField id) {
+      myId = id;
+    }
 
-        @Override
-        public void run() {
-            updateInputWidget(myId);
-        }
+    @Override
+    public void run() {
+      updateInputWidget(myId);
     }
+  }
 
-    private static class AddressSpinnerInfo {
-        private Spinner mView;
+  private static class AddressSpinnerInfo {
+    private Spinner view;
 
-        private AddressField mId;
+    private AddressField id;
 
-        private AddressField mParentId;
+    private AddressField parentId;
 
-        private ArrayAdapter<String> mAdapter;
+    private ArrayAdapter<String> adapter;
 
-        private List<RegionData> mCurrentRegions;
+    private List<RegionData> currentRegions;
 
-        @SuppressWarnings("unchecked")
-        public AddressSpinnerInfo(Spinner view, AddressField id, AddressField parentId) {
-            mView = view;
-            mId = id;
-            mParentId = parentId;
-            mAdapter = (ArrayAdapter<String>) view.getAdapter();
-        }
+    @SuppressWarnings("unchecked")
+    public AddressSpinnerInfo(Spinner view, AddressField id, AddressField parentId) {
+      this.view = view;
+      this.id = id;
+      this.parentId = parentId;
+      this.adapter = (ArrayAdapter<String>) view.getAdapter();
+    }
 
-        public void setSpinnerList(List<RegionData> 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);
-            }
-        }
+    public void setSpinnerList(List<RegionData> 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);
+      }
+    }
 
-        // 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);
-        }
+    // 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);
+    }
 
-        // 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 "";
+    // 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 "";
     }
+  }
 
-    private final ArrayList<AddressSpinnerInfo> mSpinners = new ArrayList<AddressSpinnerInfo>();
+  private final ArrayList<AddressSpinnerInfo> spinners = new ArrayList<AddressSpinnerInfo>();
 
-    private AddressWidgetUiComponentProvider mComponentProvider;
+  private AddressWidgetUiComponentProvider componentProvider;
 
-    /** TODO: Add region-dependent width types for address fields. */
-    private WidthType getFieldWidthType(AddressUiComponent field) {
-        return field.getId().getDefaulWidthType();
-    }
+  /** TODO: Add region-dependent width types for address fields. */
+  private WidthType getFieldWidthType(AddressUiComponent field) {
+    return field.getId().getDefaulWidthType();
+  }
 
-    private void createView(ViewGroup rootView, AddressUiComponent field, String defaultKey,
-            boolean readOnly) {
-        @SuppressWarnings("deprecation")  // FILL_PARENT renamed MATCH_PARENT in API Level 8.
+  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<String> 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);
-        }
-    }
-
-    /**
-     *  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(mContext.getString(R.string.i18n_dependent_locality_label));
-        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<RegionData> adminAreaList = getRegionData(AddressField.COUNTRY);
-        adminAreaUi.initializeCandidatesList(adminAreaList);
-
-        AddressUiComponent localityUi = mInputWidgets.get(AddressField.LOCALITY);
-        List<RegionData> 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);
-        }
-        return zipName;
-    }
-
-    private String getLocalityFieldName(AddressVerificationNodeData countryNode) {
-        String localityLabelType = countryNode.get(AddressDataKey.LOCALITY_NAME_TYPE);
-        mLocalityLabel = localityLabelType;
-        Integer result = LOCALITY_LABELS.get(localityLabelType);
-        if (result == null) {
-            // Fallback to city.
-            result = R.string.i18n_locality_label;
-        }
-        return mContext.getString(result);
+            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<String> 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<RegionData> adminAreaList = getRegionData(AddressField.COUNTRY);
+    adminAreaUi.initializeCandidatesList(adminAreaList);
+
+    AddressUiComponent localityUi = inputWidgets.get(AddressField.LOCALITY);
+    List<RegionData> 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<RegionData> countries = new ArrayList<RegionData>();
+    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 String getAdminAreaFieldName(AddressVerificationNodeData countryNode) {
-        String adminLabelType = countryNode.get(AddressDataKey.STATE_NAME_TYPE);
-        mAdminLabel = adminLabelType;
-        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_label));
-        ArrayList<RegionData> countries = new ArrayList<RegionData>();
-        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);
-    }
+  private String getLocalCountryName(String regionCode) {
+    return (new Locale("", regionCode)).getDisplayCountry(Locale.getDefault());
+  }
 
-    private String getLocalCountryName(String regionCode) {
-        return (new Locale("", regionCode)).getDisplayCountry(Locale.getDefault());
+  private AddressSpinnerInfo findSpinnerByView(View view) {
+    for (AddressSpinnerInfo spinnerInfo : spinners) {
+      if (spinnerInfo.view == view) {
+        return spinnerInfo;
+      }
     }
+    return null;
+  }
 
-    private AddressSpinnerInfo findSpinnerByView(View view) {
-        for (AddressSpinnerInfo spinnerInfo : mSpinners) {
-            if (spinnerInfo.mView == view) {
-                return spinnerInfo;
-            }
-        }
-        return null;
-    }
+  private void updateFields() {
+    removePreviousViews();
+    buildFieldWidgets();
+    initializeDropDowns();
+    layoutAddressFields();
+  }
 
-    private void updateFields() {
-        removePreviousViews();
-        buildFieldWidgets();
-        initializeDropDowns();
-        layoutAddressFields();
+  private void removePreviousViews() {
+    if (rootView == null) {
+      return;
     }
-
-    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);
-        }
+    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 layoutAddressFields() {
-        for (AddressField field : mFormatInterpreter.getAddressFieldOrder(mScript,
-                mCurrentRegion)) {
-            if (!mFormOptions.isHidden(field)) {
-              createView(mRootView, mInputWidgets.get(field), "", mFormOptions.isReadonly(field));
-            }
-        }
+  private void layoutAddressFields() {
+    for (AddressField field : formatInterpreter.getAddressFieldOrder(script,
+          currentRegion)) {
+      if (!formOptions.isHidden(field)) {
+        createView(rootView, inputWidgets.get(field), "", formOptions.isReadonly(field));
+      }
     }
+  }
 
-    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(){
-            }
-
-            @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<RegionData> 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<RegionData> 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<RegionData> 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<RegionData>(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<RegionData> 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<RegionData> 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<RegionData> 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<RegionData>(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<String> getEnvelopeAddress() {
-        return mFormatInterpreter.getEnvelopeAddress(getAddressData());
-    }
-
-    /**
-     * Gets the formatted address based on the AddressData passed in.
-     */
-    public List<String> 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<String> 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 when the AddressField contains an invalid entry.
-     *
-     * @return the View object representing the AddressField.
-     */
-    public View displayErrorMessageForInvalidEntryIn(AddressField field) {
-        Log.d(this.toString(), "Display error message for the field: " + field.toString());
-        AddressUiComponent addressUiComponent = mInputWidgets.get(field);
-        if (addressUiComponent != null && addressUiComponent.getUiType() == UiComponent.EDIT) {
-            int errorMessageId = getErrorMessageIdForInvalidEntryIn(field);
-            EditText view = (EditText) addressUiComponent.getView();
-            view.setError(mContext.getString(errorMessageId));
-            return view;
-        }
-        return null;
-    }
-
-    private int getErrorMessageIdForInvalidEntryIn(AddressField field) {
-        switch (field) {
-            case ADMIN_AREA:
-                return ADMIN_ERROR_MESSAGES.get(mAdminLabel);
-            case LOCALITY:
-                return R.string.invalid_locality_label;
-            case DEPENDENT_LOCALITY:
-                return R.string.invalid_dependent_locality_label;
-            case POSTAL_CODE:
-                return (mZipLabel == ZipLabel.POSTAL
-                        ? R.string.invalid_postal_code_label
-                        : R.string.invalid_zip_code_label);
-            default:
-                return R.string.invalid_entry;
-        }
+  }
+
+  private void init(Context context, ViewGroup rootView, FormOptions formOptions,
+      ClientCacheManager cacheManager) {
+    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),
+          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<String> getEnvelopeAddress() {
+    return formatInterpreter.getEnvelopeAddress(getAddressData());
+  }
+
+  /**
+   * Gets the formatted address based on the AddressData passed in.
+   */
+  public List<String> 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<String> 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);
+  }
 }