Commit 99743ead authored by Manas Verma's avatar Manas Verma Committed by Commit Bot

[Autofill Offers] Create AutofillOfferManagerFactory

AutofillManager now accesses AutofillOfferManager via the
AutofillOfferManagerFactory, which will be used for updating credit card
suggestions to display offers. AutofillOfferManager will be a
BrowserContextKeyedService, with one instance per profile.

Bug: 1093057
Change-Id: Ia065577c702ad2784d54031b781eec0cdc74b89d
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2419238
Commit-Queue: Manas Verma <manasverma@google.com>
Reviewed-by: default avatarJared Saul <jsaul@google.com>
Reviewed-by: default avatarDominic Battré <battre@chromium.org>
Reviewed-by: default avatarTommy Martino <tmartino@chromium.org>
Reviewed-by: default avatarEvan Stade <estade@chromium.org>
Reviewed-by: default avatarSiyu An <siyua@chromium.org>
Reviewed-by: default avatarDavid Roger <droger@chromium.org>
Cr-Commit-Position: refs/heads/master@{#812871}
parent a76212d9
...@@ -137,6 +137,8 @@ static_library("browser") { ...@@ -137,6 +137,8 @@ static_library("browser") {
"autofill/autocomplete_history_manager_factory.h", "autofill/autocomplete_history_manager_factory.h",
"autofill/autofill_gstatic_reader.cc", "autofill/autofill_gstatic_reader.cc",
"autofill/autofill_gstatic_reader.h", "autofill/autofill_gstatic_reader.h",
"autofill/autofill_offer_manager_factory.cc",
"autofill/autofill_offer_manager_factory.h",
"autofill/autofill_profile_validator_factory.cc", "autofill/autofill_profile_validator_factory.cc",
"autofill/autofill_profile_validator_factory.h", "autofill/autofill_profile_validator_factory.h",
"autofill/personal_data_manager_factory.cc", "autofill/personal_data_manager_factory.cc",
......
// 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.
#include "chrome/browser/autofill/autofill_offer_manager_factory.h"
#include "base/memory/singleton.h"
#include "chrome/browser/autofill/personal_data_manager_factory.h"
#include "components/autofill/core/browser/payments/autofill_offer_manager.h"
#include "components/keyed_service/content/browser_context_dependency_manager.h"
namespace autofill {
// static
AutofillOfferManager* AutofillOfferManagerFactory::GetForBrowserContext(
content::BrowserContext* context) {
return static_cast<AutofillOfferManager*>(
GetInstance()->GetServiceForBrowserContext(context, true));
}
// static
AutofillOfferManagerFactory* AutofillOfferManagerFactory::GetInstance() {
return base::Singleton<AutofillOfferManagerFactory>::get();
}
AutofillOfferManagerFactory::AutofillOfferManagerFactory()
: BrowserContextKeyedServiceFactory(
"AutofillOfferManager",
BrowserContextDependencyManager::GetInstance()) {
DependsOn(PersonalDataManagerFactory::GetInstance());
}
AutofillOfferManagerFactory::~AutofillOfferManagerFactory() = default;
KeyedService* AutofillOfferManagerFactory::BuildServiceInstanceFor(
content::BrowserContext* context) const {
return new AutofillOfferManager(
PersonalDataManagerFactory::GetForBrowserContext(context));
}
} // namespace autofill
// 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.
#ifndef CHROME_BROWSER_AUTOFILL_AUTOFILL_OFFER_MANAGER_FACTORY_H_
#define CHROME_BROWSER_AUTOFILL_AUTOFILL_OFFER_MANAGER_FACTORY_H_
#include "base/compiler_specific.h"
#include "components/keyed_service/content/browser_context_keyed_service_factory.h"
#include "components/keyed_service/core/keyed_service.h"
namespace base {
template <typename T>
struct DefaultSingletonTraits;
}
namespace autofill {
class AutofillOfferManager;
// Singleton that owns all AutofillOfferManager and associates them with
// Profiles.
class AutofillOfferManagerFactory : public BrowserContextKeyedServiceFactory {
public:
AutofillOfferManagerFactory(const AutofillOfferManagerFactory&) = delete;
AutofillOfferManagerFactory& operator=(const AutofillOfferManagerFactory&) =
delete;
static AutofillOfferManager* GetForBrowserContext(
content::BrowserContext* context);
static AutofillOfferManagerFactory* GetInstance();
private:
friend struct base::DefaultSingletonTraits<AutofillOfferManagerFactory>;
AutofillOfferManagerFactory();
~AutofillOfferManagerFactory() override;
// BrowserContextKeyedServiceFactory:
KeyedService* BuildServiceInstanceFor(
content::BrowserContext* profile) const override;
};
} // namespace autofill
#endif // CHROME_BROWSER_AUTOFILL_AUTOFILL_OFFER_MANAGER_FACTORY_H_
...@@ -40,6 +40,13 @@ PersonalDataManager* PersonalDataManagerFactory::GetForProfile( ...@@ -40,6 +40,13 @@ PersonalDataManager* PersonalDataManagerFactory::GetForProfile(
GetInstance()->GetServiceForBrowserContext(profile, true)); GetInstance()->GetServiceForBrowserContext(profile, true));
} }
// static
PersonalDataManager* PersonalDataManagerFactory::GetForBrowserContext(
content::BrowserContext* context) {
return static_cast<PersonalDataManager*>(
GetInstance()->GetServiceForBrowserContext(context, true));
}
// static // static
PersonalDataManagerFactory* PersonalDataManagerFactory::GetInstance() { PersonalDataManagerFactory* PersonalDataManagerFactory::GetInstance() {
return base::Singleton<PersonalDataManagerFactory>::get(); return base::Singleton<PersonalDataManagerFactory>::get();
......
...@@ -30,6 +30,11 @@ class PersonalDataManagerFactory : public BrowserContextKeyedServiceFactory { ...@@ -30,6 +30,11 @@ class PersonalDataManagerFactory : public BrowserContextKeyedServiceFactory {
// yet created. // yet created.
static PersonalDataManager* GetForProfile(Profile* profile); static PersonalDataManager* GetForProfile(Profile* profile);
// Returns the PersonalDataManager for |context|, creating it if it is not
// yet created.
static PersonalDataManager* GetForBrowserContext(
content::BrowserContext* context);
static PersonalDataManagerFactory* GetInstance(); static PersonalDataManagerFactory* GetInstance();
static KeyedService* BuildPersonalDataManager( static KeyedService* BuildPersonalDataManager(
......
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#include "chrome/browser/autocomplete/autocomplete_classifier_factory.h" #include "chrome/browser/autocomplete/autocomplete_classifier_factory.h"
#include "chrome/browser/autocomplete/in_memory_url_index_factory.h" #include "chrome/browser/autocomplete/in_memory_url_index_factory.h"
#include "chrome/browser/autocomplete/shortcuts_backend_factory.h" #include "chrome/browser/autocomplete/shortcuts_backend_factory.h"
#include "chrome/browser/autofill/autofill_offer_manager_factory.h"
#include "chrome/browser/autofill/personal_data_manager_factory.h" #include "chrome/browser/autofill/personal_data_manager_factory.h"
#include "chrome/browser/background/background_contents_service_factory.h" #include "chrome/browser/background/background_contents_service_factory.h"
#include "chrome/browser/bookmarks/bookmark_model_factory.h" #include "chrome/browser/bookmarks/bookmark_model_factory.h"
...@@ -232,6 +233,7 @@ void ChromeBrowserMainExtraPartsProfiles:: ...@@ -232,6 +233,7 @@ void ChromeBrowserMainExtraPartsProfiles::
#endif #endif
AutocompleteClassifierFactory::GetInstance(); AutocompleteClassifierFactory::GetInstance();
autofill::PersonalDataManagerFactory::GetInstance(); autofill::PersonalDataManagerFactory::GetInstance();
autofill::AutofillOfferManagerFactory::GetInstance();
#if BUILDFLAG(ENABLE_BACKGROUND_CONTENTS) #if BUILDFLAG(ENABLE_BACKGROUND_CONTENTS)
BackgroundContentsServiceFactory::GetInstance(); BackgroundContentsServiceFactory::GetInstance();
#endif #endif
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#include "base/strings/utf_string_conversions.h" #include "base/strings/utf_string_conversions.h"
#include "chrome/browser/autofill/address_normalizer_factory.h" #include "chrome/browser/autofill/address_normalizer_factory.h"
#include "chrome/browser/autofill/autocomplete_history_manager_factory.h" #include "chrome/browser/autofill/autocomplete_history_manager_factory.h"
#include "chrome/browser/autofill/autofill_offer_manager_factory.h"
#include "chrome/browser/autofill/personal_data_manager_factory.h" #include "chrome/browser/autofill/personal_data_manager_factory.h"
#include "chrome/browser/autofill/risk_util.h" #include "chrome/browser/autofill/risk_util.h"
#include "chrome/browser/autofill/strike_database_factory.h" #include "chrome/browser/autofill/strike_database_factory.h"
...@@ -176,6 +177,11 @@ AddressNormalizer* ChromeAutofillClient::GetAddressNormalizer() { ...@@ -176,6 +177,11 @@ AddressNormalizer* ChromeAutofillClient::GetAddressNormalizer() {
return AddressNormalizerFactory::GetInstance(); return AddressNormalizerFactory::GetInstance();
} }
AutofillOfferManager* ChromeAutofillClient::GetAutofillOfferManager() {
return AutofillOfferManagerFactory::GetForBrowserContext(
web_contents()->GetBrowserContext());
}
const GURL& ChromeAutofillClient::GetLastCommittedURL() { const GURL& ChromeAutofillClient::GetLastCommittedURL() {
return web_contents()->GetLastCommittedURL(); return web_contents()->GetLastCommittedURL();
} }
......
...@@ -63,6 +63,7 @@ class ChromeAutofillClient ...@@ -63,6 +63,7 @@ class ChromeAutofillClient
ukm::UkmRecorder* GetUkmRecorder() override; ukm::UkmRecorder* GetUkmRecorder() override;
ukm::SourceId GetUkmSourceId() override; ukm::SourceId GetUkmSourceId() override;
AddressNormalizer* GetAddressNormalizer() override; AddressNormalizer* GetAddressNormalizer() override;
AutofillOfferManager* GetAutofillOfferManager() override;
const GURL& GetLastCommittedURL() override; const GURL& GetLastCommittedURL() override;
security_state::SecurityLevel GetSecurityLevelForUmaHistograms() override; security_state::SecurityLevel GetSecurityLevelForUmaHistograms() override;
const translate::LanguageState* GetLanguageState() override; const translate::LanguageState* GetLanguageState() override;
......
...@@ -629,6 +629,7 @@ source_set("unit_tests") { ...@@ -629,6 +629,7 @@ source_set("unit_tests") {
"logging/log_manager_unittest.cc", "logging/log_manager_unittest.cc",
"logging/log_router_unittest.cc", "logging/log_router_unittest.cc",
"pattern_provider/pattern_provider_unittest.cc", "pattern_provider/pattern_provider_unittest.cc",
"payments/autofill_offer_manager_unittest.cc",
"payments/credit_card_access_manager_unittest.cc", "payments/credit_card_access_manager_unittest.cc",
"payments/credit_card_cvc_authenticator_unittest.cc", "payments/credit_card_cvc_authenticator_unittest.cc",
"payments/credit_card_save_manager_unittest.cc", "payments/credit_card_save_manager_unittest.cc",
......
...@@ -35,6 +35,10 @@ version_info::Channel AutofillClient::GetChannel() const { ...@@ -35,6 +35,10 @@ version_info::Channel AutofillClient::GetChannel() const {
return version_info::Channel::UNKNOWN; return version_info::Channel::UNKNOWN;
} }
AutofillOfferManager* AutofillClient::GetAutofillOfferManager() {
return nullptr;
}
std::string AutofillClient::GetVariationConfigCountryCode() const { std::string AutofillClient::GetVariationConfigCountryCode() const {
return std::string(); return std::string();
} }
......
...@@ -59,6 +59,7 @@ namespace autofill { ...@@ -59,6 +59,7 @@ namespace autofill {
class AddressNormalizer; class AddressNormalizer;
class AutocompleteHistoryManager; class AutocompleteHistoryManager;
class AutofillOfferManager;
class AutofillPopupDelegate; class AutofillPopupDelegate;
class CardUnmaskDelegate; class CardUnmaskDelegate;
class CreditCard; class CreditCard;
...@@ -275,6 +276,10 @@ class AutofillClient : public RiskDataLoader { ...@@ -275,6 +276,10 @@ class AutofillClient : public RiskDataLoader {
// Gets an AddressNormalizer instance (can be null). // Gets an AddressNormalizer instance (can be null).
virtual AddressNormalizer* GetAddressNormalizer() = 0; virtual AddressNormalizer* GetAddressNormalizer() = 0;
// Gets an AutofillOfferManager instance (can be null for unsupported
// platforms).
virtual AutofillOfferManager* GetAutofillOfferManager();
// Gets the virtual URL of the last committed page of this client's // Gets the virtual URL of the last committed page of this client's
// associated WebContents. // associated WebContents.
virtual const GURL& GetLastCommittedURL() = 0; virtual const GURL& GetLastCommittedURL() = 0;
......
...@@ -61,6 +61,7 @@ ...@@ -61,6 +61,7 @@
#include "components/autofill/core/browser/geo/phone_number_i18n.h" #include "components/autofill/core/browser/geo/phone_number_i18n.h"
#include "components/autofill/core/browser/logging/log_manager.h" #include "components/autofill/core/browser/logging/log_manager.h"
#include "components/autofill/core/browser/metrics/form_events.h" #include "components/autofill/core/browser/metrics/form_events.h"
#include "components/autofill/core/browser/payments/autofill_offer_manager.h"
#include "components/autofill/core/browser/payments/credit_card_access_manager.h" #include "components/autofill/core/browser/payments/credit_card_access_manager.h"
#include "components/autofill/core/browser/payments/payments_client.h" #include "components/autofill/core/browser/payments/payments_client.h"
#include "components/autofill/core/browser/personal_data_manager.h" #include "components/autofill/core/browser/personal_data_manager.h"
...@@ -1590,6 +1591,7 @@ void AutofillManager::Reset() { ...@@ -1590,6 +1591,7 @@ void AutofillManager::Reset() {
personal_data_, client_)); personal_data_, client_));
credit_card_access_manager_.reset(new CreditCardAccessManager( credit_card_access_manager_.reset(new CreditCardAccessManager(
driver(), client_, personal_data_, credit_card_form_event_logger_.get())); driver(), client_, personal_data_, credit_card_form_event_logger_.get()));
has_logged_autofill_enabled_ = false; has_logged_autofill_enabled_ = false;
has_logged_address_suggestions_count_ = false; has_logged_address_suggestions_count_ = false;
did_show_suggestions_ = false; did_show_suggestions_ = false;
...@@ -1651,6 +1653,7 @@ AutofillManager::AutofillManager( ...@@ -1651,6 +1653,7 @@ AutofillManager::AutofillManager(
driver, this, GetAPIKeyForUrl(channel), client_->GetLogManager())); driver, this, GetAPIKeyForUrl(channel), client_->GetLogManager()));
} }
CountryNames::SetLocaleString(app_locale_); CountryNames::SetLocaleString(app_locale_);
offer_manager_ = client_->GetAutofillOfferManager();
} }
bool AutofillManager::RefreshDataModels() { bool AutofillManager::RefreshDataModels() {
...@@ -2007,6 +2010,12 @@ std::vector<Suggestion> AutofillManager::GetCreditCardSuggestions( ...@@ -2007,6 +2010,12 @@ std::vector<Suggestion> AutofillManager::GetCreditCardSuggestions(
personal_data_->GetCreditCardSuggestions( personal_data_->GetCreditCardSuggestions(
type, SanitizeCreditCardFieldValue(field.value), type, SanitizeCreditCardFieldValue(field.value),
client_->AreServerCardsSupported()); client_->AreServerCardsSupported());
if (base::FeatureList::IsEnabled(
features::kAutofillEnableOffersInDownstream) &&
offer_manager_) {
offer_manager_->UpdateSuggestionsWithOffers(client_->GetLastCommittedURL(),
suggestions);
}
*should_display_gpay_logo = *should_display_gpay_logo =
credit_card_access_manager_->ShouldDisplayGPayLogo(); credit_card_access_manager_->ShouldDisplayGPayLogo();
......
...@@ -32,6 +32,7 @@ ...@@ -32,6 +32,7 @@
#include "components/autofill/core/browser/form_types.h" #include "components/autofill/core/browser/form_types.h"
#include "components/autofill/core/browser/metrics/address_form_event_logger.h" #include "components/autofill/core/browser/metrics/address_form_event_logger.h"
#include "components/autofill/core/browser/metrics/credit_card_form_event_logger.h" #include "components/autofill/core/browser/metrics/credit_card_form_event_logger.h"
#include "components/autofill/core/browser/payments/autofill_offer_manager.h"
#include "components/autofill/core/browser/payments/card_unmask_delegate.h" #include "components/autofill/core/browser/payments/card_unmask_delegate.h"
#include "components/autofill/core/browser/payments/credit_card_access_manager.h" #include "components/autofill/core/browser/payments/credit_card_access_manager.h"
#include "components/autofill/core/browser/payments/full_card_request.h" #include "components/autofill/core/browser/payments/full_card_request.h"
...@@ -681,6 +682,10 @@ class AutofillManager : public AutofillHandler, ...@@ -681,6 +682,10 @@ class AutofillManager : public AutofillHandler,
// The credit card access manager, used to access local and server cards. // The credit card access manager, used to access local and server cards.
std::unique_ptr<CreditCardAccessManager> credit_card_access_manager_; std::unique_ptr<CreditCardAccessManager> credit_card_access_manager_;
// The autofill offer manager, used to to retrieve offers for card
// suggestions.
AutofillOfferManager* offer_manager_;
// Collected information about the autofill form where a credit card will be // Collected information about the autofill form where a credit card will be
// filled. // filled.
AutofillDriver::RendererFormDataAction credit_card_action_; AutofillDriver::RendererFormDataAction credit_card_action_;
......
...@@ -4,10 +4,114 @@ ...@@ -4,10 +4,114 @@
#include "components/autofill/core/browser/payments/autofill_offer_manager.h" #include "components/autofill/core/browser/payments/autofill_offer_manager.h"
#include <map>
#include "base/bind.h"
#include "base/ranges/algorithm.h"
#include "base/ranges/ranges.h"
#include "base/strings/utf_string_conversions.h"
#include "base/time/time.h"
#include "base/timer/timer.h"
#include "components/autofill/core/browser/autofill_client.h"
#include "components/autofill/core/browser/data_model/autofill_offer_data.h"
#include "components/autofill/core/browser/payments/payments_client.h"
#include "components/autofill/core/common/autofill_clock.h"
#include "components/strings/grit/components_strings.h"
#include "ui/base/l10n/l10n_util.h"
#include "url/gurl.h"
namespace autofill { namespace autofill {
AutofillOfferManager::AutofillOfferManager() = default; namespace {
// Ensure the offer is not expired and is valid for the current page.
bool IsOfferEligible(const AutofillOfferData& offer,
const GURL& last_committed_url) {
bool is_eligible = (offer.expiry > AutofillClock::Now());
is_eligible &= base::ranges::count(offer.merchant_domain, last_committed_url);
return is_eligible;
}
} // namespace
AutofillOfferManager::AutofillOfferManager(PersonalDataManager* personal_data)
: personal_data_(personal_data) {
personal_data_->AddObserver(this);
UpdateEligibleMerchantDomains();
}
AutofillOfferManager::~AutofillOfferManager() {
personal_data_->RemoveObserver(this);
}
void AutofillOfferManager::OnPersonalDataChanged() {
UpdateEligibleMerchantDomains();
}
void AutofillOfferManager::UpdateSuggestionsWithOffers(
const GURL& last_committed_url,
std::vector<Suggestion>& suggestions) {
if (eligible_merchant_domains_.count(last_committed_url) == 0) {
return;
}
AutofillOfferManager::OffersMap eligible_offers_map =
CreateOffersMap(last_committed_url);
// Update |offer_label| for each suggestion.
for (auto& suggestion : suggestions) {
std::string id = suggestion.backend_id;
if (eligible_offers_map.count(id)) {
base::string16 reward_amount =
base::UTF8ToUTF16(eligible_offers_map[id]->offer_reward_amount);
auto string_id = (reward_amount.find('%') == std::string::npos)
? IDS_AUTOFILL_OFFERS_DISCOUNT
: IDS_AUTOFILL_OFFERS_CASHBACK;
suggestion.offer_label =
l10n_util::GetStringFUTF16(string_id, reward_amount);
}
}
}
void AutofillOfferManager::UpdateEligibleMerchantDomains() {
eligible_merchant_domains_.clear();
std::vector<AutofillOfferData*> offers =
personal_data_->GetCreditCardOffers();
for (auto* offer : offers) {
for (auto& domain : offer->merchant_domain) {
eligible_merchant_domains_.emplace(domain);
}
}
}
AutofillOfferManager::OffersMap AutofillOfferManager::CreateOffersMap(
const GURL& last_committed_url) const {
AutofillOfferManager::OffersMap offers_map;
std::vector<AutofillOfferData*> offers =
personal_data_->GetCreditCardOffers();
std::vector<CreditCard*> cards = personal_data_->GetCreditCards();
for (auto* offer : offers) {
// Ensure the offer is valid.
if (!IsOfferEligible(*offer, last_committed_url)) {
continue;
}
// Find card with corresponding instrument ID and add its guid to the map.
for (const auto* card : cards) {
// If card has an offer, add the backend ID to the map. There is currently
// a one-to-one mapping between cards and offer data, however, this may
// change in the future.
if (std::count(offer->eligible_instrument_id.begin(),
offer->eligible_instrument_id.end(),
card->instrument_id())) {
offers_map[card->guid()] = offer;
}
}
}
AutofillOfferManager::~AutofillOfferManager() = default; return offers_map;
}
} // namespace autofill } // namespace autofill
\ No newline at end of file
...@@ -5,38 +5,56 @@ ...@@ -5,38 +5,56 @@
#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_AUTOFILL_OFFER_MANAGER_H_ #ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_AUTOFILL_OFFER_MANAGER_H_
#define COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_AUTOFILL_OFFER_MANAGER_H_ #define COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_AUTOFILL_OFFER_MANAGER_H_
#include <stdint.h>
#include <map>
#include <string> #include <string>
#include <vector> #include <vector>
#include "base/strings/string16.h" #include "base/strings/string16.h"
#include "base/time/time.h"
#include "base/timer/timer.h"
#include "components/autofill/core/browser/autofill_client.h"
#include "components/autofill/core/browser/data_model/autofill_offer_data.h"
#include "components/autofill/core/browser/personal_data_manager.h"
#include "components/autofill/core/browser/personal_data_manager_observer.h"
#include "components/keyed_service/core/keyed_service.h"
#include "url/gurl.h"
namespace autofill { namespace autofill {
struct AutofillOfferData {
AutofillOfferData();
~AutofillOfferData();
// The description of this offer.
base::string16 description;
// The name of this offer.
base::string16 name;
// The unique server id of this offer.
std::string offer_id;
// The ids of the cards this offer can be applied to.
std::vector<std::string> eligible_card_id;
// The merchant URL where this offer can be redeemed.
std::vector<std::string> merchant_domain;
};
// Manages all Autofill related offers. One per frame; owned by the // Manages all Autofill related offers. One per frame; owned by the
// AutofillManager. // AutofillManager.
class AutofillOfferManager { class AutofillOfferManager : public KeyedService,
public PersonalDataManagerObserver {
public: public:
AutofillOfferManager(); // Mapping from suggestion backend ID to offer data.
virtual ~AutofillOfferManager(); using OffersMap = std::map<std::string, AutofillOfferData*>;
explicit AutofillOfferManager(PersonalDataManager* personal_data);
~AutofillOfferManager() override;
AutofillOfferManager(const AutofillOfferManager&) = delete; AutofillOfferManager(const AutofillOfferManager&) = delete;
AutofillOfferManager& operator=(const AutofillOfferManager&) = delete; AutofillOfferManager& operator=(const AutofillOfferManager&) = delete;
// PersonalDataManagerObserver:
void OnPersonalDataChanged() override;
// Modifies any suggestion in |suggestions| if it has related offer data.
void UpdateSuggestionsWithOffers(const GURL& last_committed_url,
std::vector<Suggestion>& suggestions);
private:
// Queries |personal_data_| to reset the elements of
// |eligible_merchant_domains_|
void UpdateEligibleMerchantDomains();
// Creates a mapping from Suggestion Backend ID's to eligible Credit Card
// Offers.
OffersMap CreateOffersMap(const GURL& last_committed_url) const;
PersonalDataManager* personal_data_;
std::set<GURL> eligible_merchant_domains_ = {};
}; };
} // namespace autofill } // namespace autofill
#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_AUTOFILL_OFFER_MANAGER_H_ #endif // COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_AUTOFILL_OFFER_MANAGER_H_
\ No newline at end of file
// 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.
#include <memory>
#include "base/bind.h"
#include "base/strings/utf_string_conversions.h"
#include "base/test/task_environment.h"
#include "base/time/time.h"
#include "components/autofill/core/browser/autofill_test_utils.h"
#include "components/autofill/core/browser/payments/autofill_offer_manager.h"
#include "components/autofill/core/browser/test_autofill_client.h"
#include "components/autofill/core/browser/test_personal_data_manager.h"
#include "components/autofill/core/browser/webdata/autofill_webdata_service.h"
#include "components/autofill/core/common/autofill_clock.h"
#include "services/network/public/cpp/shared_url_loader_factory.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/base/l10n/l10n_util.h"
#include "url/gurl.h"
namespace autofill {
namespace {
const char kTestGuid[] = "00000000-0000-0000-0000-000000000001";
const char kTestNumber[] = "4234567890123456"; // Visa
const char kTestUrl[] = "http://www.example.com/";
} // namespace
class AutofillOfferManagerTest : public testing::Test {
public:
AutofillOfferManagerTest() = default;
~AutofillOfferManagerTest() override = default;
void SetUp() override {
autofill_client_.SetPrefs(test::PrefServiceForTesting());
personal_data_manager_.Init(/*profile_database=*/database_,
/*account_database=*/nullptr,
/*pref_service=*/autofill_client_.GetPrefs(),
/*identity_manager=*/nullptr,
/*client_profile_validator=*/nullptr,
/*history_service=*/nullptr,
/*is_off_the_record=*/false);
personal_data_manager_.SetPrefService(autofill_client_.GetPrefs());
autofill_offer_manager_ =
std::make_unique<AutofillOfferManager>(&personal_data_manager_);
}
CreditCard CreateCreditCard(std::string guid,
std::string number = kTestNumber) {
CreditCard card = CreditCard();
test::SetCreditCardInfo(&card, "Jane Doe", number.c_str(),
test::NextMonth().c_str(), test::NextYear().c_str(),
"1");
card.set_guid(guid);
card.set_record_type(CreditCard::MASKED_SERVER_CARD);
personal_data_manager_.AddServerCreditCard(card);
return card;
}
void CreateCreditCardOfferForCard(const CreditCard& card,
std::string offer_reward_amount,
bool expired = false) {
AutofillOfferData offer_data;
offer_data.offer_id = 4444;
offer_data.offer_reward_amount = offer_reward_amount;
if (expired) {
offer_data.expiry = AutofillClock::Now() - base::TimeDelta::FromDays(2);
} else {
offer_data.expiry = AutofillClock::Now() + base::TimeDelta::FromDays(2);
}
offer_data.merchant_domain = {GURL(kTestUrl)};
offer_data.eligible_instrument_id = {card.instrument_id()};
personal_data_manager_.AddCreditCardOfferData(offer_data);
}
protected:
base::test::TaskEnvironment task_environment_{
base::test::TaskEnvironment::TimeSource::MOCK_TIME};
TestAutofillClient autofill_client_;
scoped_refptr<AutofillWebDataService> database_;
TestPersonalDataManager personal_data_manager_;
std::unique_ptr<AutofillOfferManager> autofill_offer_manager_ = nullptr;
};
TEST_F(AutofillOfferManagerTest, UpdateSuggestionsWithOffers_EligibleDiscount) {
CreditCard card = CreateCreditCard(kTestGuid);
CreateCreditCardOfferForCard(card, "$4");
std::vector<Suggestion> suggestions = {Suggestion()};
suggestions[0].backend_id = kTestGuid;
autofill_offer_manager_->UpdateSuggestionsWithOffers(GURL(kTestUrl),
suggestions);
EXPECT_EQ(suggestions[0].offer_label, base::UTF8ToUTF16("$4 Off"));
}
TEST_F(AutofillOfferManagerTest, UpdateSuggestionsWithOffers_EligibleCashback) {
CreditCard card = CreateCreditCard(kTestGuid);
CreateCreditCardOfferForCard(card, "5%");
std::vector<Suggestion> suggestions = {Suggestion()};
suggestions[0].backend_id = kTestGuid;
autofill_offer_manager_->UpdateSuggestionsWithOffers(GURL(kTestUrl),
suggestions);
EXPECT_EQ(suggestions[0].offer_label, base::UTF8ToUTF16("5% Cash Back"));
}
TEST_F(AutofillOfferManagerTest, UpdateSuggestionsWithOffers_ExpiredOffer) {
CreditCard card = CreateCreditCard(kTestGuid);
CreateCreditCardOfferForCard(card, "5%", /*expired=*/true);
std::vector<Suggestion> suggestions = {Suggestion()};
suggestions[0].backend_id = kTestGuid;
autofill_offer_manager_->UpdateSuggestionsWithOffers(GURL(kTestUrl),
suggestions);
EXPECT_TRUE(suggestions[0].offer_label.empty());
}
TEST_F(AutofillOfferManagerTest, UpdateSuggestionsWithOffers_WrongUrl) {
CreditCard card = CreateCreditCard(kTestGuid);
CreateCreditCardOfferForCard(card, "5%");
std::vector<Suggestion> suggestions = {Suggestion()};
suggestions[0].backend_id = kTestGuid;
autofill_offer_manager_->UpdateSuggestionsWithOffers(
GURL("http://wrongurl.com/"), suggestions);
EXPECT_TRUE(suggestions[0].offer_label.empty());
}
} // namespace autofill
...@@ -294,6 +294,10 @@ void TestPersonalDataManager::ClearCloudTokenData() { ...@@ -294,6 +294,10 @@ void TestPersonalDataManager::ClearCloudTokenData() {
server_credit_card_cloud_token_data_.clear(); server_credit_card_cloud_token_data_.clear();
} }
void TestPersonalDataManager::ClearCreditCardOfferData() {
autofill_offer_data_.clear();
}
AutofillProfile* TestPersonalDataManager::GetProfileWithGUID(const char* guid) { AutofillProfile* TestPersonalDataManager::GetProfileWithGUID(const char* guid) {
for (AutofillProfile* profile : GetProfiles()) { for (AutofillProfile* profile : GetProfiles()) {
if (!profile->guid().compare(guid)) if (!profile->guid().compare(guid))
...@@ -326,6 +330,14 @@ void TestPersonalDataManager::AddCloudTokenData( ...@@ -326,6 +330,14 @@ void TestPersonalDataManager::AddCloudTokenData(
NotifyPersonalDataObserver(); NotifyPersonalDataObserver();
} }
void TestPersonalDataManager::AddCreditCardOfferData(
const AutofillOfferData& offer_data) {
std::unique_ptr<AutofillOfferData> data =
std::make_unique<AutofillOfferData>(offer_data);
autofill_offer_data_.emplace_back(std::move(data));
NotifyPersonalDataObserver();
}
void TestPersonalDataManager::SetNicknameForCardWithGUID( void TestPersonalDataManager::SetNicknameForCardWithGUID(
const char* guid, const char* guid,
const std::string& nickname) { const std::string& nickname) {
......
...@@ -75,6 +75,9 @@ class TestPersonalDataManager : public PersonalDataManager { ...@@ -75,6 +75,9 @@ class TestPersonalDataManager : public PersonalDataManager {
// Clears |server_credit_card_cloud_token_data_|. // Clears |server_credit_card_cloud_token_data_|.
void ClearCloudTokenData(); void ClearCloudTokenData();
// Clears |autofill_offer_data_|.
void ClearCreditCardOfferData();
// Gets a profile based on the provided |guid|. // Gets a profile based on the provided |guid|.
AutofillProfile* GetProfileWithGUID(const char* guid); AutofillProfile* GetProfileWithGUID(const char* guid);
...@@ -88,6 +91,9 @@ class TestPersonalDataManager : public PersonalDataManager { ...@@ -88,6 +91,9 @@ class TestPersonalDataManager : public PersonalDataManager {
// Adds a cloud token data to |server_credit_card_cloud_token_data_|. // Adds a cloud token data to |server_credit_card_cloud_token_data_|.
void AddCloudTokenData(const CreditCardCloudTokenData& cloud_token_data); void AddCloudTokenData(const CreditCardCloudTokenData& cloud_token_data);
// Adds offer data to |autofill_offer_data_|.
void AddCreditCardOfferData(const AutofillOfferData& offer_data);
// Sets a local/server card's nickname based on the provided |guid|. // Sets a local/server card's nickname based on the provided |guid|.
void SetNicknameForCardWithGUID(const char* guid, void SetNicknameForCardWithGUID(const char* guid,
const std::string& nickname); const std::string& nickname);
......
...@@ -50,6 +50,9 @@ struct Suggestion { ...@@ -50,6 +50,9 @@ struct Suggestion {
base::string16 value; base::string16 value;
base::string16 label; base::string16 label;
// A label to be shown beneath |label| that will display information about any
// credit card offers or rewards.
base::string16 offer_label;
// Used only for passwords to show the password value. // Used only for passwords to show the password value.
// Also used to display an extra line of information if two line // Also used to display an extra line of information if two line
// display is enabled. // display is enabled.
......
...@@ -505,4 +505,12 @@ ...@@ -505,4 +505,12 @@
No thanks No thanks
</message> </message>
<!-- Credit card offers and rewards related strings -->
<message name="IDS_AUTOFILL_OFFERS_CASHBACK" desc="Displays that a cashback offer will be rewarded if credit card is used on current page. Part of Autofill suggestions popup.">
<ph name="PERCENT">$1<ex>5%</ex></ph> Cash Back
</message>
<message name="IDS_AUTOFILL_OFFERS_DISCOUNT" desc="Displays a discount that will be rewarded if credit card is used on current page. Part of Autofill suggestions popup.">
<ph name="DISCOUNT">$1<ex>$$3</ex></ph> Off
</message>
</grit-part> </grit-part>
378244426ac8f525d17518614e3d7b1508061cf9
\ No newline at end of file
a09ae4c895b292cf8ce625cf9843a477d86dfc35
\ No newline at end of file
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