Refactor contact editor controller into its own class.
BUG=603635
Review-Url: https://codereview.chromium.org/2092083003
Cr-Commit-Position: refs/heads/master@{#402352}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/payments/ContactEditor.java b/chrome/android/java/src/org/chromium/chrome/browser/payments/ContactEditor.java
new file mode 100644
index 0000000..ddc48d6
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/payments/ContactEditor.java
@@ -0,0 +1,191 @@
+// 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.content.Context;
+import android.telephony.PhoneNumberUtils;
+import android.util.Patterns;
+
+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.EditorModel;
+import org.chromium.chrome.browser.payments.ui.EditorView;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.annotation.Nullable;
+
+/**
+ * Contact information editor.
+ */
+public class ContactEditor {
+ private final boolean mRequestPayerPhone;
+ private final boolean mRequestPayerEmail;
+ private final List<CharSequence> mPhoneNumbers;
+ private final List<CharSequence> mEmailAddresses;
+ @Nullable private EditorView mEditorView;
+ @Nullable private Context mContext;
+ @Nullable private EditorFieldValidator mPhoneValidator;
+ @Nullable private EditorFieldValidator mEmailValidator;
+
+ /**
+ * Builds a contact information editor.
+ *
+ * @param requestPayerPhone Whether to request the user's phone number.
+ * @param requestPayerEmail Whether to request the user's email address.
+ */
+ public ContactEditor(boolean requestPayerPhone, boolean requestPayerEmail) {
+ assert requestPayerPhone || requestPayerEmail;
+ mRequestPayerPhone = requestPayerPhone;
+ mRequestPayerEmail = requestPayerEmail;
+ mPhoneNumbers = new ArrayList<>();
+ mEmailAddresses = new ArrayList<>();
+ }
+
+ /**
+ * Returns whether the following contact information can be sent to the merchant as-is without
+ * editing first.
+ *
+ * @param phone The phone number to check.
+ * @param email The email address to check.
+ * @return Whether the contact information is complete.
+ */
+ public boolean isContactInformationComplete(@Nullable String phone, @Nullable String email) {
+ return (!mRequestPayerPhone || getPhoneValidator().isValid(phone))
+ && (!mRequestPayerEmail || getEmailValidator().isValid(email));
+ }
+
+ /**
+ * Sets the user interface to be used for editing contact information.
+ *
+ * @param editorView The user interface to be used.
+ */
+ public void setEditorView(EditorView editorView) {
+ assert editorView != null;
+ mEditorView = editorView;
+ mContext = mEditorView.getContext();
+ }
+
+ /**
+ * 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)) mPhoneNumbers.add(phoneNumber);
+ }
+
+ /**
+ * Adds the given email address to the autocomplete list, if it's valid.
+ *
+ * @param emailAddress The email address to possibly add.
+ */
+ public void addEmailAddressIfValid(@Nullable CharSequence emailAddress) {
+ if (getEmailValidator().isValid(emailAddress)) mEmailAddresses.add(emailAddress);
+ }
+
+ /**
+ * Shows the user interface for editing the given contact. The contact is also updated on disk,
+ * so there's no need to do that in the calling code.
+ *
+ * @param toEdit The contact to edit. Can be null if the user is adding a new contact instead
+ * of editing an existing one.
+ * @param callback The callback to invoke with the complete and valid contact information. Can
+ * be invoked with null if the user clicked Cancel.
+ */
+ public void editContact(
+ @Nullable AutofillContact toEdit, final Callback<AutofillContact> callback) {
+ assert mEditorView != null;
+ assert mContext != null;
+
+ final AutofillContact contact = toEdit == null
+ ? new AutofillContact(new AutofillProfile(), null, null, false) : toEdit;
+
+ final EditorFieldModel phoneField = mRequestPayerPhone
+ ? new EditorFieldModel(EditorFieldModel.INPUT_TYPE_HINT_PHONE,
+ mContext.getString(R.string.autofill_profile_editor_phone_number),
+ mPhoneNumbers, getPhoneValidator(),
+ mContext.getString(R.string.payments_phone_required_validation_message),
+ mContext.getString(R.string.payments_phone_invalid_validation_message),
+ contact.getPayerPhone())
+ : null;
+
+ final EditorFieldModel emailField = mRequestPayerEmail
+ ? new EditorFieldModel(EditorFieldModel.INPUT_TYPE_HINT_EMAIL,
+ mContext.getString(R.string.autofill_profile_editor_email_address),
+ mEmailAddresses, getEmailValidator(),
+ mContext.getString(R.string.payments_email_required_validation_message),
+ mContext.getString(R.string.payments_email_invalid_validation_message),
+ contact.getPayerEmail())
+ : null;
+
+ EditorModel editor =
+ new EditorModel(mContext.getString(R.string.payments_add_contact_details_label));
+ if (phoneField != null) editor.addField(phoneField);
+ if (emailField != null) editor.addField(emailField);
+
+ editor.setCancelCallback(new Runnable() {
+ @Override
+ public void run() {
+ callback.onResult(null);
+ }
+ });
+
+ editor.setDoneCallback(new Runnable() {
+ @Override
+ public void run() {
+ String phone = null;
+ String email = null;
+
+ if (phoneField != null) {
+ phone = phoneField.getValue().toString();
+ contact.getProfile().setPhoneNumber(phone);
+ }
+
+ if (emailField != null) {
+ email = emailField.getValue().toString();
+ contact.getProfile().setEmailAddress(email);
+ }
+
+ PersonalDataManager.getInstance().setProfile(contact.getProfile());
+ contact.completeContact(phone, email);
+ callback.onResult(contact);
+ }
+ });
+
+ mEditorView.show(editor);
+ }
+
+ 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;
+ }
+
+ private EditorFieldValidator getEmailValidator() {
+ if (mEmailValidator == null) {
+ mEmailValidator = new EditorFieldValidator() {
+ @Override
+ public boolean isValid(@Nullable CharSequence value) {
+ return value != null && Patterns.EMAIL_ADDRESS.matcher(value).matches();
+ }
+ };
+ }
+ return mEmailValidator;
+ }
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentRequestImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentRequestImpl.java
index 99b9ae17..56f79dda 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentRequestImpl.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentRequestImpl.java
@@ -7,20 +7,14 @@
import android.app.Activity;
import android.graphics.Bitmap;
import android.os.Handler;
-import android.telephony.PhoneNumberUtils;
import android.text.TextUtils;
-import android.util.Patterns;
import org.chromium.base.Callback;
import org.chromium.base.Log;
import org.chromium.base.VisibleForTesting;
-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.favicon.FaviconHelper;
-import org.chromium.chrome.browser.payments.ui.EditorFieldModel;
-import org.chromium.chrome.browser.payments.ui.EditorFieldModel.EditorFieldValidator;
-import org.chromium.chrome.browser.payments.ui.EditorModel;
import org.chromium.chrome.browser.payments.ui.LineItem;
import org.chromium.chrome.browser.payments.ui.PaymentInformation;
import org.chromium.chrome.browser.payments.ui.PaymentOption;
@@ -135,12 +129,7 @@
private Pattern mRegionCodePattern;
private boolean mMerchantNeedsShippingAddress;
private boolean mPaymentAppRunning;
- private boolean mRequestPayerPhone;
- private boolean mRequestPayerEmail;
- private List<CharSequence> mAllPhoneNumbers;
- private List<CharSequence> mAllEmailAddresses;
- private EditorFieldValidator mPhoneValidator;
- private EditorFieldValidator mEmailValidator;
+ private ContactEditor mContactEditor;
/**
* Builds the PaymentRequest service implementation.
@@ -227,30 +216,31 @@
mMerchantNeedsShippingAddress =
requestShipping && mUiShippingOptions.getSelectedItem() == null;
- mRequestPayerPhone = options != null && options.requestPayerPhone;
- mRequestPayerEmail = options != null && options.requestPayerEmail;
+ boolean requestPayerPhone = options != null && options.requestPayerPhone;
+ boolean requestPayerEmail = options != null && options.requestPayerEmail;
+ if (requestPayerPhone || requestPayerEmail) {
+ mContactEditor = new ContactEditor(requestPayerPhone, requestPayerEmail);
+ }
- if (requestShipping || mRequestPayerPhone || mRequestPayerEmail) {
+ if (requestShipping || requestPayerPhone || requestPayerEmail) {
List<AutofillProfile> profiles =
PersonalDataManager.getInstance().getProfilesToSuggest();
List<AutofillContact> contacts = new ArrayList<>();
List<AutofillAddress> addresses = new ArrayList<>();
- mAllPhoneNumbers = new ArrayList<>();
- mAllEmailAddresses = new ArrayList<>();
int firstCompleteContactIndex = SectionInformation.NO_SELECTION;
for (int i = 0; i < profiles.size(); i++) {
AutofillProfile profile = profiles.get(i);
- String phone = mRequestPayerPhone && !TextUtils.isEmpty(profile.getPhoneNumber())
+ String phone = requestPayerPhone && !TextUtils.isEmpty(profile.getPhoneNumber())
? profile.getPhoneNumber() : null;
- String email = mRequestPayerEmail && !TextUtils.isEmpty(profile.getEmailAddress())
+ String email = requestPayerEmail && !TextUtils.isEmpty(profile.getEmailAddress())
? profile.getEmailAddress() : null;
if (phone != null || email != null) {
- boolean isComplete = isContactInformationComplete(phone, email);
+ boolean isComplete = mContactEditor.isContactInformationComplete(phone, email);
contacts.add(new AutofillContact(profile, phone, email, isComplete));
if (isComplete && firstCompleteContactIndex < 0) firstCompleteContactIndex = i;
- if (getPhoneValidator().isValid(phone)) mAllPhoneNumbers.add(phone);
- if (getEmailValidator().isValid(email)) mAllEmailAddresses.add(email);
+ mContactEditor.addPhoneNumberIfValid(phone);
+ mContactEditor.addEmailAddressIfValid(email);
}
if (canUseAddress(profile, requestShipping)) {
@@ -268,7 +258,7 @@
}
// The contact section automatically selects the first complete entry.
- if (mRequestPayerPhone || mRequestPayerEmail) {
+ if (requestPayerPhone || requestPayerEmail) {
mContactSection = new SectionInformation(
PaymentRequestUI.TYPE_CONTACT_DETAILS, firstCompleteContactIndex, contacts);
}
@@ -295,9 +285,12 @@
}
mUI = new PaymentRequestUI(mContext, this, requestShipping,
- mRequestPayerPhone || mRequestPayerEmail, mMerchantName, mOrigin);
+ requestPayerPhone || requestPayerEmail, mMerchantName, mOrigin);
+
if (mFavicon != null) mUI.setTitleBitmap(mFavicon);
mFavicon = null;
+
+ if (mContactEditor != null) mContactEditor.setEditorView(mUI.getEditorView());
}
private static HashMap<String, JSONObject> getValidatedMethodData(
@@ -335,11 +328,6 @@
return result;
}
- private boolean isContactInformationComplete(String phone, String email) {
- return (!mRequestPayerPhone || getPhoneValidator().isValid(phone))
- && (!mRequestPayerEmail || getEmailValidator().isValid(email));
- }
-
private boolean canUseAddress(AutofillProfile profile, boolean requestShipping) {
return requestShipping && profile.getCountryCode() != null
&& mRegionCodePattern.matcher(profile.getCountryCode()).matches()
@@ -621,93 +609,6 @@
return false;
}
- private void editContact(final AutofillContact contact) {
- final EditorFieldModel phoneField = mRequestPayerPhone
- ? new EditorFieldModel(EditorFieldModel.INPUT_TYPE_HINT_PHONE,
- mContext.getString(R.string.autofill_profile_editor_phone_number),
- mAllPhoneNumbers, getPhoneValidator(),
- mContext.getString(R.string.payments_phone_required_validation_message),
- mContext.getString(R.string.payments_phone_invalid_validation_message),
- contact == null ? null : contact.getPayerPhone())
- : null;
-
- final EditorFieldModel emailField = mRequestPayerEmail
- ? new EditorFieldModel(EditorFieldModel.INPUT_TYPE_HINT_EMAIL,
- mContext.getString(R.string.autofill_profile_editor_email_address),
- mAllEmailAddresses, getEmailValidator(),
- mContext.getString(R.string.payments_email_required_validation_message),
- mContext.getString(R.string.payments_email_invalid_validation_message),
- contact == null ? null : contact.getPayerEmail())
- : null;
-
- EditorModel editor =
- new EditorModel(mContext.getString(R.string.payments_add_contact_details_label));
- if (phoneField != null) editor.addField(phoneField);
- if (emailField != null) editor.addField(emailField);
-
- editor.setCancelCallback(new Runnable() {
- @Override
- public void run() {
- mContactSection.setSelectedItemIndex(SectionInformation.NO_SELECTION);
- mUI.updateSection(PaymentRequestUI.TYPE_CONTACT_DETAILS, mContactSection);
- }
- });
-
- editor.setDoneCallback(new Runnable() {
- @Override
- public void run() {
- AutofillProfile profile =
- contact != null ? contact.getProfile() : new AutofillProfile();
- String phone = null;
- String email = null;
- if (phoneField != null) {
- phone = phoneField.getValue().toString();
- profile.setPhoneNumber(phone);
- }
- if (emailField != null) {
- email = emailField.getValue().toString();
- profile.setEmailAddress(email);
- }
- PersonalDataManager.getInstance().setProfile(profile);
-
- if (contact == null) {
- mContactSection.addAndSelectItem(
- new AutofillContact(profile, phone, email, true));
- } else {
- contact.completeContact(phone, email);
- }
- mUI.updateSection(PaymentRequestUI.TYPE_CONTACT_DETAILS, mContactSection);
- }
- });
- mUI.showEditor(editor);
- }
-
- private EditorFieldValidator getPhoneValidator() {
- if (mPhoneValidator == null) {
- mPhoneValidator = new EditorFieldValidator() {
- @Override
- public boolean isValid(CharSequence value) {
- return value != null
- && PhoneNumberUtils.isGlobalPhoneNumber(
- PhoneNumberUtils.stripSeparators(value.toString()));
- }
- };
- }
- return mPhoneValidator;
- }
-
- private EditorFieldValidator getEmailValidator() {
- if (mEmailValidator == null) {
- mEmailValidator = new EditorFieldValidator() {
- @Override
- public boolean isValid(CharSequence value) {
- return value != null && Patterns.EMAIL_ADDRESS.matcher(value).matches();
- }
- };
- }
- return mEmailValidator;
- }
-
@Override
public void onSectionAddOption(@PaymentRequestUI.DataType int optionType) {
if (optionType == PaymentRequestUI.TYPE_SHIPPING_ADDRESSES) {
@@ -720,6 +621,21 @@
}
}
+ private void editContact(final AutofillContact toEdit) {
+ mContactEditor.editContact(toEdit, new Callback<AutofillContact>() {
+ @Override
+ public void onResult(AutofillContact completeContact) {
+ if (completeContact == null) {
+ mContactSection.setSelectedItemIndex(SectionInformation.NO_SELECTION);
+ } else if (toEdit == null) {
+ mContactSection.addAndSelectItem(completeContact);
+ }
+
+ mUI.updateSection(PaymentRequestUI.TYPE_CONTACT_DETAILS, mContactSection);
+ }
+ });
+ }
+
@Override
public void onPayClicked(PaymentOption selectedShippingAddress,
PaymentOption selectedShippingOption, PaymentOption selectedPaymentMethod) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/payments/ui/EditorView.java b/chrome/android/java/src/org/chromium/chrome/browser/payments/ui/EditorView.java
index c673af7..9996db1 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/payments/ui/EditorView.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/payments/ui/EditorView.java
@@ -334,6 +334,8 @@
prepareToolbar();
prepareButtons();
prepareEditor();
+ getWindow().setLayout(ViewGroup.LayoutParams.MATCH_PARENT,
+ ViewGroup.LayoutParams.MATCH_PARENT);
show();
// Immediately focus the first invalid field to make it faster to edit.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/payments/ui/PaymentRequestUI.java b/chrome/android/java/src/org/chromium/chrome/browser/payments/ui/PaymentRequestUI.java
index ae91771..7e15a3a 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/payments/ui/PaymentRequestUI.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/payments/ui/PaymentRequestUI.java
@@ -582,13 +582,9 @@
}
}
- /**
- * Displays the editor user interface for the given model.
- *
- * @param editorModel The description of the editor user interface to display.
- */
- public void showEditor(final EditorModel editorModel) {
- mEditorView.show(editorModel);
+ /** @return The editor user interface. */
+ public EditorView getEditorView() {
+ return mEditorView;
}
/**
@@ -1016,11 +1012,6 @@
}
@VisibleForTesting
- public Dialog getEditorViewForTest() {
- return mEditorView;
- }
-
- @VisibleForTesting
public ViewGroup getShippingAddressSectionForTest() {
return mShippingAddressSection;
}
diff --git a/chrome/android/java_sources.gni b/chrome/android/java_sources.gni
index ad2972d..c62fd62 100644
--- a/chrome/android/java_sources.gni
+++ b/chrome/android/java_sources.gni
@@ -579,6 +579,7 @@
"java/src/org/chromium/chrome/browser/payments/AutofillContact.java",
"java/src/org/chromium/chrome/browser/payments/AutofillPaymentApp.java",
"java/src/org/chromium/chrome/browser/payments/AutofillPaymentInstrument.java",
+ "java/src/org/chromium/chrome/browser/payments/ContactEditor.java",
"java/src/org/chromium/chrome/browser/payments/CurrencyStringFormatter.java",
"java/src/org/chromium/chrome/browser/payments/PaymentApp.java",
"java/src/org/chromium/chrome/browser/payments/PaymentAppFactory.java",
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestTestBase.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestTestBase.java
index 126a02a..e7149b74 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestTestBase.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestTestBase.java
@@ -140,7 +140,7 @@
ThreadUtils.runOnUiThreadBlocking(new Runnable() {
@Override
public void run() {
- mUI.getEditorViewForTest().findViewById(resourceId).performClick();
+ mUI.getEditorView().findViewById(resourceId).performClick();
}
});
helper.waitForCallback(callCount);
@@ -176,7 +176,7 @@
ThreadUtils.runOnUiThreadBlocking(new Runnable() {
@Override
public void run() {
- ((EditText) mUI.getEditorViewForTest().findViewById(resourceId)).setText(input);
+ ((EditText) mUI.getEditorView().findViewById(resourceId)).setText(input);
}
});
}