Commit ed717079 authored by rouslan's avatar rouslan Committed by Commit bot
Browse files

Refactor contact editor controller into its own class.

BUG=603635

Review-Url: https://codereview.chromium.org/2092083003
Cr-Commit-Position: refs/heads/master@{#402352}
parent 210d15f8
// 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;
}
}
......@@ -7,20 +7,14 @@ package org.chromium.chrome.browser.payments;
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 @@ public class PaymentRequestImpl implements PaymentRequest, PaymentRequestUI.Clie
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 @@ public class PaymentRequestImpl implements PaymentRequest, PaymentRequestUI.Clie
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 @@ public class PaymentRequestImpl implements PaymentRequest, PaymentRequestUI.Clie
}
// 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 @@ public class PaymentRequestImpl implements PaymentRequest, PaymentRequestUI.Clie
}
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 @@ public class PaymentRequestImpl implements PaymentRequest, PaymentRequestUI.Clie
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 @@ public class PaymentRequestImpl implements PaymentRequest, PaymentRequestUI.Clie
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 @@ public class PaymentRequestImpl implements PaymentRequest, PaymentRequestUI.Clie
}
}
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) {
......
......@@ -334,6 +334,8 @@ public class EditorView extends AlwaysDismissedDialog
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.
......
......@@ -582,13 +582,9 @@ public class PaymentRequestUI implements DialogInterface.OnDismissListener, View
}
}
/**
* 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;
}
/**
......@@ -1015,11 +1011,6 @@ public class PaymentRequestUI implements DialogInterface.OnDismissListener, View
return mDialog;
}
@VisibleForTesting
public Dialog getEditorViewForTest() {
return mEditorView;
}
@VisibleForTesting
public ViewGroup getShippingAddressSectionForTest() {
return mShippingAddressSection;
......
......@@ -579,6 +579,7 @@ chrome_java_sources = [
"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",
......
......@@ -140,7 +140,7 @@ abstract class PaymentRequestTestBase extends ChromeActivityTestCaseBase<ChromeA
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 @@ abstract class PaymentRequestTestBase extends ChromeActivityTestCaseBase<ChromeA
ThreadUtils.runOnUiThreadBlocking(new Runnable() {
@Override
public void run() {
((EditText) mUI.getEditorViewForTest().findViewById(resourceId)).setText(input);
((EditText) mUI.getEditorView().findViewById(resourceId)).setText(input);
}
});
}
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment