Commit 6c71598c authored by gogerald's avatar gogerald Committed by Commit bot

Show required information for contact details and set appropriate editor title

BUG=673855

Review-Url: https://codereview.chromium.org/2529043003
Cr-Commit-Position: refs/heads/master@{#438626}
parent d66436c2
......@@ -4,8 +4,10 @@
package org.chromium.chrome.browser.payments;
import android.content.Context;
import android.text.TextUtils;
import org.chromium.chrome.R;
import org.chromium.chrome.browser.autofill.PersonalDataManager.AutofillProfile;
import org.chromium.chrome.browser.payments.ui.PaymentOption;
......@@ -16,6 +18,7 @@ import javax.annotation.Nullable;
*/
public class AutofillContact extends PaymentOption {
private final AutofillProfile mProfile;
private final Context mContext;
@Nullable private String mPayerName;
@Nullable private String mPayerPhone;
@Nullable private String mPayerEmail;
......@@ -23,21 +26,23 @@ public class AutofillContact extends PaymentOption {
/**
* Builds contact details.
*
* @param profile The autofill profile where this contact data lives.
* @param name The payer name. If not empty, this will be the primary label.
* @param phone The phone number. If name is empty, this will be the primary label.
* @param email The email address. If name and phone are empty, this will be the primary
* label.
* @param isComplete Whether the data in this contact can be sent to the merchant as-is. If
* false, user needs to add more information here.
* @param context The application context.
* @param profile The autofill profile where this contact data lives.
* @param name The payer name. If not empty, this will be the primary label.
* @param phone The phone number. If name is empty, this will be the primary label.
* @param email The email address. If name and phone are empty, this will be the
* primary label.
* @param completionStatus The completion status of this contact.
*/
public AutofillContact(AutofillProfile profile, @Nullable String name,
@Nullable String phone, @Nullable String email, boolean isComplete) {
public AutofillContact(Context context, AutofillProfile profile, @Nullable String name,
@Nullable String phone, @Nullable String email,
@ContactEditor.CompletionStatus int completionStatus) {
super(profile.getGUID(), null, null, null, null);
mContext = context;
mProfile = profile;
mIsComplete = isComplete;
mIsEditable = true;
setContactInfo(profile.getGUID(), name, phone, email);
updateCompletionStatus(completionStatus);
}
/** @return Payer name. Null if the merchant did not request it or data is incomplete. */
......@@ -73,8 +78,8 @@ public class AutofillContact extends PaymentOption {
*/
public void completeContact(String guid, @Nullable String name,
@Nullable String phone, @Nullable String email) {
mIsComplete = true;
setContactInfo(guid, name, phone, email);
updateCompletionStatus(ContactEditor.COMPLETE);
}
private void setContactInfo(String guid, @Nullable String name,
......@@ -92,4 +97,33 @@ public class AutofillContact extends PaymentOption {
mPayerPhone == null ? null : mPayerEmail);
}
}
private void updateCompletionStatus(int completionStatus) {
mIsComplete = completionStatus == ContactEditor.COMPLETE;
switch (completionStatus) {
case ContactEditor.COMPLETE:
mEditMessage = null;
mEditTitle = mContext.getString(R.string.payments_edit_contact_details_label);
break;
case ContactEditor.INVALID_NAME:
mEditMessage = mContext.getString(R.string.payments_name_required);
mEditTitle = mContext.getString(R.string.payments_add_name);
break;
case ContactEditor.INVALID_EMAIL:
mEditMessage = mContext.getString(R.string.payments_email_required);
mEditTitle = mContext.getString(R.string.payments_add_email);
break;
case ContactEditor.INVALID_PHONE_NUMBER:
mEditMessage = mContext.getString(R.string.payments_phone_number_required);
mEditTitle = mContext.getString(R.string.payments_add_phone_number);
break;
case ContactEditor.INVALID_MULTIPLE_FIELDS:
mEditMessage = mContext.getString(R.string.payments_more_information_required);
mEditTitle = mContext.getString(R.string.payments_add_more_information);
break;
default:
assert false : "Invalid completion status code";
}
}
}
......@@ -4,6 +4,7 @@
package org.chromium.chrome.browser.payments;
import android.support.annotation.IntDef;
import android.telephony.PhoneNumberUtils;
import android.text.TextUtils;
import android.util.Patterns;
......@@ -16,6 +17,8 @@ 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 java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.HashSet;
import java.util.Set;
......@@ -25,6 +28,20 @@ import javax.annotation.Nullable;
* Contact information editor.
*/
public class ContactEditor extends EditorBase<AutofillContact> {
@IntDef({INVALID_NAME, INVALID_EMAIL, INVALID_PHONE_NUMBER, INVALID_MULTIPLE_FIELDS})
@Retention(RetentionPolicy.SOURCE)
public @interface CompletionStatus {}
/** Can be sent to the merchant as-is without editing first. */
public static final int COMPLETE = 0;
/** The contact name is missing. */
public static final int INVALID_NAME = 1;
/** The contact email is invalid or missing. */
public static final int INVALID_EMAIL = 2;
/** The contact phone number is invalid or missing. */
public static final int INVALID_PHONE_NUMBER = 3;
/** Multiple fields are invalid or missing. */
public static final int INVALID_MULTIPLE_FIELDS = 4;
private final boolean mRequestPayerName;
private final boolean mRequestPayerPhone;
private final boolean mRequestPayerEmail;
......@@ -53,19 +70,39 @@ public class ContactEditor extends EditorBase<AutofillContact> {
}
/**
* Returns whether the following contact information can be sent to the merchant as-is without
* editing first.
* Returns the contact completion status with the given name, phone and email.
*
* @param name The payer name to check.
* @param phone The phone number to check.
* @param email The email address to check.
* @return Whether the contact information is complete.
* @return The completion status.
*/
public boolean isContactInformationComplete(
@CompletionStatus
public int checkContactCompletionStatus(
@Nullable String name, @Nullable String phone, @Nullable String email) {
return (!mRequestPayerName || !TextUtils.isEmpty(name))
&& (!mRequestPayerPhone || getPhoneValidator().isValid(phone))
&& (!mRequestPayerEmail || getEmailValidator().isValid(email));
int invalidFieldCount = 0;
int completionStatus = COMPLETE;
if (mRequestPayerName && TextUtils.isEmpty(name)) {
invalidFieldCount++;
completionStatus = INVALID_NAME;
}
if (mRequestPayerPhone && !getPhoneValidator().isValid(phone)) {
invalidFieldCount++;
completionStatus = INVALID_PHONE_NUMBER;
}
if (mRequestPayerEmail && !getEmailValidator().isValid(email)) {
invalidFieldCount++;
completionStatus = INVALID_EMAIL;
}
if (invalidFieldCount > 1) {
completionStatus = INVALID_MULTIPLE_FIELDS;
}
return completionStatus;
}
/**
......@@ -101,7 +138,9 @@ public class ContactEditor extends EditorBase<AutofillContact> {
super.edit(toEdit, callback);
final AutofillContact contact = toEdit == null
? new AutofillContact(new AutofillProfile(), null, null, null, false) : toEdit;
? new AutofillContact(mContext, new AutofillProfile(), null, null, null,
INVALID_MULTIPLE_FIELDS)
: toEdit;
final EditorFieldModel nameField = mRequestPayerName
? EditorFieldModel.createTextInput(EditorFieldModel.INPUT_TYPE_HINT_PERSON_NAME,
......@@ -129,9 +168,10 @@ public class ContactEditor extends EditorBase<AutofillContact> {
contact.getPayerEmail())
: null;
EditorModel editor = new EditorModel(
mContext.getString(toEdit == null ? R.string.payments_add_contact_details_label
: R.string.payments_edit_contact_details_label));
EditorModel editor = new EditorModel(toEdit == null
? mContext.getString(R.string.payments_add_contact_details_label)
: toEdit.getEditTitle());
if (nameField != null) editor.addField(nameField);
if (phoneField != null) editor.addField(phoneField);
if (emailField != null) editor.addField(emailField);
......
......@@ -431,9 +431,11 @@ public class PaymentRequestImpl
if (!uniqueContactInfos.contains(uniqueContactInfo)) {
uniqueContactInfos.add(uniqueContactInfo);
boolean isComplete = mContactEditor.isContactInformationComplete(name,
phone, email);
contacts.add(new AutofillContact(profile, name, phone, email, isComplete));
@ContactEditor.CompletionStatus
int completionStatus =
mContactEditor.checkContactCompletionStatus(name, phone, email);
contacts.add(new AutofillContact(
mContext, profile, name, phone, email, completionStatus));
}
}
}
......
......@@ -2618,10 +2618,10 @@ You can control the Physical Web in Chrome Settings.
<message name="IDS_PAYMENTS_ADD_VALID_CARD_NUMBER" desc="The title of the dialog for user to add valid payment card number.">
Add valid card number
</message>
<message name="IDS_PAYMENTS_MORE_INFORMATION_REQUIRED" desc="The label to indicate more information is required for payment card.">
<message name="IDS_PAYMENTS_MORE_INFORMATION_REQUIRED" desc="The label to indicate more information is required for payment card or shipping address or contact info.">
More information required
</message>
<message name="IDS_PAYMENTS_ADD_MORE_INFORMATION" desc="The title of the dialog for user to add more information to payment card.">
<message name="IDS_PAYMENTS_ADD_MORE_INFORMATION" desc="The title of the dialog for user to add more information to payment card or shipping address or contact info.">
Add more information
</message>
<message name="IDS_PAYMENTS_EDIT_CARD" desc="The title of the dialog for user to edit payment card.">
......@@ -2630,10 +2630,10 @@ You can control the Physical Web in Chrome Settings.
<message name="IDS_PAYMENTS_CREDIT_CARD_EXPIRATION_DATE_ABBR" desc="Abbreviated label for credit card expiration date. [CHAR-LIMIT=32]">
Exp: <ph name="EXPIRATION_MONTH">%1$s<ex>06</ex></ph>/<ph name="EXPIRATION_YEAR">%2$s<ex>17</ex></ph>
</message>
<message name="IDS_PAYMENTS_PHONE_NUMBER_REQUIRED" desc="The label to indicate phone number is required in the shipping address. This phone number can be used, for example, if there's a problem with shipping a package to its destination.">
<message name="IDS_PAYMENTS_PHONE_NUMBER_REQUIRED" desc="The label to indicate phone number is required in the shipping address or contact info. This phone number can be used, for example, if there's a problem with shipping a package to its destination.">
Phone number required
</message>
<message name="IDS_PAYMENTS_ADD_PHONE_NUMBER" desc="The title of the dialog for user to add phone number to the shipping address. This phone number can be used, for example, if there's a problem with shipping a package to its destination.">
<message name="IDS_PAYMENTS_ADD_PHONE_NUMBER" desc="The title of the dialog for user to add phone number to the shipping address or contact info. This phone number can be used, for example, if there's a problem with shipping a package to its destination.">
Add phone number
</message>
<message name="IDS_PAYMENTS_RECIPIENT_REQUIRED" desc="The label to indicate recipient is required in the shipping address. The recipient could be a person or institute name identifies the receiver of the shipping package.">
......@@ -2648,6 +2648,18 @@ You can control the Physical Web in Chrome Settings.
<message name="IDS_PAYMENTS_ADD_VALID_ADDRESS" desc="The title of the dialog for user to add valid shipping address. For example, missing state or city name.">
Add valid address
</message>
<message name="IDS_PAYMENTS_EMAIL_REQUIRED" desc="The label to indicate email is required for the contact details. This email can be used to contact the payer.">
Email required
</message>
<message name="IDS_PAYMENTS_ADD_EMAIL" desc="The title of the dialog for user to add email to the contact details. This email can be used to contact the payer.">
Add email
</message>
<message name="IDS_PAYMENTS_NAME_REQUIRED" desc="The label to indicate name is required for the contact details. This name could be a person or institute name of the payer.">
Name required
</message>
<message name="IDS_PAYMENTS_ADD_NAME" desc="The title of the dialog for user to add name to the contact details. This name could be a person or institute name of the payer.">
Add name
</message>
<message name="IDS_PAYMENTS_ORDER_SUMMARY_LABEL" desc="The title of the section that shows the summary of the order, including names and prices of individual line items, i.e. the bill.">
Order summary
</message>
......
......@@ -10,18 +10,55 @@ import org.chromium.base.test.util.Feature;
import org.chromium.chrome.R;
import org.chromium.chrome.browser.autofill.AutofillTestHelper;
import org.chromium.chrome.browser.autofill.PersonalDataManager.AutofillProfile;
import org.chromium.chrome.browser.autofill.PersonalDataManager.CreditCard;
import java.util.ArrayList;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeoutException;
/**
* A payment integration test for a merchant that requests contact details and a user that has
* 5 contact detail options.
* multiple contact detail options.
*/
public class PaymentRequestMultipleContactDetailsTest extends PaymentRequestTestBase {
private static final AutofillProfile[] AUTOFILL_PROFILES = {
// Incomplete (no phone) profile.
new AutofillProfile("" /* guid */, "https://www.example.com" /* origin */,
"Bart Simpson", "Acme Inc.", "123 Main", "California", "Los Angeles", "",
"90210", "", "US", "", "bart@simpson.com", ""),
// Incomplete (no email) profile.
new AutofillProfile("" /* guid */, "https://www.example.com" /* origin */,
"Homer Simpson", "Acme Inc.", "123 Main", "California", "Los Angeles", "",
"90210", "", "US", "555 123-4567", "", ""),
// Complete profile.
new AutofillProfile("" /* guid */, "https://www.example.com" /* origin */,
"Lisa Simpson", "Acme Inc.", "123 Main", "California", "Los Angeles", "",
"90210", "", "US", "555 123-4567", "lisa@simpson.com", ""),
// Complete profile.
new AutofillProfile("" /* guid */, "https://www.example.com" /* origin */,
"Maggie Simpson", "Acme Inc.", "123 Main", "California", "Los Angeles", "",
"90210", "", "US", "555 123-4567", "maggie@simpson.com", ""),
// Incomplete (no phone and email) profile.
new AutofillProfile("" /* guid */, "https://www.example.com" /* origin */,
"Marge Simpson", "Acme Inc.", "123 Main", "California", "Los Angeles", "",
"90210", "", "US", "", "", ""),
// Incomplete (no name) profile.
new AutofillProfile("" /* guid */, "https://www.example.com" /* origin */, "",
"Acme Inc.", "123 Main", "California", "Los Angeles", "", "90210", "", "US",
"555 123-4567", "marge@simpson.com", ""),
};
private AutofillProfile[] mProfilesToAdd;
private int[] mCountsToSet;
private int[] mDatesToSet;
public PaymentRequestMultipleContactDetailsTest() {
// The merchant requests both a phone number and an email address.
// The merchant requests a name, a phone number and an email address.
super("payment_request_contact_details_test.html");
}
......@@ -29,48 +66,17 @@ public class PaymentRequestMultipleContactDetailsTest extends PaymentRequestTest
public void onMainActivityStarted()
throws InterruptedException, ExecutionException, TimeoutException {
AutofillTestHelper helper = new AutofillTestHelper();
// Create an incomplete (no phone) profile with the highest frecency score.
String guid1 = helper.setProfile(
new AutofillProfile("" /* guid */, "https://www.example.com" /* origin */,
"Bart Simpson", "Acme Inc.", "123 Main", "California", "Los Angeles", "",
"90210", "", "US", "", "bart@simpson.com", ""));
// Create an incomplete (no phone) profile with a the second highest frecency score.
String guid2 = helper.setProfile(
new AutofillProfile("" /* guid */, "https://www.example.com" /* origin */,
"Homer Simpson", "Acme Inc.", "123 Main", "California", "Los Angeles", "",
"90210", "", "US", "", "homer@simpson.com", ""));
// Create a complete profile with a middle frecency score.
String guid3 = helper.setProfile(
new AutofillProfile("" /* guid */, "https://www.example.com" /* origin */,
"Lisa Simpson", "Acme Inc.", "123 Main", "California", "Los Angeles", "",
"90210", "", "US", "555 123-4567", "lisa@simpson.com", ""));
// Create a complete profile with the second lowest frecency score.
String guid4 = helper.setProfile(
new AutofillProfile("" /* guid */, "https://www.example.com" /* origin */,
"Maggie Simpson", "Acme Inc.", "123 Main", "California", "Los Angeles", "",
"90210", "", "US", "555 123-4567", "maggie@simpson.com", ""));
// Create an incomplete profile with the lowest frecency score.
String guid5 = helper.setProfile(
new AutofillProfile("" /* guid */, "https://www.example.com" /* origin */,
"Marge Simpson", "Acme Inc.", "123 Main", "California", "Los Angeles", "",
"90210", "", "US", "", "marge@simpson.com", ""));
// Create a credit card associated with the fourth profile.
helper.setCreditCard(new CreditCard("", "https://example.com", true, true, "Jon Doe",
"4111111111111111", "1111", "12", "2050", "visa", R.drawable.pr_visa,
guid4, "" /* serverId */));
// Set the use stats so that profile1 has the highest frecency score, profile2 the second
// highest, profile 3 the third lowest, profile4 the second lowest and profile 5 the lowest.
helper.setProfileUseStatsForTesting(guid1, 20, 5000);
helper.setProfileUseStatsForTesting(guid2, 15, 5000);
helper.setProfileUseStatsForTesting(guid3, 10, 5000);
helper.setProfileUseStatsForTesting(guid4, 5, 5000);
helper.setProfileUseStatsForTesting(guid5, 1, 1);
// Add the profiles.
ArrayList<String> guids = new ArrayList<>();
for (int i = 0; i < mProfilesToAdd.length; i++) {
guids.add(helper.setProfile(mProfilesToAdd[i]));
}
// Set up the profile use stats.
for (int i = 0; i < guids.size(); i++) {
helper.setProfileUseStatsForTesting(guids.get(i), mCountsToSet[i], mDatesToSet[i]);
}
}
/**
......@@ -82,14 +88,50 @@ public class PaymentRequestMultipleContactDetailsTest extends PaymentRequestTest
@Feature({"Payments"})
public void testContactDetailsSuggestionOrdering()
throws InterruptedException, ExecutionException, TimeoutException {
triggerUIAndWait(mReadyToPay);
// Set the use stats so that profile[0] has the highest frecency score, profile[1] the
// second highest, profile[2] the third lowest, profile[3] the second lowest and profile[4]
// the lowest.
mProfilesToAdd = new AutofillProfile[] {AUTOFILL_PROFILES[0], AUTOFILL_PROFILES[1],
AUTOFILL_PROFILES[2], AUTOFILL_PROFILES[3], AUTOFILL_PROFILES[4]};
mCountsToSet = new int[] {20, 15, 10, 5, 1};
mDatesToSet = new int[] {5000, 5000, 5000, 5000, 1};
triggerUIAndWait(mReadyForInput);
clickInContactInfoAndWait(R.id.payments_section, mReadyForInput);
assertEquals(4, getNumberOfContactDetailSuggestions());
assertEquals("Lisa Simpson\n555 123-4567\nlisa@simpson.com",
getContactDetailsSuggestionLabel(0));
assertEquals("Maggie Simpson\n555 123-4567\nmaggie@simpson.com",
getContactDetailsSuggestionLabel(1));
assertEquals("Bart Simpson\nbart@simpson.com", getContactDetailsSuggestionLabel(2));
assertEquals("Homer Simpson\nhomer@simpson.com", getContactDetailsSuggestionLabel(3));
assertEquals("Bart Simpson\nbart@simpson.com\nPhone number required",
getContactDetailsSuggestionLabel(2));
assertEquals(
"Homer Simpson\n555 123-4567\nEmail required", getContactDetailsSuggestionLabel(3));
}
/**
* Make sure the information required message has been displayed for incomplete contact details
* correctly.
*/
@MediumTest
@Feature({"Payments"})
public void testContactDetailsEditRequiredMessage()
throws InterruptedException, ExecutionException, TimeoutException {
mProfilesToAdd = new AutofillProfile[] {AUTOFILL_PROFILES[0], AUTOFILL_PROFILES[1],
AUTOFILL_PROFILES[4], AUTOFILL_PROFILES[5]};
mCountsToSet = new int[] {15, 10, 5, 1};
mDatesToSet = new int[] {5000, 5000, 5000, 5000};
triggerUIAndWait(mReadyForInput);
clickInContactInfoAndWait(R.id.payments_section, mReadyForInput);
assertEquals(4, getNumberOfContactDetailSuggestions());
assertEquals("Bart Simpson\nbart@simpson.com\nPhone number required",
getContactDetailsSuggestionLabel(0));
assertEquals(
"Homer Simpson\n555 123-4567\nEmail required", getContactDetailsSuggestionLabel(1));
assertEquals(
"Marge Simpson\nMore information required", getContactDetailsSuggestionLabel(2));
assertEquals("555 123-4567\nmarge@simpson.com\nName required",
getContactDetailsSuggestionLabel(3));
}
}
......@@ -4,11 +4,19 @@
package org.chromium.chrome.browser.payments;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.spy;
import android.content.Context;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
import org.robolectric.ParameterizedRobolectricTestRunner;
import org.robolectric.ParameterizedRobolectricTestRunner.Parameters;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;
import org.chromium.chrome.browser.autofill.PersonalDataManager.AutofillProfile;
......@@ -18,7 +26,8 @@ import java.util.Collection;
/**
* Unit tests for the AutofillContact class.
*/
@RunWith(Parameterized.class)
@RunWith(ParameterizedRobolectricTestRunner.class)
@Config(sdk = 21, manifest = Config.NONE)
public class AutofillContactTest {
@Parameters
public static Collection<Object[]> data() {
......@@ -62,6 +71,9 @@ public class AutofillContactTest {
});
}
private static final String IMCOMPLETE_MESSAGE = "incomplete";
private final Context mContext;
private final String mPayerName;
private final String mPayerPhone;
private final String mPayerEmail;
......@@ -77,6 +89,8 @@ public class AutofillContactTest {
boolean isComplete, String expectedLabel, String expectedSublabel,
String expectedTertiaryLabel, String expectedPayerName, String expectedPayerPhone,
String expectedPayerEmail) {
mContext = spy(RuntimeEnvironment.application);
doReturn(IMCOMPLETE_MESSAGE).when(mContext).getString(anyInt());
mPayerName = payerName;
mPayerPhone = payerPhone;
mPayerEmail = payerEmail;
......@@ -92,8 +106,9 @@ public class AutofillContactTest {
@Test
public void test() {
AutofillProfile profile = new AutofillProfile();
AutofillContact contact =
new AutofillContact(profile, mPayerName, mPayerPhone, mPayerEmail, mIsComplete);
AutofillContact contact = new AutofillContact(mContext, profile, mPayerName, mPayerPhone,
mPayerEmail,
mIsComplete ? ContactEditor.COMPLETE : ContactEditor.INVALID_MULTIPLE_FIELDS);
Assert.assertEquals(
mIsComplete ? "Contact should be complete" : "Contact should be incomplete",
......@@ -124,5 +139,11 @@ public class AutofillContactTest {
"Sublabel should be " + expectedSublabel, expectedSublabel, actual.getSublabel());
Assert.assertEquals("TertiaryLabel should be " + expectedTertiaryLabel,
expectedTertiaryLabel, actual.getTertiaryLabel());
Assert.assertEquals("EditTitle should be " + IMCOMPLETE_MESSAGE, IMCOMPLETE_MESSAGE,
actual.getEditTitle());
String editMessage = actual.isComplete() ? null : IMCOMPLETE_MESSAGE;
Assert.assertEquals(
"EditMessage should be " + editMessage, editMessage, actual.getEditMessage());
}
}
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