Commit 9a7c97d5 authored by siashah's avatar siashah Committed by Commit Bot

Add nickname field to local card editor and new instrumentation tests.

The field is flag protected and this is only a UI change, so setting the
nickname won't set the nickname in the database. Will follow up with a CL
that updates it in the database.

Screencast: https://drive.google.com/file/d/1aIMedpnwlWtJ1YKNT0cpRCowuhDOnNRq/view?usp=sharing
(Googlers only)

Bug: 1082013
Change-Id: Ib26a67c858da4388563e4ba241604517a5e7fde8
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2213341Reviewed-by: default avatarJared Saul <jsaul@google.com>
Reviewed-by: default avatarsebsg <sebsg@chromium.org>
Reviewed-by: default avatarTheresa  <twellington@chromium.org>
Commit-Queue: Siddharth Shah <siashah@chromium.org>
Cr-Commit-Position: refs/heads/master@{#772310}
parent e8315e0d
......@@ -58,6 +58,7 @@ chrome_test_java_sources = [
"javatests/src/org/chromium/chrome/browser/autofill/AutofillTestHelper.java",
"javatests/src/org/chromium/chrome/browser/autofill/AutofillUpstreamTest.java",
"javatests/src/org/chromium/chrome/browser/autofill/PersonalDataManagerTest.java",
"javatests/src/org/chromium/chrome/browser/autofill/settings/AutofillLocalCardEditorTest.java",
"javatests/src/org/chromium/chrome/browser/autofill/settings/AutofillPaymentMethodsFragmentTest.java",
"javatests/src/org/chromium/chrome/browser/autofill/settings/AutofillProfilesFragmentTest.java",
"javatests/src/org/chromium/chrome/browser/autofill/settings/AutofillTestRule.java",
......
......@@ -108,4 +108,28 @@
</LinearLayout>
<include layout="@layout/autofill_billing_address_dropdown" />
<!-- Nickname -->
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/credit_card_nickname_label"
android:labelFor="@+id/credit_card_nickname_edit"
app:counterEnabled="true"
app:counterMaxLength="25"
app:errorEnabled="true"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/pref_autofill_field_large_top_margin"
android:layout_marginBottom="@dimen/pref_autofill_field_bottom_margin">
<EditText
tools:ignore="Autofill,LabelFor"
android:id="@+id/credit_card_nickname_edit"
android:maxLength="25"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:imeOptions="flagNoExtractUi"
android:inputType="text"
android:hint="@string/autofill_credit_card_editor_nickname" />
</com.google.android.material.textfield.TextInputLayout>
</merge>
......@@ -7,6 +7,7 @@ package org.chromium.chrome.browser.autofill.settings;
import android.os.Bundle;
import android.text.Editable;
import android.text.TextUtils;
import android.text.TextWatcher;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
......@@ -26,6 +27,7 @@ import org.chromium.chrome.browser.ChromeVersionInfo;
import org.chromium.chrome.browser.autofill.PersonalDataManager;
import org.chromium.chrome.browser.autofill.PersonalDataManager.AutofillProfile;
import org.chromium.chrome.browser.autofill.PersonalDataManager.CreditCard;
import org.chromium.chrome.browser.flags.ChromeFeatureList;
import org.chromium.chrome.browser.payments.SettingsAutofillAndPaymentsObserver;
import java.text.SimpleDateFormat;
......@@ -38,6 +40,8 @@ import java.util.Locale;
public class AutofillLocalCardEditor extends AutofillCreditCardEditor {
private TextInputLayout mNameLabel;
private EditText mNameText;
protected TextInputLayout mNicknameLabel;
protected EditText mNicknameText;
private TextInputLayout mNumberLabel;
private EditText mNumberText;
private Spinner mExpirationMonth;
......@@ -63,9 +67,14 @@ public class AutofillLocalCardEditor extends AutofillCreditCardEditor {
mNameLabel = (TextInputLayout) v.findViewById(R.id.credit_card_name_label);
mNameText = (EditText) v.findViewById(R.id.credit_card_name_edit);
mNicknameLabel = (TextInputLayout) v.findViewById(R.id.credit_card_nickname_label);
mNicknameText = (EditText) v.findViewById(R.id.credit_card_nickname_edit);
mNumberLabel = (TextInputLayout) v.findViewById(R.id.credit_card_number_label);
mNumberText = (EditText) v.findViewById(R.id.credit_card_number_edit);
// Set the visibility of the nickname field based on the experiment flag.
mNicknameLabel.setVisibility(isNicknameManagementEnabled() ? View.VISIBLE : View.GONE);
mNicknameText.addTextChangedListener(nicknameTextWatcher());
// Set text watcher to format credit card number
mNumberText.addTextChangedListener(new CreditCardNumberFormattingTextWatcher());
......@@ -220,8 +229,8 @@ public class AutofillLocalCardEditor extends AutofillCreditCardEditor {
mExpirationMonth.setOnItemSelectedListener(this);
mExpirationYear.setOnItemSelectedListener(this);
// Listen for touch events for drop down menus. We clear the keyboard when user touches
// any of these fields.
// Listen for touch events for drop down menus. We clear the keyboard when user touches any
// of these fields.
mExpirationMonth.setOnTouchListener(this);
mExpirationYear.setOnTouchListener(this);
}
......@@ -232,4 +241,28 @@ public class AutofillLocalCardEditor extends AutofillCreditCardEditor {
boolean enabled = !TextUtils.isEmpty(mNumberText.getText());
((Button) getView().findViewById(R.id.button_primary)).setEnabled(enabled);
}
private boolean isNicknameManagementEnabled() {
return ChromeFeatureList.isEnabled(
ChromeFeatureList.AUTOFILL_ENABLE_CARD_NICKNAME_MANAGEMENT);
}
private TextWatcher nicknameTextWatcher() {
return new TextWatcher() {
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {}
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
@Override
public void afterTextChanged(Editable s) {
// Show an error message if nickname contains any digits.
mNicknameLabel.setError(s.toString().matches(".*\\d.*")
? mContext.getResources().getString(
R.string.autofill_credit_card_editor_invalid_nickname)
: "");
}
};
}
}
......@@ -9,6 +9,7 @@ import org.chromium.chrome.browser.autofill.PersonalDataManager.AutofillProfile;
import org.chromium.chrome.browser.autofill.PersonalDataManager.CreditCard;
import org.chromium.content_public.browser.test.util.TestThreadUtils;
import java.util.Calendar;
import java.util.List;
import java.util.concurrent.TimeoutException;
......@@ -259,6 +260,11 @@ public class AutofillTestHelper {
() -> PersonalDataManager.getInstance().getCurrentDateForTesting());
}
/** Returns the YYYY value of the year after the current year. */
public static String nextYear() {
return String.valueOf(Calendar.getInstance().get(Calendar.YEAR) + 1);
}
private void registerDataObserver() {
try {
int callCount = mOnPersonalDataChangedHelper.getCallCount();
......
// Copyright 2020 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.autofill.settings;
import static com.google.common.truth.Truth.assertThat;
import android.support.test.filters.MediumTest;
import android.view.View;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TestRule;
import org.junit.runner.RunWith;
import org.chromium.chrome.R;
import org.chromium.chrome.browser.autofill.AutofillTestHelper;
import org.chromium.chrome.browser.autofill.PersonalDataManager.CreditCard;
import org.chromium.chrome.browser.flags.ChromeFeatureList;
import org.chromium.chrome.browser.settings.SettingsActivity;
import org.chromium.chrome.browser.settings.SettingsActivityTestRule;
import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
import org.chromium.chrome.test.util.browser.Features;
import org.chromium.content_public.browser.test.util.TestThreadUtils;
/**
* Instrumentation tests for AutofillLocalCardEditor.
*/
@RunWith(ChromeJUnit4ClassRunner.class)
public class AutofillLocalCardEditorTest {
@Rule
public TestRule mFeaturesProcessorRule = new Features.JUnitProcessor();
@Rule
public final AutofillTestRule rule = new AutofillTestRule();
@Rule
public final SettingsActivityTestRule<AutofillLocalCardEditor> mSettingsActivityTestRule =
new SettingsActivityTestRule<>(AutofillLocalCardEditor.class);
private static final CreditCard SAMPLE_LOCAL_CARD =
new CreditCard(/* guid= */ "", /* origin= */ "",
/* isLocal= */ true, /* isCached= */ false, /* name= */ "John Doe",
/* number= */ "4444333322221111",
/* obfuscatedNumber= */ "", /* month= */ "5", AutofillTestHelper.nextYear(),
/* basicCardIssuerNetwork = */ "visa",
/* issuerIconDrawableId= */ 0, /* billingAddressId= */ "", /* serverId= */ "");
private AutofillTestHelper mAutofillTestHelper;
@Before
public void setUp() {
mAutofillTestHelper = new AutofillTestHelper();
}
@Test
@MediumTest
@Features.DisableFeatures({ChromeFeatureList.AUTOFILL_ENABLE_CARD_NICKNAME_MANAGEMENT})
public void nicknameFieldNotShown_expOff() throws Exception {
mAutofillTestHelper.setCreditCard(SAMPLE_LOCAL_CARD);
SettingsActivity activity = mSettingsActivityTestRule.startSettingsActivity();
AutofillLocalCardEditor autofillLocalCardEditorFragment =
(AutofillLocalCardEditor) activity.getMainFragment();
assertThat(autofillLocalCardEditorFragment.mNicknameLabel.getVisibility())
.isEqualTo(View.GONE);
}
@Test
@MediumTest
@Features.EnableFeatures({ChromeFeatureList.AUTOFILL_ENABLE_CARD_NICKNAME_MANAGEMENT})
public void testNicknameFieldIsShown() throws Exception {
mAutofillTestHelper.setCreditCard(SAMPLE_LOCAL_CARD);
SettingsActivity activity = mSettingsActivityTestRule.startSettingsActivity();
AutofillLocalCardEditor autofillLocalCardEditorFragment =
(AutofillLocalCardEditor) activity.getMainFragment();
assertThat(autofillLocalCardEditorFragment.mNicknameLabel.getVisibility())
.isEqualTo(View.VISIBLE);
}
@Test
@MediumTest
@Features.EnableFeatures({ChromeFeatureList.AUTOFILL_ENABLE_CARD_NICKNAME_MANAGEMENT})
public void testInvalidNicknameShowsErrorMessage() throws Exception {
mAutofillTestHelper.setCreditCard(SAMPLE_LOCAL_CARD);
SettingsActivity activity = mSettingsActivityTestRule.startSettingsActivity();
AutofillLocalCardEditor autofillLocalCardEditorFragment =
(AutofillLocalCardEditor) activity.getMainFragment();
TestThreadUtils.runOnUiThreadBlocking(() -> {
try {
autofillLocalCardEditorFragment.mNicknameText.setText("Nickname 123");
} catch (Exception e) {
Assert.fail("Failed to set the nickname");
}
});
assertThat(autofillLocalCardEditorFragment.mNicknameLabel.getError())
.isEqualTo(activity.getResources().getString(
R.string.autofill_credit_card_editor_invalid_nickname));
}
@Test
@MediumTest
@Features.EnableFeatures({ChromeFeatureList.AUTOFILL_ENABLE_CARD_NICKNAME_MANAGEMENT})
public void testErrorMessageHiddenAfterNicknameIsEditedFromInvalidToValid() throws Exception {
mAutofillTestHelper.setCreditCard(SAMPLE_LOCAL_CARD);
SettingsActivity activity = mSettingsActivityTestRule.startSettingsActivity();
AutofillLocalCardEditor autofillLocalCardEditorFragment =
(AutofillLocalCardEditor) activity.getMainFragment();
TestThreadUtils.runOnUiThreadBlocking(() -> {
try {
autofillLocalCardEditorFragment.mNicknameText.setText("Nickname 123");
} catch (Exception e) {
Assert.fail("Failed to set the nickname");
}
});
assertThat(autofillLocalCardEditorFragment.mNicknameLabel.getError())
.isEqualTo(activity.getResources().getString(
R.string.autofill_credit_card_editor_invalid_nickname));
TestThreadUtils.runOnUiThreadBlocking(() -> {
try {
autofillLocalCardEditorFragment.mNicknameText.setText("Valid Nickname");
} catch (Exception e) {
Assert.fail("Failed to set the nickname");
}
});
assertThat(autofillLocalCardEditorFragment.mNicknameLabel.getError()).isNull();
}
@Test
@MediumTest
@Features.EnableFeatures({ChromeFeatureList.AUTOFILL_ENABLE_CARD_NICKNAME_MANAGEMENT})
public void testNicknameLengthCappedAt25Characters() throws Exception {
String veryLongNickname = "This is a very very long nickname";
mAutofillTestHelper.setCreditCard(SAMPLE_LOCAL_CARD);
SettingsActivity activity = mSettingsActivityTestRule.startSettingsActivity();
AutofillLocalCardEditor autofillLocalCardEditorFragment =
(AutofillLocalCardEditor) activity.getMainFragment();
TestThreadUtils.runOnUiThreadBlocking(() -> {
try {
autofillLocalCardEditorFragment.mNicknameText.setText(veryLongNickname);
} catch (Exception e) {
Assert.fail("Failed to set the nickname");
}
});
assertThat(autofillLocalCardEditorFragment.mNicknameText.getText().toString())
.isEqualTo(veryLongNickname.substring(0, 25));
}
}
......@@ -26,8 +26,6 @@ import org.chromium.chrome.browser.settings.SettingsActivityTestRule;
import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
import org.chromium.chrome.test.util.browser.Features;
import java.util.Calendar;
/**
* Instrumentation tests for AutofillPaymentMethodsFragment.
*/
......@@ -50,7 +48,7 @@ public class AutofillPaymentMethodsFragmentTest {
/* origin= */ "",
/* isLocal= */ false, /* isCached= */ false, /* name= */ "John Doe",
/* number= */ "4444333322221111",
/* obfuscatedNumber= */ "", /* month= */ "5", nextYear(),
/* obfuscatedNumber= */ "", /* month= */ "5", AutofillTestHelper.nextYear(),
/* basicCardIssuerNetwork =*/"visa",
/* issuerIconDrawableId= */ 0, /* billingAddressId= */ "",
/* serverId= */ "");
......@@ -58,7 +56,7 @@ public class AutofillPaymentMethodsFragmentTest {
new CreditCard(/* guid= */ "", /* origin= */ "",
/* isLocal= */ false, /* isCached= */ false, /* name= */ "John Doe",
/* number= */ "5454545454545454",
/* obfuscatedNumber= */ "", /* month= */ "12", nextYear(),
/* obfuscatedNumber= */ "", /* month= */ "12", AutofillTestHelper.nextYear(),
/* basicCardIssuerNetwork= */ "mastercard", /* issuerIconDrawableId= */ 0,
/* billingAddressId= */ "",
/* serverId= */ "");
......@@ -191,8 +189,4 @@ public class AutofillPaymentMethodsFragmentTest {
private static PreferenceScreen getPreferenceScreen(SettingsActivity activity) {
return ((AutofillPaymentMethodsFragment) activity.getMainFragment()).getPreferenceScreen();
}
private static String nextYear() {
return String.valueOf(Calendar.getInstance().get(Calendar.YEAR) + 1);
}
}
......@@ -65,6 +65,7 @@ const base::Feature* kFeaturesExposedToJava[] = {
&autofill::features::kAutofillKeyboardAccessory,
&autofill::features::kAutofillManualFallbackAndroid,
&autofill::features::kAutofillRefreshStyleAndroid,
&autofill::features::kAutofillEnableCardNicknameManagement,
&autofill::features::kAutofillEnableCompanyName,
&autofill::features::kAutofillEnableGoogleIssuedCard,
&autofill::features::kAutofillEnableSurfacingServerCardNickname,
......
......@@ -195,6 +195,8 @@ public abstract class ChromeFeatureList {
"AutofillAllowNonHttpActivation";
public static final String AUTOFILL_CREDIT_CARD_AUTHENTICATION =
"AutofillCreditCardAuthentication";
public static final String AUTOFILL_ENABLE_CARD_NICKNAME_MANAGEMENT =
"AutofillEnableCardNicknameManagement";
public static final String AUTOFILL_ENABLE_COMPANY_NAME = "AutofillEnableCompanyName";
public static final String AUTOFILL_ENABLE_GOOGLE_ISSUED_CARD =
"AutofillEnableGoogleIssuedCard";
......
......@@ -427,6 +427,12 @@ CHAR-LIMIT guidelines:
<message name="IDS_AUTOFILL_CREDIT_CARD_EDITOR_NAME" desc="Label for text input field containing the name on a credit card. [CHAR-LIMIT=32]">
Name on card
</message>
<message name="IDS_AUTOFILL_CREDIT_CARD_EDITOR_NICKNAME" desc="Label for text input field containing the nickname on a credit card. [CHAR-LIMIT=25]">
Card nickname
</message>
<message name="IDS_AUTOFILL_CREDIT_CARD_EDITOR_INVALID_NICKNAME" desc="Label for text input field containing the nickname on a credit card. [CHAR-LIMIT=25]">
Nickname can’t include numbers
</message>
<message name="IDS_AUTOFILL_CARD_HOLDER_NAME" desc="Label for text input field containing the name on a credit card. [CHAR-LIMIT=32]">
Cardholder name
</message>
......
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