Skip to content

Commit

Permalink
[FastCheckout] Implement FC delegate preconditions.
Browse files Browse the repository at this point in the history
We check that:
* FC is shown once per page (reset on navigation).
* The clicked field is focusable and empty.
* There is at least 1 complete valid credit card and address on file.
* UI is available (RFH is active).
More checks might be added once the requirements are clarified.

Also we now hide the Autofill Popup when FC is to be shown.

Full context: go/fast-checkout-keyboard-hiding

Bug: 1334642
Change-Id: Ief25fb95bfdd980141d2b13be18a7c0a3197737b
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3830023
Reviewed-by: Rohit Rao <rohitrao@chromium.org>
Reviewed-by: Mohamed Amir Yosef <mamir@chromium.org>
Reviewed-by: Christoph Schwering <schwering@google.com>
Reviewed-by: Bo Liu <boliu@chromium.org>
Reviewed-by: Jan Keitel <jkeitel@google.com>
Commit-Queue: Norge Vizcay <vizcay@google.com>
Reviewed-by: Elizabeth Popova <lizapopova@google.com>
Cr-Commit-Position: refs/heads/main@{#1041540}
  • Loading branch information
norgevz authored and Chromium LUCI CQ committed Aug 31, 2022
1 parent 91d25b9 commit bdb73ce
Show file tree
Hide file tree
Showing 26 changed files with 445 additions and 15 deletions.
20 changes: 20 additions & 0 deletions android_webview/browser/aw_autofill_client.cc
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,26 @@ void AwAutofillClient::ScanCreditCard(CreditCardScanCallback callback) {
NOTIMPLEMENTED();
}

bool AwAutofillClient::IsFastCheckoutSupported() {
return false;
}

bool AwAutofillClient::IsFastCheckoutTriggerForm(
const autofill::FormData& form,
const autofill::FormFieldData& field) {
return false;
}

bool AwAutofillClient::ShowFastCheckout(
base::WeakPtr<autofill::FastCheckoutDelegate> delegate) {
NOTREACHED();
return false;
}

void AwAutofillClient::HideFastCheckout() {
NOTREACHED();
}

bool AwAutofillClient::IsTouchToFillCreditCardSupported() {
return false;
}
Expand Down
6 changes: 6 additions & 0 deletions android_webview/browser/aw_autofill_client.h
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,12 @@ class AwAutofillClient : public autofill::AutofillClient,
AddressProfileSavePromptCallback callback) override;
bool HasCreditCardScanFeature() override;
void ScanCreditCard(CreditCardScanCallback callback) override;
bool IsFastCheckoutSupported() override;
bool IsFastCheckoutTriggerForm(const autofill::FormData& form,
const autofill::FormFieldData& field) override;
bool ShowFastCheckout(
base::WeakPtr<autofill::FastCheckoutDelegate> delegate) override;
void HideFastCheckout() override;
bool IsTouchToFillCreditCardSupported() override;
bool ShowTouchToFillCreditCard(
base::WeakPtr<autofill::TouchToFillDelegate> delegate) override;
Expand Down
26 changes: 26 additions & 0 deletions chrome/browser/ui/autofill/chrome_autofill_client.cc
Original file line number Diff line number Diff line change
Expand Up @@ -677,6 +677,32 @@ void ChromeAutofillClient::ScanCreditCard(CreditCardScanCallback callback) {
std::move(callback));
}

bool ChromeAutofillClient::IsFastCheckoutSupported() {
// TODO(crbug.com/1334642): Implement.
NOTIMPLEMENTED();
return false;
}

bool ChromeAutofillClient::IsFastCheckoutTriggerForm(
const FormData& form,
const FormFieldData& field) {
// TODO(crbug.com/1334642): Implement.
NOTIMPLEMENTED();
return false;
}

bool ChromeAutofillClient::ShowFastCheckout(
base::WeakPtr<FastCheckoutDelegate> delegate) {
// TODO(crbug.com/1334642): Implement.
NOTIMPLEMENTED();
return false;
}

void ChromeAutofillClient::HideFastCheckout() {
// TODO(crbug.com/1334642): Implement.
NOTIMPLEMENTED();
}

