Commit 9183784e authored by Ben Blake's avatar Ben Blake Committed by Commit Bot

Create AutofillOfferManagerFactory and implement GetOfferDataRequest.

This change further implements the functionality of AutofillOfferManager. AutofillManager now accesses a singleton AutofillOfferManager via the AutofillOfferManagerFactory. AutofillOfferManager then prepares a request which is sent to the PaymentsClient to retrieve offer data. In further CLs, the data retrieved during these calls will stored and used.

Change-Id: I384c95f26b9b3094d9b3387d467134ef5998396e
Bug: 1093057
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2258154
Commit-Queue: Ben Blake <fiorito@google.com>
Reviewed-by: default avatarAnne Lim <annelim@google.com>
Reviewed-by: default avatarDominic Battré <battre@chromium.org>
Reviewed-by: default avatarVasilii Sukhanov <vasilii@chromium.org>
Reviewed-by: default avatarJared Saul <jsaul@google.com>
Reviewed-by: default avatarSiyu An <siyua@chromium.org>
Cr-Commit-Position: refs/heads/master@{#798344}
parent 2d174628
...@@ -143,6 +143,8 @@ static_library("browser") { ...@@ -143,6 +143,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/profiles/profile.h"
#include "components/autofill/core/browser/payments/autofill_offer_manager.h"
#include "components/keyed_service/content/browser_context_dependency_manager.h"
namespace autofill {
namespace payments {
// static
AutofillOfferManager* AutofillOfferManagerFactory::GetForProfile(
Profile* profile) {
return static_cast<AutofillOfferManager*>(
GetInstance()->GetServiceForBrowserContext(profile, true));
}
// static
AutofillOfferManagerFactory* AutofillOfferManagerFactory::GetInstance() {
return base::Singleton<AutofillOfferManagerFactory>::get();
}
AutofillOfferManagerFactory::AutofillOfferManagerFactory()
: BrowserContextKeyedServiceFactory(
"AutofillOfferManager",
BrowserContextDependencyManager::GetInstance()) {}
AutofillOfferManagerFactory::~AutofillOfferManagerFactory() = default;
KeyedService* AutofillOfferManagerFactory::BuildServiceInstanceFor(
content::BrowserContext* context) const {
return new AutofillOfferManager();
}
} // namespace payments
} // 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;
}
class Profile;
namespace autofill {
namespace payments {
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* GetForProfile(Profile* profile);
static AutofillOfferManagerFactory* GetInstance();
private:
friend struct base::DefaultSingletonTraits<AutofillOfferManagerFactory>;
AutofillOfferManagerFactory();
~AutofillOfferManagerFactory() override;
// BrowserContextKeyedServiceFactory:
KeyedService* BuildServiceInstanceFor(
content::BrowserContext* profile) const override;
};
} // namespace payments
} // namespace autofill
#endif // CHROME_BROWSER_AUTOFILL_AUTOFILL_OFFER_MANAGER_FACTORY_H_
...@@ -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"
...@@ -178,6 +179,13 @@ AddressNormalizer* ChromeAutofillClient::GetAddressNormalizer() { ...@@ -178,6 +179,13 @@ AddressNormalizer* ChromeAutofillClient::GetAddressNormalizer() {
return nullptr; return nullptr;
} }
payments::AutofillOfferManager*
ChromeAutofillClient::GetAutofillOfferManager() {
Profile* profile =
Profile::FromBrowserContext(web_contents()->GetBrowserContext());
return payments::AutofillOfferManagerFactory::GetForProfile(profile);
}
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;
payments::AutofillOfferManager* GetAutofillOfferManager() override;
const GURL& GetLastCommittedURL() override; const GURL& GetLastCommittedURL() override;
security_state::SecurityLevel GetSecurityLevelForUmaHistograms() override; security_state::SecurityLevel GetSecurityLevelForUmaHistograms() override;
std::string GetPageLanguage() const override; std::string GetPageLanguage() const override;
......
...@@ -83,6 +83,8 @@ static_library("browser") { ...@@ -83,6 +83,8 @@ static_library("browser") {
"data_model/autofill_data_model.h", "data_model/autofill_data_model.h",
"data_model/autofill_metadata.cc", "data_model/autofill_metadata.cc",
"data_model/autofill_metadata.h", "data_model/autofill_metadata.h",
"data_model/autofill_offer_data.cc",
"data_model/autofill_offer_data.h",
"data_model/autofill_profile.cc", "data_model/autofill_profile.cc",
"data_model/autofill_profile.h", "data_model/autofill_profile.h",
"data_model/autofill_profile_comparator.cc", "data_model/autofill_profile_comparator.cc",
...@@ -608,6 +610,7 @@ source_set("unit_tests") { ...@@ -608,6 +610,7 @@ source_set("unit_tests") {
"logging/log_buffer_submitter_unittest.cc", "logging/log_buffer_submitter_unittest.cc",
"logging/log_manager_unittest.cc", "logging/log_manager_unittest.cc",
"logging/log_router_unittest.cc", "logging/log_router_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;
} }
payments::AutofillOfferManager* AutofillClient::GetAutofillOfferManager() {
return nullptr;
}
std::string AutofillClient::GetPageLanguage() const { std::string AutofillClient::GetPageLanguage() const {
return std::string(); return std::string();
} }
......
...@@ -72,6 +72,7 @@ enum class WebauthnDialogState; ...@@ -72,6 +72,7 @@ enum class WebauthnDialogState;
struct Suggestion; struct Suggestion;
namespace payments { namespace payments {
class AutofillOfferManager;
class PaymentsClient; class PaymentsClient;
} }
...@@ -274,6 +275,9 @@ class AutofillClient : public RiskDataLoader { ...@@ -274,6 +275,9 @@ 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.
virtual payments::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;
......
...@@ -60,6 +60,7 @@ ...@@ -60,6 +60,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"
...@@ -1657,6 +1658,12 @@ AutofillManager::AutofillManager( ...@@ -1657,6 +1658,12 @@ AutofillManager::AutofillManager(
driver, this, GetAPIKeyForUrl(channel), client_->GetLogManager())); driver, this, GetAPIKeyForUrl(channel), client_->GetLogManager()));
} }
CountryNames::SetLocaleString(app_locale_); CountryNames::SetLocaleString(app_locale_);
if (base::FeatureList::IsEnabled(
features::kAutofillEnableOffersInDownstream)) {
offer_manager_ = client_->GetAutofillOfferManager();
if (offer_manager_)
offer_manager_->Init(client_, app_locale_);
}
} }
bool AutofillManager::RefreshDataModels() { bool AutofillManager::RefreshDataModels() {
......
...@@ -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"
...@@ -673,6 +674,10 @@ class AutofillManager : public AutofillHandler, ...@@ -673,6 +674,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.
payments::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_;
......
// 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 "components/autofill/core/browser/data_model/autofill_offer_data.h"
namespace autofill {
namespace payments {
AutofillOfferData::AutofillOfferData() = default;
AutofillOfferData::~AutofillOfferData() = default;
AutofillOfferData::AutofillOfferData(const AutofillOfferData&) = default;
AutofillOfferData& AutofillOfferData::operator=(const AutofillOfferData&) =
default;
} // namespace payments
} // 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 COMPONENTS_AUTOFILL_CORE_BROWSER_DATA_MODEL_AUTOFILL_OFFER_DATA_H_
#define COMPONENTS_AUTOFILL_CORE_BROWSER_DATA_MODEL_AUTOFILL_OFFER_DATA_H_
#include <string>
#include <vector>
#include "base/strings/string16.h"
#include "url/gurl.h"
namespace autofill {
namespace payments {
// Represents an offer for certain merchants redeemable with certain cards.
struct AutofillOfferData {
public:
AutofillOfferData();
~AutofillOfferData();
AutofillOfferData(const AutofillOfferData&);
AutofillOfferData& operator=(const AutofillOfferData&);
// The unique server id of this offer.
std::string offer_id;
// The name of this offer.
base::string16 name;
// The description of this offer.
base::string16 description;
// The expiration timestamp of this offer, in the form of seconds since Unix
// epoch.
int64_t expiry;
// The merchant URL where this offer can be redeemed.
GURL merchant_domain;
// The ids of the cards this offer can be applied to.
std::vector<std::string> eligible_instrument_id;
// The legacy ids of the cards this offer can be applied to.
std::vector<std::string> eligible_legacy_instrument_id;
};
} // namespace payments
} // namespace autofill
#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_DATA_MODEL_AUTOFILL_OFFER_DATA_H_
...@@ -4,10 +4,54 @@ ...@@ -4,10 +4,54 @@
#include "components/autofill/core/browser/payments/autofill_offer_manager.h" #include "components/autofill/core/browser/payments/autofill_offer_manager.h"
#include "base/bind.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 "url/gurl.h"
namespace autofill { namespace autofill {
namespace payments {
AutofillOfferManager::AutofillOfferManager() = default; AutofillOfferManager::AutofillOfferManager() = default;
AutofillOfferManager::~AutofillOfferManager() = default; AutofillOfferManager::~AutofillOfferManager() = default;
void AutofillOfferManager::Init(AutofillClient* client,
const std::string& app_locale) {
if (base::TimeDelta(AutofillClock::Now() - last_updated_timestamp_) >=
base::TimeDelta::FromMicroseconds(kOfferDataExpiryTimeInMicros) &&
!request_is_active_) {
client->GetPaymentsClient()->GetOfferData(
app_locale, base::BindOnce(&AutofillOfferManager::OnDidGetOfferData,
weak_ptr_factory_.GetWeakPtr()));
request_is_active_ = true;
request_timer_.Start(
FROM_HERE,
base::TimeDelta::FromMicroseconds(kRequestExpiryTimeInMicros), this,
&AutofillOfferManager::OnRequestTimeout);
}
}
void AutofillOfferManager::OnRequestTimeout() {
request_is_active_ = false;
}
void AutofillOfferManager::OnDidGetOfferData(
AutofillClient::PaymentsRpcResult result,
const std::vector<AutofillOfferData>& offers) {
request_timer_.Stop();
request_is_active_ = false;
if (result == AutofillClient::SUCCESS) {
// TODO(crbug/1093057): Parse and store returned offer data.
last_updated_timestamp_ = AutofillClock::Now();
}
}
} // namespace payments
} // namespace autofill } // namespace autofill
...@@ -5,38 +5,78 @@ ...@@ -5,38 +5,78 @@
#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 <string> #include <string>
#include <vector> #include <vector>
#include "base/memory/weak_ptr.h"
#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/keyed_service/core/keyed_service.h"
// Constant used to set intervals between calls for new offer data.
static const int64_t kOfferDataExpiryTimeInMicros =
int64_t{1000000 * 60 * 60 * 24}; // 24 hours
// Constant used to set expiry time for a single call before the next call can
// be made.
static const int64_t kRequestExpiryTimeInMicros =
int64_t{1000000 * 60}; // 1 minute
namespace autofill { namespace autofill {
struct AutofillOfferData { class AutofillClient;
AutofillOfferData();
~AutofillOfferData(); namespace payments {
// 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: public:
AutofillOfferManager(); AutofillOfferManager();
virtual ~AutofillOfferManager(); ~AutofillOfferManager() override;
AutofillOfferManager(const AutofillOfferManager&) = delete; AutofillOfferManager(const AutofillOfferManager&) = delete;
AutofillOfferManager& operator=(const AutofillOfferManager&) = delete; AutofillOfferManager& operator=(const AutofillOfferManager&) = delete;
void Init(AutofillClient* client, const std::string& app_locale);
private:
// Helper function used as callback when using |request_timer_|
void OnRequestTimeout();
// Callback function after successfully retrieving offer data.
void OnDidGetOfferData(AutofillClient::PaymentsRpcResult result,
const std::vector<AutofillOfferData>& offers);
// The time the offer data was last retrieved from Payments.
base::Time last_updated_timestamp_;
// Bool used to track if a request has been sent.
bool request_is_active_ = false;
// Timer used to wait for sent requests to come back before sending another.
base::OneShotTimer request_timer_;
base::WeakPtrFactory<AutofillOfferManager> weak_ptr_factory_{this};
FRIEND_TEST_ALL_PREFIXES(AutofillOfferManagerTest, InitFirstCallSucceeds);
FRIEND_TEST_ALL_PREFIXES(AutofillOfferManagerTest,
InitBeforeOfferDataExpiry_OneSecond);
FRIEND_TEST_ALL_PREFIXES(AutofillOfferManagerTest,
InitAfterOfferDataExpiry_OneSecond);
FRIEND_TEST_ALL_PREFIXES(AutofillOfferManagerTest,
InitBeforeTimerExpiry_OneSecond);
FRIEND_TEST_ALL_PREFIXES(AutofillOfferManagerTest,
InitAfterTimerExpiry_OneSecond);
FRIEND_TEST_ALL_PREFIXES(AutofillOfferManagerTest,
InitAfterOfferDataExpiryButRequestActive);
}; };
} // namespace payments
} // namespace autofill } // namespace autofill
#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_AUTOFILL_OFFER_MANAGER_H_ #endif // COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_AUTOFILL_OFFER_MANAGER_H_
// 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/test/task_environment.h"
#include "base/time/time.h"
#include "components/autofill/core/browser/payments/autofill_offer_manager.h"
#include "components/autofill/core/browser/payments/test_payments_client.h"
#include "components/autofill/core/browser/test_autofill_client.h"
#include "components/autofill/core/browser/test_autofill_driver.h"
#include "components/autofill/core/common/autofill_clock.h"
#include "services/network/public/cpp/shared_url_loader_factory.h"
static const char kTestAppLocale[] = "en";
static const int64_t kOneSecondMicros = 1000000;
namespace autofill {
namespace payments {
class AutofillOfferManagerTest : public testing::Test {
public:
AutofillOfferManagerTest() = default;
~AutofillOfferManagerTest() override = default;
void SetUp() override {
payments_client_ = new TestPaymentsClient(
autofill_driver_.GetURLLoaderFactory(),
autofill_client_.GetIdentityManager(), &personal_data_manager_);
autofill_client_.set_test_payments_client(
std::unique_ptr<TestPaymentsClient>(payments_client_));
}
protected:
base::test::TaskEnvironment task_environment_{
base::test::TaskEnvironment::TimeSource::MOCK_TIME};
TestAutofillClient autofill_client_;
TestAutofillDriver autofill_driver_;
TestPersonalDataManager personal_data_manager_;
TestPaymentsClient* payments_client_;
AutofillOfferManager autofill_offer_manager_;
};
TEST_F(AutofillOfferManagerTest, InitFirstCallSucceeds) {
autofill_offer_manager_.Init(&autofill_client_, kTestAppLocale);
// Should call GetOfferData, as this is the first time Init() has been called
// and the |last_updated_timestamp| has not been set.
EXPECT_EQ(payments_client_->get_offer_data_calls(), 1);
}
TEST_F(AutofillOfferManagerTest, InitBeforeOfferDataExpiry_OneSecond) {
autofill_offer_manager_.last_updated_timestamp_ = AutofillClock::Now();
task_environment_.FastForwardBy(base::TimeDelta::FromMicroseconds(
kOfferDataExpiryTimeInMicros - kOneSecondMicros));
autofill_offer_manager_.Init(&autofill_client_, kTestAppLocale);
// Should not call GetOfferData because it hasn't been long enough since the
// last successful request.
EXPECT_EQ(payments_client_->get_offer_data_calls(), 0);
}
TEST_F(AutofillOfferManagerTest, InitAfterOfferDataExpiry_OneSecond) {
autofill_offer_manager_.last_updated_timestamp_ = AutofillClock::Now();
task_environment_.FastForwardBy(base::TimeDelta::FromMicroseconds(
kOfferDataExpiryTimeInMicros + kOneSecondMicros));
autofill_offer_manager_.Init(&autofill_client_, kTestAppLocale);
// Should call GetOfferData because it has been long enough since the last
// successful request.
EXPECT_EQ(payments_client_->get_offer_data_calls(), 1);
}
TEST_F(AutofillOfferManagerTest, InitBeforeTimerExpiry_OneSecond) {
payments_client_->SetShouldReturnOfferData(false);
autofill_offer_manager_.Init(&autofill_client_, kTestAppLocale);
EXPECT_EQ(payments_client_->get_offer_data_calls(), 1);
task_environment_.FastForwardBy(base::TimeDelta::FromMicroseconds(
kRequestExpiryTimeInMicros - kOneSecondMicros));
autofill_offer_manager_.Init(&autofill_client_, kTestAppLocale);
// Should not call GetOfferData a second time because even though the request
// has not returned, it also has not expired.
EXPECT_EQ(payments_client_->get_offer_data_calls(), 1);
}
TEST_F(AutofillOfferManagerTest, InitAfterTimerExpiry_OneSecond) {
payments_client_->SetShouldReturnOfferData(false);
autofill_offer_manager_.Init(&autofill_client_, kTestAppLocale);
EXPECT_EQ(payments_client_->get_offer_data_calls(), 1);
task_environment_.FastForwardBy(base::TimeDelta::FromMicroseconds(
kRequestExpiryTimeInMicros + kOneSecondMicros));
autofill_offer_manager_.Init(&autofill_client_, kTestAppLocale);
// Should call GetOfferData a second time because even though the request has
// not returned, it has expired.
EXPECT_EQ(payments_client_->get_offer_data_calls(), 2);
}
TEST_F(AutofillOfferManagerTest, InitAfterOfferDataExpiryButRequestActive) {
payments_client_->SetShouldReturnOfferData(false);
autofill_offer_manager_.last_updated_timestamp_ = AutofillClock::Now();
task_environment_.FastForwardBy(base::TimeDelta::FromMicroseconds(
kOfferDataExpiryTimeInMicros + kOneSecondMicros));
autofill_offer_manager_.Init(&autofill_client_, kTestAppLocale);
// Should call GetOfferData because the offer data has expired.
EXPECT_EQ(payments_client_->get_offer_data_calls(), 1);
task_environment_.FastForwardBy(base::TimeDelta::FromMicroseconds(
kRequestExpiryTimeInMicros - kOneSecondMicros));
autofill_offer_manager_.Init(&autofill_client_, kTestAppLocale);
// Should not call GetOfferData a second time because even though the request
// has not returned, it has not expired.
EXPECT_EQ(payments_client_->get_offer_data_calls(), 1);
}
} // namespace payments
} // namespace autofill
...@@ -25,8 +25,10 @@ ...@@ -25,8 +25,10 @@
#include "components/autofill/core/browser/autofill_experiments.h" #include "components/autofill/core/browser/autofill_experiments.h"
#include "components/autofill/core/browser/autofill_type.h" #include "components/autofill/core/browser/autofill_type.h"
#include "components/autofill/core/browser/data_model/autofill_data_model.h" #include "components/autofill/core/browser/data_model/autofill_data_model.h"
#include "components/autofill/core/browser/data_model/autofill_offer_data.h"
#include "components/autofill/core/browser/data_model/credit_card.h" #include "components/autofill/core/browser/data_model/credit_card.h"
#include "components/autofill/core/browser/payments/account_info_getter.h" #include "components/autofill/core/browser/payments/account_info_getter.h"
#include "components/autofill/core/browser/payments/autofill_offer_manager.h"
#include "components/autofill/core/browser/payments/local_card_migration_manager.h" #include "components/autofill/core/browser/payments/local_card_migration_manager.h"
#include "components/autofill/core/browser/payments/payments_request.h" #include "components/autofill/core/browser/payments/payments_request.h"
#include "components/autofill/core/browser/payments/payments_service_url.h" #include "components/autofill/core/browser/payments/payments_service_url.h"
...@@ -82,6 +84,9 @@ const char kMigrateCardsRequestPath[] = ...@@ -82,6 +84,9 @@ const char kMigrateCardsRequestPath[] =
const char kMigrateCardsRequestFormat[] = const char kMigrateCardsRequestFormat[] =
"requestContentType=application/json; charset=utf-8&request=%s"; "requestContentType=application/json; charset=utf-8&request=%s";
const char kGetOfferDataRequestPath[] =
"payments/apis/chromepaymentsservice/getoffers";
const char kTokenFetchId[] = "wallet_client"; const char kTokenFetchId[] = "wallet_client";
const char kPaymentsOAuth2Scope[] = const char kPaymentsOAuth2Scope[] =
"https://www.googleapis.com/auth/wallet.chrome"; "https://www.googleapis.com/auth/wallet.chrome";
...@@ -1008,6 +1013,109 @@ class MigrateCardsRequest : public PaymentsRequest { ...@@ -1008,6 +1013,109 @@ class MigrateCardsRequest : public PaymentsRequest {
DISALLOW_COPY_AND_ASSIGN(MigrateCardsRequest); DISALLOW_COPY_AND_ASSIGN(MigrateCardsRequest);
}; };
class GetOfferDataRequest : public PaymentsRequest {
public:
GetOfferDataRequest(
const std::string& app_locale,
base::OnceCallback<void(AutofillClient::PaymentsRpcResult,
const std::vector<AutofillOfferData>&)> callback)
: app_locale_(app_locale), callback_(std::move(callback)) {}
~GetOfferDataRequest() override = default;
GetOfferDataRequest(const GetOfferDataRequest& other) = delete;
GetOfferDataRequest& operator=(const GetOfferDataRequest& other) = delete;
std::string GetRequestUrlPath() override { return kGetOfferDataRequestPath; }
std::string GetRequestContentType() override { return "application/json"; }
std::string GetRequestContent() override {
base::Value request_dict(base::Value::Type::DICTIONARY);
base::Value context(base::Value::Type::DICTIONARY);
context.SetKey("language_code", base::Value(app_locale_));
request_dict.SetKey("context", std::move(context));
std::string request_content;
base::JSONWriter::Write(request_dict, &request_content);
VLOG(3) << "getoffers request body: " << request_content;
return request_content;
}
void ParseResponse(const base::Value& response) override {
const auto* found_list =
response.FindKeyOfType("offer", base::Value::Type::LIST);
if (!found_list)
return;
std::vector<AutofillOfferData> offers;
for (const base::Value& result : found_list->GetList()) {
AutofillOfferData offer_data;
if (!result.is_dict() || !JsonToAutofillOfferData(result, offer_data))
continue;
offers.push_back(offer_data);
}
offers_.emplace(offers);
}
bool IsResponseComplete() override { return offers_.has_value(); }
void RespondToDelegate(AutofillClient::PaymentsRpcResult result) override {
std::move(callback_).Run(result, std::move(offers_.value()));
}
private:
// Extract, validate, and assign all required fields.
bool JsonToAutofillOfferData(const base::Value& value,
AutofillOfferData& result) {
const std::string* offer_id = value.FindStringKey("offer_id");
if (!offer_id || offer_id->empty())
return false;
result.offer_id = *offer_id;
const std::string* name = value.FindStringKey("name");
if (!name || name->empty())
return false;
result.name = base::UTF8ToUTF16(*name);
const std::string* description = value.FindStringKey("description");
result.description =
description ? base::UTF8ToUTF16(*description) : base::string16();
const std::string* expiry = value.FindStringKey("expiry");
int64_t expiry_value;
if (!expiry || !base::StringToInt64(*expiry, &expiry_value))
return false;
result.expiry = expiry_value;
const std::string* merchant_domain = value.FindStringKey("merchant_domain");
if (!merchant_domain || !GURL(*merchant_domain).is_valid())
return false;
result.merchant_domain = GURL(*merchant_domain);
const auto* eligible_instrument_id =
value.FindKeyOfType("eligible_instrument_id", base::Value::Type::LIST);
if (eligible_instrument_id) {
for (const base::Value& id : eligible_instrument_id->GetList()) {
if (!id.GetString().empty()) {
result.eligible_instrument_id.push_back(id.GetString());
}
}
}
const auto* eligible_legacy_instrument_id = value.FindKeyOfType(
"eligible_legacy_instrument_id", base::Value::Type::LIST);
if (eligible_legacy_instrument_id) {
for (const base::Value& id : eligible_legacy_instrument_id->GetList()) {
if (!id.GetString().empty()) {
result.eligible_legacy_instrument_id.push_back(id.GetString());
}
}
}
return result.eligible_instrument_id.size() +
result.eligible_legacy_instrument_id.size() >
0;
}
const std::string app_locale_;
base::OnceCallback<void(AutofillClient::PaymentsRpcResult,
const std::vector<AutofillOfferData>&)>
callback_;
base::Optional<std::vector<AutofillOfferData>> offers_;
};
} // namespace } // namespace
const char PaymentsClient::kRecipientName[] = "recipient_name"; const char PaymentsClient::kRecipientName[] = "recipient_name";
...@@ -1200,6 +1308,15 @@ void PaymentsClient::MigrateCards( ...@@ -1200,6 +1308,15 @@ void PaymentsClient::MigrateCards(
/*authenticate=*/true); /*authenticate=*/true);
} }
void PaymentsClient::GetOfferData(
const std::string& app_locale,
base::OnceCallback<void(AutofillClient::PaymentsRpcResult,
const std::vector<AutofillOfferData>&)> callback) {
IssueRequest(
std::make_unique<GetOfferDataRequest>(app_locale, std::move(callback)),
/*authenticate=*/true);
}
void PaymentsClient::CancelRequest() { void PaymentsClient::CancelRequest() {
request_.reset(); request_.reset();
resource_request_.reset(); resource_request_.reset();
......
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
#include "base/memory/scoped_refptr.h" #include "base/memory/scoped_refptr.h"
#include "base/memory/weak_ptr.h" #include "base/memory/weak_ptr.h"
#include "components/autofill/core/browser/autofill_client.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/data_model/autofill_profile.h" #include "components/autofill/core/browser/data_model/autofill_profile.h"
#include "components/autofill/core/browser/data_model/credit_card.h" #include "components/autofill/core/browser/data_model/credit_card.h"
#include "components/autofill/core/browser/payments/card_unmask_delegate.h" #include "components/autofill/core/browser/payments/card_unmask_delegate.h"
...@@ -316,6 +317,12 @@ class PaymentsClient { ...@@ -316,6 +317,12 @@ class PaymentsClient {
const std::vector<MigratableCreditCard>& migratable_credit_cards, const std::vector<MigratableCreditCard>& migratable_credit_cards,
MigrateCardsCallback callback); MigrateCardsCallback callback);
// The user has opened a new tab and their offer data needs to be refreshed.
virtual void GetOfferData(
const std::string& app_locale,
base::OnceCallback<void(AutofillClient::PaymentsRpcResult,
const std::vector<AutofillOfferData>&)> callback);
// Cancels and clears the current |request_|. // Cancels and clears the current |request_|.
void CancelRequest(); void CancelRequest();
......
...@@ -91,6 +91,15 @@ void TestPaymentsClient::MigrateCards( ...@@ -91,6 +91,15 @@ void TestPaymentsClient::MigrateCards(
"this is display text"); "this is display text");
} }
void TestPaymentsClient::GetOfferData(
const std::string& app_locale,
base::OnceCallback<void(AutofillClient::PaymentsRpcResult,
const std::vector<AutofillOfferData>&)> callback) {
get_offer_data_calls_++;
if (should_return_offer_data_)
std::move(callback).Run(AutofillClient::SUCCESS, offers_);
}
void TestPaymentsClient::ShouldReturnUnmaskDetailsImmediately( void TestPaymentsClient::ShouldReturnUnmaskDetailsImmediately(
bool should_return_unmask_details) { bool should_return_unmask_details) {
should_return_unmask_details_ = should_return_unmask_details; should_return_unmask_details_ = should_return_unmask_details;
...@@ -190,5 +199,10 @@ std::unique_ptr<base::Value> TestPaymentsClient::LegalMessage() { ...@@ -190,5 +199,10 @@ std::unique_ptr<base::Value> TestPaymentsClient::LegalMessage() {
} }
} }
void TestPaymentsClient::SetShouldReturnOfferData(
bool should_return_offer_data) {
should_return_offer_data_ = should_return_offer_data;
}
} // namespace payments } // namespace payments
} // namespace autofill } // namespace autofill
...@@ -63,6 +63,12 @@ class TestPaymentsClient : public payments::PaymentsClient { ...@@ -63,6 +63,12 @@ class TestPaymentsClient : public payments::PaymentsClient {
const std::vector<MigratableCreditCard>& migratable_credit_cards, const std::vector<MigratableCreditCard>& migratable_credit_cards,
MigrateCardsCallback callback) override; MigrateCardsCallback callback) override;
void GetOfferData(
const std::string& app_locale,
base::OnceCallback<void(AutofillClient::PaymentsRpcResult,
const std::vector<AutofillOfferData>&)> callback)
override;
// Some metrics are affected by the latency of GetUnmaskDetails, so it is // Some metrics are affected by the latency of GetUnmaskDetails, so it is
// useful to control whether or not GetUnmaskDetails() is responded to. // useful to control whether or not GetUnmaskDetails() is responded to.
void ShouldReturnUnmaskDetailsImmediately(bool should_return_unmask_details); void ShouldReturnUnmaskDetailsImmediately(bool should_return_unmask_details);
...@@ -84,6 +90,8 @@ class TestPaymentsClient : public payments::PaymentsClient { ...@@ -84,6 +90,8 @@ class TestPaymentsClient : public payments::PaymentsClient {
void SetUseInvalidLegalMessageInGetUploadDetails( void SetUseInvalidLegalMessageInGetUploadDetails(
bool use_invalid_legal_message); bool use_invalid_legal_message);
void SetShouldReturnOfferData(bool should_return_offer_data);
payments::PaymentsClient::UnmaskDetails* unmask_details() { payments::PaymentsClient::UnmaskDetails* unmask_details() {
return &unmask_details_; return &unmask_details_;
} }
...@@ -106,6 +114,7 @@ class TestPaymentsClient : public payments::PaymentsClient { ...@@ -106,6 +114,7 @@ class TestPaymentsClient : public payments::PaymentsClient {
PaymentsClient::UploadCardSource upload_card_source_in_request() const { PaymentsClient::UploadCardSource upload_card_source_in_request() const {
return upload_card_source_; return upload_card_source_;
} }
int get_offer_data_calls() const { return get_offer_data_calls_; }
private: private:
std::string server_id_; std::string server_id_;
...@@ -126,6 +135,9 @@ class TestPaymentsClient : public payments::PaymentsClient { ...@@ -126,6 +135,9 @@ class TestPaymentsClient : public payments::PaymentsClient {
std::unique_ptr<std::unordered_map<std::string, std::string>> save_result_; std::unique_ptr<std::unordered_map<std::string, std::string>> save_result_;
bool use_invalid_legal_message_ = false; bool use_invalid_legal_message_ = false;
std::unique_ptr<base::Value> LegalMessage(); std::unique_ptr<base::Value> LegalMessage();
std::vector<AutofillOfferData> offers_;
int get_offer_data_calls_ = 0;
bool should_return_offer_data_ = true;
DISALLOW_COPY_AND_ASSIGN(TestPaymentsClient); DISALLOW_COPY_AND_ASSIGN(TestPaymentsClient);
}; };
......
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