blob: 76cd12a360ffbb0522f09f2c0beb6655aaa7d55f [file] [log] [blame]
/*
* Copyright (C) 2010 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.i18n.addressinput;
import android.app.ProgressDialog;
import android.content.Context;
import android.os.Handler;
import android.telephony.TelephonyManager;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.LinearLayout.LayoutParams;
import android.widget.Spinner;
import android.widget.TextView;
import com.android.i18n.addressinput.AddressField.WidthType;
import com.android.i18n.addressinput.AddressUiComponent.UiComponent;
import com.android.i18n.addressinput.LookupKey.KeyType;
import com.android.i18n.addressinput.LookupKey.ScriptType;
import java.text.Collator;
import java.util.ArrayList;
import java.util.Collections;
import java.util.EnumMap;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
/**
* Address widget that lays out address fields, validate and format addresses according to local
* customs.
*/
public class AddressWidget implements AdapterView.OnItemSelectedListener {
private Context mContext;
private ViewGroup mRootView;
private LayoutInflater mInflater;
private CacheData mCacheData;
// A map for all address fields except for country.
private final EnumMap<AddressField, AddressUiComponent> mInputWidgets =
new EnumMap<AddressField, AddressUiComponent>(AddressField.class);
private FormController mFormController;
private FormatInterpreter mFormatInterpreter;
private FormOptions mFormOptions;
private StandardAddressVerifier mVerifier;
private ProgressDialog mProgressDialog;
private String mCurrentRegion;
// 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;
private ScriptType mScript;
// The appropriate label that should be applied to the locality (city) field of the current
// country. Examples include "city" or "district".
private String mLocalityLabel;
// 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 Map<String, Integer> ADMIN_LABELS;
private static final Map<String, Integer> LOCALITY_LABELS;
private static final Map<String, Integer> ADMIN_ERROR_MESSAGES;
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<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("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> 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);
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("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);
}
// 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;
public UpdateRunnable(AddressField id) {
myId = id;
}
@Override
public void run() {
updateInputWidget(myId);
}
}
private static class AddressSpinnerInfo {
private Spinner mView;
private AddressField mId;
private AddressField mParentId;
private ArrayAdapter<String> mAdapter;
private List<RegionData> mCurrentRegions;
@SuppressWarnings("unchecked")
public AddressSpinnerInfo(Spinner view, AddressField id, AddressField parentId) {
mView = view;
mId = id;
mParentId = parentId;
mAdapter = (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);
}
}
// 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 for the region value.
public String getRegionDataKeyForValue(String value) {
for (RegionData data : mCurrentRegions) {
if (data.getDisplayName().endsWith(value)) {
return data.getKey();
}
}
return "";
}
}
private final ArrayList<AddressSpinnerInfo> mSpinners = new ArrayList<AddressSpinnerInfo>();
private AddressWidgetUiComponentProvider mComponentProvider;
/** 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.
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);
}
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 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 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 layoutAddressFields() {
for (AddressField field : mFormatInterpreter.getAddressFieldOrder(mScript,
mCurrentRegion)) {
if (!mFormOptions.isHidden(field)) {
createView(mRootView, mInputWidgets.get(field), "", mFormOptions.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);
}
});
}
public void updateWidgetOnCountryChange(String regionCode) {
if (mCurrentRegion.equalsIgnoreCase(regionCode)) {
return;
}
mCurrentRegion = regionCode;
mFormController.setCurrentCountry(mCurrentRegion);
renderForm();
}
private void updateInputWidget(AddressField myId) {
for (AddressSpinnerInfo child : mSpinners) {
if (child.mParentId == myId) {
List<RegionData> candidates = getRegionData(child.mParentId);
child.setSpinnerList(candidates, "");
}
}
}
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();
}
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);
}
}
}
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));
}
}
/**
* 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;
}
}
/**
* 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);
}
}
}
}
public View getViewForField(AddressField field) {
AddressUiComponent component = mInputWidgets.get(field);
if (component == null) {
return null;
}
return component.getView();
}
@Override
public void onNothingSelected(AdapterView<?> arg0) {
}
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
updateChildNodes(parent, position);
}
}