bool ChromeAutofillClient::IsTouchToFillCreditCardSupported() {
#if BUILDFLAG(IS_ANDROID)
return base::FeatureList::IsEnabled(
Expand Down
6 changes: 6 additions & 0 deletions chrome/browser/ui/autofill/chrome_autofill_client.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@

#if BUILDFLAG(IS_ANDROID)
#include "chrome/browser/autofill/android/save_update_address_profile_flow_manager.h"
#include "chrome/browser/fast_checkout/fast_checkout_client.h"
#include "chrome/browser/touch_to_fill/payments/android/touch_to_fill_credit_card_controller.h"
#include "chrome/browser/ui/android/autofill/save_card_message_controller_android.h"
#include "components/autofill/core/browser/ui/payments/card_expiration_date_fix_flow_controller_impl.h"
Expand Down Expand Up @@ -170,6 +171,11 @@ class ChromeAutofillClient
AddressProfileSavePromptCallback callback) override;
bool HasCreditCardScanFeature() override;
void ScanCreditCard(CreditCardScanCallback callback) override;
bool IsFastCheckoutSupported() override;
bool IsFastCheckoutTriggerForm(const FormData& form,
const FormFieldData& field) override;
bool ShowFastCheckout(base::WeakPtr<FastCheckoutDelegate> delegate) override;
void HideFastCheckout() override;
bool IsTouchToFillCreditCardSupported() override;
bool ShowTouchToFillCreditCard(
base::WeakPtr<TouchToFillDelegate> delegate) override;
Expand Down
1 change: 1 addition & 0 deletions components/autofill/core/browser/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -816,6 +816,7 @@ source_set("unit_tests") {
"data_model/credit_card_unittest.cc",
"data_model/iban_unittest.cc",
"data_model/phone_number_unittest.cc",
"fast_checkout_delegate_impl_unittest.cc",
"field_filler_unittest.cc",
"field_types_unittest.cc",
"form_data_importer_unittest.cc",
Expand Down
21 changes: 21 additions & 0 deletions components/autofill/core/browser/autofill_client.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include "base/memory/weak_ptr.h"
#include "base/types/strong_alias.h"
#include "build/build_config.h"
#include "components/autofill/core/browser/fast_checkout_delegate.h"
#include "components/autofill/core/browser/payments/legal_message_line.h"
#include "components/autofill/core/browser/payments/risk_data_loader.h"
#include "components/autofill/core/browser/ui/popup_item_ids.h"
Expand Down Expand Up @@ -587,6 +588,26 @@ class AutofillClient : public RiskDataLoader {
// HasCreditCardScanFeature() returns true.
virtual void ScanCreditCard(CreditCardScanCallback callback) = 0;

// Returns true if the Fast Checkout feature is both supported by platform and
// enabled. Should be called before `ShowFastCheckout` or `HideFastCheckout`.
virtual bool IsFastCheckoutSupported() = 0;

// Returns true if the form is one of the trigger forms for Fast Checkout on
// the domain. Should be called before `ShowFastCheckout`.
virtual bool IsFastCheckoutTriggerForm(const FormData& form,
const FormFieldData& field) = 0;

// Shows the FastCheckout surface (for autofilling information during the
// checkout flow) and returns `true` on success. `delegate` will be notified
// of events. Should be called only if `IsFastCheckoutSupported` returns true.
virtual bool ShowFastCheckout(
base::WeakPtr<FastCheckoutDelegate> delegate) = 0;

// Hides the Fast Checkout surface (for autofilling information during the
// checkout flow) if one is currently shown. Should be called only if
// `IsFastCheckoutSupported` returns true.
virtual void HideFastCheckout() = 0;

// Returns true if the Touch To Fill feature is both supported by platform and
// enabled. Should be called before |ShowTouchToFillCreditCard| or
// |HideTouchToFillCreditCard|.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1121,7 +1121,7 @@ void BrowserAutofillManager::OnAskForValuesToFillImpl(

if (fast_checkout_delegate_->IsShowingFastCheckoutUI() ||
(form_element_was_clicked &&
fast_checkout_delegate_->TryToShowFastCheckout(field))) {
fast_checkout_delegate_->TryToShowFastCheckout(form, field))) {
// The Fast Checkout surface is shown, so abort showing regular Autofill UI.
// Now the flow is controlled by the `fast_checkout_delegate_` instead
// of `external_delegate_`.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,7 @@ class MockFastCheckoutDelegate : public FastCheckoutDelegate {

MOCK_METHOD(bool,
TryToShowFastCheckout,
(const FormFieldData& field),
(const FormData& form, const FormFieldData& field),
(override));
MOCK_METHOD(bool, IsShowingFastCheckoutUI, (), (const, override));
MOCK_METHOD(void, HideFastCheckoutUI, (), (override));
Expand Down
10 changes: 10 additions & 0 deletions components/autofill/core/browser/data_model/credit_card.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1146,10 +1146,20 @@ bool CreditCard::IsExpired(const base::Time& current_time) const {
current_time);
}

bool CreditCard::masked() const {
return record_type() == CreditCard::MASKED_SERVER_CARD ||
record_type() == CreditCard::VIRTUAL_CARD;
}

bool CreditCard::ShouldUpdateExpiration() const {
return IsExpired(AutofillClock::Now());
}

bool CreditCard::IsCompleteValidCard() const {
return !IsExpired(AutofillClock::Now()) && HasNameOnCard() &&
(masked() || HasValidCardNumber());
}

// So we can compare CreditCards with EXPECT_EQ().
std::ostream& operator<<(std::ostream& os, const CreditCard& credit_card) {
return os << base::UTF16ToUTF8(credit_card.Label()) << " "
Expand Down
8 changes: 8 additions & 0 deletions components/autofill/core/browser/data_model/credit_card.h
Original file line number Diff line number Diff line change
Expand Up @@ -250,9 +250,17 @@ class CreditCard : public AutofillDataModel {
// Returns whether the card is expired based on |current_time|.
bool IsExpired(const base::Time& current_time) const;

// Returns whether the card is a masked card. Such cards will only have
// the last 4 digits of the card number.
bool masked() const;

// Whether the card expiration date should be updated.
bool ShouldUpdateExpiration() const;

// Complete = contains number, expiration date and name on card.
// Valid = unexpired with valid number format.
bool IsCompleteValidCard() const;

const std::string& billing_address_id() const { return billing_address_id_; }
void set_billing_address_id(const std::string& id) {
billing_address_id_ = id;
Expand Down
3 changes: 2 additions & 1 deletion components/autofill/core/browser/fast_checkout_delegate.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ class FastCheckoutDelegate {

// Checks whether FastCheckout is eligible for the given web form data. On
// success triggers the corresponding surface and returns `true`.
virtual bool TryToShowFastCheckout(const FormFieldData& field) = 0;
virtual bool TryToShowFastCheckout(const FormData& form,
const FormFieldData& field) = 0;

// Returns whether the FC surface is currently being shown.
virtual bool IsShowingFastCheckoutUI() const = 0;
Expand Down
38 changes: 34 additions & 4 deletions components/autofill/core/browser/fast_checkout_delegate_impl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
// found in the LICENSE file.

#include "components/autofill/core/browser/fast_checkout_delegate_impl.h"
#include "components/autofill/core/browser/browser_autofill_manager.h"

namespace autofill {

Expand All @@ -14,10 +15,34 @@ FastCheckoutDelegateImpl::FastCheckoutDelegateImpl(

FastCheckoutDelegateImpl::~FastCheckoutDelegateImpl() = default;

// TODO(crbug.com/1334642): Add metrics to record reasons why FC is not shown.
bool FastCheckoutDelegateImpl::TryToShowFastCheckout(
const FormData& form,
const FormFieldData& field) {
// TODO(crbug.com/1334642): Implement.
return false;
// Trigger only on supported platforms.
if (!manager_->client()->IsFastCheckoutSupported())
return false;
// Trigger only if the form is a trigger form for FC.
if (!manager_->client()->IsFastCheckoutTriggerForm(form, field))
return false;
// Trigger only if not shown before.
if (fast_checkout_state_ != FastCheckoutState::kNotShownYet)
return false;
// Trigger only on focusable empty fields.
if (!field.is_focusable || !field.value.empty())
return false;
// Trigger only if the UI is available.
if (!manager_->driver()->CanShowAutofillUi())
return false;

// Finally try showing the surface.
if (!manager_->client()->ShowFastCheckout(GetWeakPtr()))
return false;

fast_checkout_state_ = FastCheckoutState::kIsShowing;
manager_->client()->HideAutofillPopup(
PopupHidingReason::kOverlappingWithFastCheckoutSurface);
return true;
}

bool FastCheckoutDelegateImpl::IsShowingFastCheckoutUI() const {
Expand All @@ -28,12 +53,17 @@ void FastCheckoutDelegateImpl::OnFastCheckoutUIHidden() {
fast_checkout_state_ = FastCheckoutState::kWasShown;
}

// TODO(crbug.com/1348538): Create a central point for TTF/FC hiding decision.
void FastCheckoutDelegateImpl::HideFastCheckoutUI() {
// TODO(crbug.com/1334642): Implement.
if (IsShowingFastCheckoutUI()) {
manager_->client()->HideFastCheckout();
fast_checkout_state_ = FastCheckoutState::kWasShown;
}
}

void FastCheckoutDelegateImpl::Reset() {
// TODO(crbug.com/1334642): Implement.
HideFastCheckoutUI();
fast_checkout_state_ = FastCheckoutState::kNotShownYet;
}

base::WeakPtr<FastCheckoutDelegateImpl> FastCheckoutDelegateImpl::GetWeakPtr() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ class FastCheckoutDelegateImpl : public FastCheckoutDelegate {
~FastCheckoutDelegateImpl() override;

// FastCheckoutDelegate:
bool TryToShowFastCheckout(const FormFieldData& field) override;
bool TryToShowFastCheckout(const FormData& form,
const FormFieldData& field) override;
bool IsShowingFastCheckoutUI() const override;
void HideFastCheckoutUI() override;
void OnFastCheckoutUIHidden() override;
Expand Down
Loading

0 comments on commit bdb73ce

Please sign in to comment.