Skip to content

Commit

Permalink
Enable autofill local save card as a bottom sheet. 6/7
Browse files Browse the repository at this point in the history
The local card save path in the autofill client now launches the bottom
sheet when the flag is enabled.

AutofillSaveCardUiInfo now creates an empty list of LegalMessageLine
objects since no LegalMessageLines are provided on local save.

Screenshot:
https://screenshot.googleplex.com/5WMydzxLfZSWJ6n.png

Enable chrome://flags#autofill-enable-payments-android-bottom-sheet on
Chrome for Android while signed out to see this bottom sheet after
filling a new credit card.

Bug: 1479546
Change-Id: I7414cdc7dd4a5d14f09f955a0db281633e13282b
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4803123
Reviewed-by: Christoph Schwering <schwering@google.com>
Commit-Queue: Christoph Schwering <schwering@google.com>
Auto-Submit: Slobodan Pejic <slobodan@chromium.org>
Code-Coverage: findit-for-me@appspot.gserviceaccount.com <findit-for-me@appspot.gserviceaccount.com>
Cr-Commit-Position: refs/heads/main@{#1193563}
  • Loading branch information
Slobodan Pejic authored and Chromium LUCI CQ committed Sep 7, 2023
1 parent fbbd5ca commit 14eeddf
Show file tree
Hide file tree
Showing 7 changed files with 125 additions and 24 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -83,8 +83,11 @@ public void setDelegate(Delegate delegate) {
* @param uiInfo Contains the UI resources to be applied to this bottom sheet content's view.
*/
/*package*/ void setUiInfo(AutofillSaveCardUiInfo uiInfo) {
// TODO(crbug.com/1454271): Implement local save card (isForUpload = true).
setLogoIconId(uiInfo.getLogoIcon());
if (uiInfo.isForUpload()) {
setLogoIconId(uiInfo.getLogoIcon());
} else {
setLogoIconId(0);
}
mView.<ImageView>findViewById(R.id.autofill_save_card_credit_card_icon)
.setImageResource(uiInfo.getCardDetail().issuerIconDrawableId);
setTextViewText(R.id.autofill_save_card_credit_card_label, uiInfo.getCardDetail().label);
Expand Down Expand Up @@ -114,6 +117,11 @@ private void setLogoIconId(@DrawableRes int iconId) {
private void setTextViewText(@IdRes int resourceId, CharSequence text) {
TextView textView = mView.findViewById(resourceId);
textView.setText(text);
if (text == null || text.length() == 0) {
textView.setVisibility(View.GONE);
} else {
textView.setVisibility(View.VISIBLE);
}
}

private void setLegalMessage(List<LegalMessageLine> legalMessageLines) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ public void testCancelButtonClick_callsDelegateDidClickCancel() {
@Test
public void testSetUiInfo_setsAllViews() {
AutofillSaveCardUiInfo uiInfo = new AutofillSaveCardUiInfo.Builder()
.withIsForUpload(true)
.withLogoIcon(0)
.withTitleText("Title Text")
.withDescriptionText("Description Text")
Expand Down Expand Up @@ -128,13 +129,35 @@ public void testSetUiInfo_setsAllViews() {
assertEquals("Cancel Text", cancelButton.getText());
}

@Test
public void testSetUiInfo_setsViewsToGone_whenEmptyText() {
// Set visibility to gone on description and legal message to remove the visually extra
// margins caused by empty views.
AutofillSaveCardUiInfo uiInfo = defaultUiInfoBuilder()
.withDescriptionText("")
.withLegalMessageLines(ImmutableList.of())
.build();

mContent.setUiInfo(uiInfo);

View contentView = mContent.getContentView();
assertEquals(View.GONE,
contentView.findViewById(R.id.autofill_save_card_description_text).getVisibility());
assertEquals(View.GONE, contentView.findViewById(R.id.legal_message).getVisibility());
}

private CharSequence getTextViewText(@IdRes int resourceId) {
return mContent.getContentView().<TextView>findViewById(resourceId).getText();
}

@Test
public void testSetLogoIconId_visiblySetsTheImage() {
mContent.setUiInfo(defaultUiInfoBuilder().withLogoIcon(EXAMPLE_DRAWABLE_RES).build());
AutofillSaveCardUiInfo uiInfo = defaultUiInfoBuilder()
.withIsForUpload(true)
.withLogoIcon(EXAMPLE_DRAWABLE_RES)
.build();

mContent.setUiInfo(uiInfo);

ImageView imageView = mContent.getContentView().findViewById(R.id.autofill_save_card_icon);
assertThat(imageView.getDrawable(), notNullValue());
Expand Down Expand Up @@ -269,7 +292,7 @@ private List<ClickableSpan> getClickableSpans(Spannable text) {

private static AutofillSaveCardUiInfo.Builder defaultUiInfoBuilder() {
return new AutofillSaveCardUiInfo.Builder()
.withIsForUpload(false)
.withIsForUpload(true)
.withCardDetail(new CardDetail(/*iconId=*/0, /*label=*/"", /*subLabel=*/""))
.withLegalMessageLines(Collections.EMPTY_LIST)
.withTitleText("")
Expand Down
54 changes: 35 additions & 19 deletions chrome/browser/ui/autofill/chrome_autofill_client.cc
Original file line number Diff line number Diff line change
Expand Up @@ -757,12 +757,21 @@ void ChromeAutofillClient::ConfirmSaveCreditCardLocally(
LocalSaveCardPromptCallback callback) {
#if BUILDFLAG(IS_ANDROID)
DCHECK(options.show_prompt);
AutofillSaveCardUiInfo ui_info =
AutofillSaveCardUiInfo::CreateForLocalSave(options, card);
auto save_card_delegate =
std::make_unique<AutofillSaveCardDelegate>(std::move(callback), options);
if (base::FeatureList::IsEnabled(
features::kAutofillEnablePaymentsAndroidBottomSheet)) {
if (auto* bridge = GetOrCreateAutofillSaveCardBottomSheetBridge()) {
bridge->RequestShowContent(ui_info, std::move(save_card_delegate));
}
return;
}
infobars::ContentInfoBarManager::FromWebContents(web_contents())
->AddInfoBar(CreateSaveCardInfoBarMobile(
std::make_unique<AutofillSaveCardInfoBarDelegateMobile>(
AutofillSaveCardUiInfo::CreateForLocalSave(options, card),
std::make_unique<AutofillSaveCardDelegate>(std::move(callback),
options))));
std::move(ui_info), std::move(save_card_delegate))));
#else
// Do lazy initialization of SaveCardBubbleControllerImpl.
SaveCardBubbleControllerImpl::CreateForWebContents(web_contents());
Expand All @@ -785,31 +794,19 @@ void ChromeAutofillClient::ConfirmSaveCreditCardToCloud(
identity_manager->GetPrimaryAccountInfo(signin::ConsentLevel::kSignin));
AutofillSaveCardUiInfo ui_info = AutofillSaveCardUiInfo::CreateForUploadSave(
options, card, legal_message_lines, account_info);
auto common_delegate =
auto save_card_delegate =
std::make_unique<AutofillSaveCardDelegate>(std::move(callback), options);
if (base::FeatureList::IsEnabled(
features::kAutofillEnablePaymentsAndroidBottomSheet)) {
if (!autofill_save_card_bottom_sheet_bridge_) {
// During shutdown the window may be null. There is no need to show the
// bottom sheet during shutdown.
auto* window_android = web_contents()->GetTopLevelNativeWindow();
TabModel* tab_model =
TabModelList::GetTabModelForWebContents(web_contents());
if (!window_android || !tab_model) {
return;
}
autofill_save_card_bottom_sheet_bridge_ =
std::make_unique<AutofillSaveCardBottomSheetBridge>(window_android,
tab_model);
if (auto* bridge = GetOrCreateAutofillSaveCardBottomSheetBridge()) {
bridge->RequestShowContent(ui_info, std::move(save_card_delegate));
}
autofill_save_card_bottom_sheet_bridge_->RequestShowContent(
ui_info, std::move(common_delegate));
return;
}
infobars::ContentInfoBarManager::FromWebContents(web_contents())
->AddInfoBar(CreateSaveCardInfoBarMobile(
std::make_unique<AutofillSaveCardInfoBarDelegateMobile>(
std::move(ui_info), std::move(common_delegate))));
std::move(ui_info), std::move(save_card_delegate))));
#else
// Do lazy initialization of SaveCardBubbleControllerImpl.
SaveCardBubbleControllerImpl::CreateForWebContents(web_contents());
Expand Down Expand Up @@ -1354,4 +1351,23 @@ std::u16string ChromeAutofillClient::GetAccountHolderEmail() {
return base::UTF8ToUTF16(primary_account_info.email);
}

#if BUILDFLAG(IS_ANDROID)
AutofillSaveCardBottomSheetBridge*
ChromeAutofillClient::GetOrCreateAutofillSaveCardBottomSheetBridge() {
if (!autofill_save_card_bottom_sheet_bridge_) {
// During shutdown the window may be null. There is no need to show the
// bottom sheet during shutdown.
auto* window_android = web_contents()->GetTopLevelNativeWindow();
TabModel* tab_model =
TabModelList::GetTabModelForWebContents(web_contents());
if (window_android && tab_model) {
autofill_save_card_bottom_sheet_bridge_ =
std::make_unique<AutofillSaveCardBottomSheetBridge>(window_android,
tab_model);
}
}
return autofill_save_card_bottom_sheet_bridge_.get();
}
#endif

} // namespace autofill
4 changes: 4 additions & 0 deletions chrome/browser/ui/autofill/chrome_autofill_client.h
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,10 @@ class ChromeAutofillClient : public ContentAutofillClient,
std::u16string GetAccountHolderName();
std::u16string GetAccountHolderEmail();
bool SupportsConsentlessExecution(const url::Origin& origin);
#if BUILDFLAG(IS_ANDROID)
AutofillSaveCardBottomSheetBridge*
GetOrCreateAutofillSaveCardBottomSheetBridge();
#endif

std::unique_ptr<LogManager> log_manager_;

Expand Down
26 changes: 26 additions & 0 deletions chrome/browser/ui/autofill/chrome_autofill_client_unittest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,32 @@ TEST_F(ChromeAutofillClientTestWithPaymentsAndroidBottomSheetFeature,
ChromeAutofillClient::SaveCreditCardOptions().with_show_prompt(true),
base::DoNothing()));
}

TEST_F(ChromeAutofillClientTestWithPaymentsAndroidBottomSheetFeature,
ConfirmSaveCreditCardLocally_RequestsBottomSheet) {
TestChromeAutofillClient* autofill_client = client();
auto* bottom_sheet_bridge =
autofill_client->InjectMockAutofillSaveCardBottomSheetBridge();

EXPECT_CALL(*bottom_sheet_bridge,
RequestShowContent(testing::An<const AutofillSaveCardUiInfo&>(),
testing::NotNull()));

autofill_client->ConfirmSaveCreditCardLocally(
CreditCard(),
ChromeAutofillClient::SaveCreditCardOptions().with_show_prompt(true),
base::DoNothing());
}

TEST_F(ChromeAutofillClientTestWithPaymentsAndroidBottomSheetFeature,
ConfirmSaveCreditCardLocally_DoesNotFailWithoutAWindow) {
TestChromeAutofillClient* autofill_client = client();

EXPECT_NO_FATAL_FAILURE(autofill_client->ConfirmSaveCreditCardLocally(
CreditCard(),
ChromeAutofillClient::SaveCreditCardOptions().with_show_prompt(true),
base::DoNothing()));
}
#endif

} // namespace
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,14 +80,18 @@ public boolean isGooglePayBrandingEnabled() {

// LINT.IfChange
@CalledByNative
@VisibleForTesting
/** Construct the delegate given all the members. */
private AutofillSaveCardUiInfo(boolean isForUpload, @DrawableRes int logoIcon,
/*package*/ AutofillSaveCardUiInfo(boolean isForUpload, @DrawableRes int logoIcon,
@DrawableRes int issuerIcon, List<LegalMessageLine> legalMessageLines, String cardLabel,
String cardSubLabel, String cardDescription, String titleText, String confirmText,
String cancelText, boolean isGooglePayBrandingEnabled, String descriptionText) {
mIsForUpload = isForUpload;
mLogoIcon = logoIcon;
mIssuerIcon = issuerIcon;
if (legalMessageLines == null) {
legalMessageLines = ImmutableList.of();
}
mLegalMessageLines = ImmutableList.copyOf(legalMessageLines);
mCardLabel = cardLabel;
mCardSubLabel = cardSubLabel;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
package org.chromium.components.autofill.payments;

import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.empty;
import static org.hamcrest.Matchers.equalTo;

import android.annotation.SuppressLint;
Expand Down Expand Up @@ -40,6 +41,25 @@ private static AutofillSaveCardUiInfo.Builder defaultBuilder() {
.withDescriptionText("");
}

@Test
public void testConstructor_createsEmptyListWhenLegalMessageLinesIsNull() {
var uiInfo = new AutofillSaveCardUiInfo(
/*isForUpload=*/false,
/*logoIcon=*/0,
/*issuerIcon=*/0,
/*legalMessageLines=*/null,
/*cardLabel=*/null,
/*cardSubLabel=*/null,
/*cardDescription=*/null,
/*titleText=*/null,
/*confirmText=*/null,
/*cancelText=*/null,
/*isGooglePayBrandingEnabled=*/false,
/*descriptionText=*/null);

assertThat(uiInfo.getLegalMessageLines(), empty());
}

@Test
public void testBuilder_setsIsForUpload() {
AutofillSaveCardUiInfo uiInfo = defaultBuilder().withIsForUpload(true).build();
Expand Down

0 comments on commit 14eeddf

Please sign in to comment.