Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(2884)

Unified Diff: chrome/android/java/src/org/chromium/chrome/browser/payments/AddressEditor.java

Issue 2093363002: Autofill address editor in PaymentRequest UI. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@contact-editor
Patch Set: Created 4 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: chrome/android/java/src/org/chromium/chrome/browser/payments/AddressEditor.java
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/payments/AddressEditor.java b/chrome/android/java/src/org/chromium/chrome/browser/payments/AddressEditor.java
new file mode 100644
index 0000000000000000000000000000000000000000..51103f3d3085a5ee3652873f880d75df15a66e17
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/payments/AddressEditor.java
@@ -0,0 +1,302 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.payments;
+
+import android.os.Handler;
+import android.telephony.PhoneNumberUtils;
+import android.text.TextUtils;
+
+import org.chromium.base.Callback;
+import org.chromium.chrome.R;
+import org.chromium.chrome.browser.autofill.PersonalDataManager;
+import org.chromium.chrome.browser.autofill.PersonalDataManager.AutofillProfile;
+import org.chromium.chrome.browser.payments.ui.EditorFieldModel;
+import org.chromium.chrome.browser.payments.ui.EditorFieldModel.EditorFieldValidator;
+import org.chromium.chrome.browser.payments.ui.EditorFieldModel.SpinnerChangedEventData;
+import org.chromium.chrome.browser.payments.ui.EditorModel;
+import org.chromium.chrome.browser.preferences.autofill.AutofillProfileBridge;
+import org.chromium.chrome.browser.preferences.autofill.AutofillProfileBridge.AddressField;
+import org.chromium.chrome.browser.preferences.autofill.AutofillProfileBridge.AddressUiComponent;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Set;
+
+import javax.annotation.Nullable;
+
+/**
+ * An address editor. Can be used for either shipping or billing address editing.
+ */
+public class AddressEditor extends EditorBase<AutofillAddress> {
+ private final Handler mHandler;
+ private final Map<Integer, EditorFieldModel> mAddressFields;
+ private final List<CharSequence> mAllPhoneNumbers;
gone 2016/06/28 17:30:28 Same comment about "All" as the other CL
please use gerrit instead 2016/06/29 00:28:45 Done.
+ @Nullable private AutofillProfileBridge mAutofillProfileBridge;
+ @Nullable private EditorFieldModel mCountryField;
+ @Nullable private EditorFieldModel mPhoneField;
+ @Nullable private EditorFieldValidator mPhoneValidator;
+ @Nullable private List<AddressUiComponent> mAddressUiComponents;
+
+ /**
+ * Builds an address editor.
+ */
+ public AddressEditor() {
+ mHandler = new Handler();
+ mAddressFields = new HashMap<>();
+ mAllPhoneNumbers = new ArrayList<>();
+ }
+
+ /**
+ * Returns whether the given profile can be sent to the merchant as-is without editing first. If
+ * the country code is not set or invalid, but all fields for the default locale's country code
+ * are present, then the profile is deemed "complete." AutoflllAddress.toPaymentAddress() will
+ * use the default locale to fill in a blank country code before sending the address to the
+ * renderer.
+ *
+ * @param profile The profile to check.
+ * @return Whether the profile is complete.
+ */
+ public boolean isProfileComplete(@Nullable AutofillProfile profile) {
+ if (profile == null || TextUtils.isEmpty(profile.getFullName())
+ || !getPhoneValidator().isValid(profile.getPhoneNumber())) {
+ return false;
+ }
+
+ List<Integer> requiredFields = AutofillProfileBridge.getRequiredAddressFields(
+ AutofillAddress.getCountryCode(profile));
+ for (int i = 0; i < requiredFields.size(); i++) {
+ if (TextUtils.isEmpty(getProfileField(profile, requiredFields.get(i)))) return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * Adds the given phone number to the autocomplete list, if it's valid.
+ *
+ * @param phoneNumber The phone number to possibly add.
+ */
+ public void addPhoneNumberIfValid(@Nullable CharSequence phoneNumber) {
+ if (getPhoneValidator().isValid(phoneNumber)) mAllPhoneNumbers.add(phoneNumber);
+ }
+
+ @Override
+ public void edit(@Nullable AutofillAddress toEdit, final Callback<AutofillAddress> callback) {
+ super.edit(toEdit, callback);
+
+ if (mAutofillProfileBridge == null) mAutofillProfileBridge = new AutofillProfileBridge();
+
+ final AutofillAddress address = toEdit == null
+ ? new AutofillAddress(new AutofillProfile(), false) : toEdit;
+ final AutofillProfile profile = address.getProfile();
+
+ final EditorModel editor = new EditorModel(
+ mContext.getString(toEdit == null ? R.string.payments_add_address_label
+ : R.string.payments_edit_address_label));
+
+ if (mCountryField == null) {
+ mCountryField = new EditorFieldModel(
+ mContext.getString(R.string.autofill_profile_editor_country),
+ AutofillProfileBridge.getSupportedCountries());
+ }
+ mCountryField.setValue(AutofillAddress.getCountryCode(profile));
+ mCountryField.setSpinnerCallback(new Callback<SpinnerChangedEventData>() {
gone 2016/06/28 17:30:28 You really, really need to add comments all over t
please use gerrit instead 2016/06/29 00:28:45 Done.
+ @Override
+ public void onResult(SpinnerChangedEventData eventData) {
+ editor.removeAllFields();
+ editor.addField(mCountryField);
+ addAddressTextFieldsToEditor(
+ editor, eventData.key, Locale.getDefault().getLanguage());
+ editor.addField(mPhoneField);
+ mHandler.post(eventData.callback);
+ }
+ });
+ editor.addField(mCountryField);
+
+ if (mAddressFields.isEmpty()) {
gone 2016/06/28 17:30:28 Adding a bunch of default fields?
please use gerrit instead 2016/06/29 00:28:45 Added a comment: // There's a finite number of fi
+ mAddressFields.put(AddressField.LOCALITY, new EditorFieldModel(0));
+ mAddressFields.put(AddressField.DEPENDENT_LOCALITY, new EditorFieldModel(0));
+ mAddressFields.put(AddressField.ORGANIZATION, new EditorFieldModel(0));
+ mAddressFields.put(AddressField.ADMIN_AREA,
+ new EditorFieldModel(EditorFieldModel.INPUT_TYPE_HINT_REGION));
+ mAddressFields.put(AddressField.SORTING_CODE,
+ new EditorFieldModel(EditorFieldModel.INPUT_TYPE_HINT_ALPHA_NUMERIC));
+ mAddressFields.put(AddressField.POSTAL_CODE,
+ new EditorFieldModel(EditorFieldModel.INPUT_TYPE_HINT_ALPHA_NUMERIC));
+ mAddressFields.put(AddressField.STREET_ADDRESS,
+ new EditorFieldModel(EditorFieldModel.INPUT_TYPE_HINT_STREET_LINES));
+ mAddressFields.put(AddressField.RECIPIENT,
+ new EditorFieldModel(EditorFieldModel.INPUT_TYPE_HINT_PERSON_NAME));
+ }
+ for (Map.Entry<Integer, EditorFieldModel> entry : mAddressFields.entrySet()) {
+ entry.getValue().setValue(getProfileField(profile, entry.getKey()));
+ }
+ addAddressTextFieldsToEditor(editor, profile.getCountryCode(), profile.getLanguageCode());
+
+ if (mPhoneField == null) {
+ mPhoneField = new EditorFieldModel(EditorFieldModel.INPUT_TYPE_HINT_PHONE,
+ mContext.getString(R.string.autofill_profile_editor_phone_number),
+ mAllPhoneNumbers, getPhoneValidator(),
+ mContext.getString(R.string.payments_address_field_required_validation_message),
+ mContext.getString(R.string.payments_phone_invalid_validation_message), null);
+ }
+ mPhoneField.setValue(profile.getPhoneNumber());
+ editor.addField(mPhoneField);
+
+ editor.setCancelCallback(new Runnable() {
+ @Override
+ public void run() {
+ callback.onResult(null);
+ }
+ });
+
+ editor.setDoneCallback(new Runnable() {
+ @Override
+ public void run() {
+ profile.setCountryCode(mCountryField.getValue().toString());
gone 2016/06/28 17:30:28 Pull all this out into a function called "commitCh
please use gerrit instead 2016/06/29 00:28:45 Done.
+ profile.setPhoneNumber(mPhoneField.getValue().toString());
+ profile.setLanguageCode(mAutofillProfileBridge.getCurrentBestLanguageCode());
+
+ Set<Integer> visibleFields = new HashSet<>();
+ for (int i = 0; i < mAddressUiComponents.size(); i++) {
+ AddressUiComponent component = mAddressUiComponents.get(i);
+ visibleFields.add(component.id);
+ if (component.id != AddressField.COUNTRY) {
+ setProfileField(profile, component.id,
+ mAddressFields.get(component.id).getValue());
+ }
+ }
+
+ // Clear the fields that are hidden from the user interface, so
+ // AutofillAddress.toPaymentAddress() will send them to the renderer as empty
+ // strings.
+ for (Map.Entry<Integer, EditorFieldModel> entry : mAddressFields.entrySet()) {
+ if (!visibleFields.contains(entry.getKey())) {
+ setProfileField(profile, entry.getKey(), "");
+ }
+ }
+
+ PersonalDataManager pmd = PersonalDataManager.getInstance();
+ pmd.setProfile(profile);
+ profile.setLabel(pmd.getGetAddressLabelForPaymentRequest(profile));
+ address.completeAddress(profile);
+ callback.onResult(address);
+ }
+ });
+
+ mEditorView.show(editor);
+ }
+
+ private static String getProfileField(AutofillProfile profile, int field) {
+ assert profile != null;
+ switch (field) {
+ case AddressField.COUNTRY:
+ return profile.getCountryCode();
+ case AddressField.ADMIN_AREA:
+ return profile.getRegion();
+ case AddressField.LOCALITY:
+ return profile.getLocality();
+ case AddressField.DEPENDENT_LOCALITY:
+ return profile.getDependentLocality();
+ case AddressField.SORTING_CODE:
+ return profile.getSortingCode();
+ case AddressField.POSTAL_CODE:
+ return profile.getPostalCode();
+ case AddressField.STREET_ADDRESS:
+ return profile.getStreetAddress();
+ case AddressField.ORGANIZATION:
+ return profile.getCompanyName();
+ case AddressField.RECIPIENT:
+ return profile.getFullName();
+ }
+
+ assert false;
+ return null;
+ }
+
+ private static void setProfileField(
+ AutofillProfile profile, int field, @Nullable CharSequence value) {
+ assert profile != null;
+ switch (field) {
+ case AddressField.COUNTRY:
+ profile.setCountryCode(ensureNotNull(value));
+ return;
+ case AddressField.ADMIN_AREA:
+ profile.setRegion(ensureNotNull(value));
+ return;
+ case AddressField.LOCALITY:
+ profile.setLocality(ensureNotNull(value));
+ return;
+ case AddressField.DEPENDENT_LOCALITY:
+ profile.setDependentLocality(ensureNotNull(value));
+ return;
+ case AddressField.SORTING_CODE:
+ profile.setSortingCode(ensureNotNull(value));
+ return;
+ case AddressField.POSTAL_CODE:
+ profile.setPostalCode(ensureNotNull(value));
+ return;
+ case AddressField.STREET_ADDRESS:
+ profile.setStreetAddress(ensureNotNull(value));
+ return;
+ case AddressField.ORGANIZATION:
+ profile.setCompanyName(ensureNotNull(value));
+ return;
+ case AddressField.RECIPIENT:
+ profile.setFullName(ensureNotNull(value));
+ return;
+ }
+
+ assert false;
+ }
+
+ private static String ensureNotNull(@Nullable CharSequence value) {
+ return value == null ? "" : value.toString();
+ }
+
+ private void addAddressTextFieldsToEditor(
+ EditorModel container, String countryCode, String languageCode) {
+ mAddressUiComponents = mAutofillProfileBridge.getAddressUiComponents(countryCode,
+ languageCode);
+
+ for (int i = 0; i < mAddressUiComponents.size(); i++) {
+ AddressUiComponent component = mAddressUiComponents.get(i);
+ if (component.id == AddressField.COUNTRY) continue;
+
+ EditorFieldModel field = mAddressFields.get(component.id);
+ field.setLabel(component.label);
+ field.setIsFullLine(component.isFullLine);
+
+ // Libaddressinput formats do not always require the full name (RECIPIENT), but
+ // PaymentRequest does.
+ if (component.isRequired || component.id == AddressField.RECIPIENT) {
+ field.setRequiredErrorMessage(mContext.getString(
+ R.string.payments_address_field_required_validation_message));
+ } else {
+ field.setRequiredErrorMessage(null);
+ }
+
+ container.addField(field);
+ }
+ }
+
+ private EditorFieldValidator getPhoneValidator() {
+ if (mPhoneValidator == null) {
+ mPhoneValidator = new EditorFieldValidator() {
+ @Override
+ public boolean isValid(@Nullable CharSequence value) {
+ return value != null
+ && PhoneNumberUtils.isGlobalPhoneNumber(
+ PhoneNumberUtils.stripSeparators(value.toString()));
+ }
+ };
+ }
+ return mPhoneValidator;
+ }
+}

Powered by Google App Engine
This is Rietveld 408576698