Remove user_annotations component
It is no longer used. The metrics deletions are intentional. Since this feature was never launched, we do not want to obsolete the metrics - they should just be deleted. Bug: 395040395 Change-Id: I1a59181eca10758939439dd7ff94829a91712de8 No-Presubmit: true Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6308728 Reviewed-by: Devlin Cronin <rdevlin.cronin@chromium.org> Reviewed-by: Colin Blundell <blundell@chromium.org> Reviewed-by: Sophie Chang <sophiechang@chromium.org> Reviewed-by: Sylvain Defresne <sdefresne@chromium.org> Reviewed-by: Martin Šrámek <msramek@chromium.org> Commit-Queue: Jan Keitel <jkeitel@google.com> Reviewed-by: Alexei Svitkine <asvitkine@chromium.org> Reviewed-by: Christoph Schwering <schwering@google.com> Cr-Commit-Position: refs/heads/main@{#1427119}
This commit is contained in:

committed by
Chromium LUCI CQ

parent
eb3610c473
commit
485f65af53
chrome
browser
BUILD.gnDEPS
autofill_ai
browsing_data
extensions
api
autofill_private
profiles
BUILD.gnchrome_browser_main_extra_parts_profiles.ccprofile_statistics.ccprofile_statistics.hprofile_statistics_aggregator.ccprofile_statistics_aggregator.hprofile_statistics_aggregator_unittest.ccprofile_statistics_factory.cc
ui
BUILD.gn
autofill
user_annotations
test
components
BUILD.gn
autofill
autofill_ai
core
browsing_data
core
user_annotations
BUILD.gnDEPSDIR_METADATAOWNERSform_submission_handler.ccform_submission_handler.htest_user_annotations_service.cctest_user_annotations_service.huser_annotations_database.ccuser_annotations_database.huser_annotations_database_unittest.ccuser_annotations_features.ccuser_annotations_features.huser_annotations_features_unittest.ccuser_annotations_service.ccuser_annotations_service.huser_annotations_service_unittest.ccuser_annotations_switches.ccuser_annotations_switches.huser_annotations_switches_unittest.ccuser_annotations_types.ccuser_annotations_types.h
extensions
ios/chrome/browser
browsing_data
settings
ui_bundled
clear_browsing_data
tools/metrics/histograms
@ -2392,7 +2392,6 @@ static_library("browser") {
|
||||
"//components/url_formatter/spoof_checks/top_domains:top_bucket_domains",
|
||||
"//components/url_formatter/spoof_checks/top_domains:top_bucket_domains_header",
|
||||
"//components/url_matcher",
|
||||
"//components/user_annotations",
|
||||
"//components/user_manager",
|
||||
"//components/user_prefs",
|
||||
"//components/variations",
|
||||
@ -4324,7 +4323,6 @@ static_library("browser") {
|
||||
"//chrome/browser/ui/webui/whats_new",
|
||||
"//chrome/browser/ui/webui/whats_new:impl",
|
||||
"//chrome/browser/upgrade_detector:build_state_observer",
|
||||
"//chrome/browser/user_annotations",
|
||||
"//chrome/browser/web_applications",
|
||||
"//chrome/browser/web_applications:features",
|
||||
"//chrome/browser/web_applications:web_applications_metrics",
|
||||
@ -4407,9 +4405,6 @@ static_library("browser") {
|
||||
# TODO(crbug.com/366172297): Remove circular dependencies.
|
||||
"//chrome/browser/autofill_ai:util",
|
||||
|
||||
# TODO(crbug.com/366172297): Remove circular dependencies.
|
||||
"//chrome/browser/user_annotations",
|
||||
|
||||
# TODO(b/220386256): Remove circular dependency from the browser.
|
||||
"//chrome/browser/media/router/discovery/access_code:access_code_sink_service",
|
||||
"//chrome/browser/media/router:mojo_impl",
|
||||
|
@ -399,7 +399,6 @@ include_rules = [
|
||||
"+components/upload_list",
|
||||
"+components/url_matcher",
|
||||
"+components/url_pattern_index/proto",
|
||||
"+components/user_annotations",
|
||||
"+components/user_education",
|
||||
"+components/user_manager",
|
||||
"+components/user_prefs",
|
||||
|
@ -14,7 +14,6 @@
|
||||
#include "chrome/browser/optimization_guide/mock_optimization_guide_keyed_service.h"
|
||||
#include "chrome/browser/optimization_guide/optimization_guide_keyed_service_factory.h"
|
||||
#include "chrome/browser/signin/identity_manager_factory.h"
|
||||
#include "chrome/browser/user_annotations/user_annotations_service_factory.h"
|
||||
#include "chrome/test/base/chrome_render_view_host_test_harness.h"
|
||||
#include "chrome/test/base/testing_profile.h"
|
||||
#include "components/autofill/core/browser/data_manager/autofill_ai/entity_data_manager.h"
|
||||
@ -35,7 +34,6 @@
|
||||
#include "components/signin/public/identity_manager/account_capabilities_test_mutator.h"
|
||||
#include "components/signin/public/identity_manager/identity_test_utils.h"
|
||||
#include "components/sync_preferences/testing_pref_service_syncable.h"
|
||||
#include "components/user_annotations/test_user_annotations_service.h"
|
||||
#include "content/public/browser/browser_context.h"
|
||||
#include "content/public/test/web_contents_tester.h"
|
||||
#include "testing/gmock/include/gmock/gmock.h"
|
||||
@ -52,11 +50,6 @@ std::unique_ptr<KeyedService> CreateOptimizationGuideKeyedService(
|
||||
return std::make_unique<NiceMock<MockOptimizationGuideKeyedService>>();
|
||||
}
|
||||
|
||||
std::unique_ptr<KeyedService> CreateUserAnnotationsServiceFactory(
|
||||
content::BrowserContext* context) {
|
||||
return std::make_unique<user_annotations::TestUserAnnotationsService>();
|
||||
}
|
||||
|
||||
std::unique_ptr<KeyedService> CreateTestPersonalDataManager(
|
||||
content::BrowserContext* context) {
|
||||
return std::make_unique<autofill::TestPersonalDataManager>();
|
||||
@ -92,9 +85,6 @@ class ChromeAutofillAiClientTest : public ChromeRenderViewHostTestHarness {
|
||||
return {TestingProfile::TestingFactory{
|
||||
OptimizationGuideKeyedServiceFactory::GetInstance(),
|
||||
base::BindRepeating(&CreateOptimizationGuideKeyedService)},
|
||||
TestingProfile::TestingFactory{
|
||||
UserAnnotationsServiceFactory::GetInstance(),
|
||||
base::BindRepeating(&CreateUserAnnotationsServiceFactory)},
|
||||
TestingProfile::TestingFactory{
|
||||
autofill::PersonalDataManagerFactory::GetInstance(),
|
||||
base::BindRepeating(&CreateTestPersonalDataManager)},
|
||||
|
@ -185,14 +185,12 @@
|
||||
#if !BUILDFLAG(IS_ANDROID)
|
||||
#include "chrome/browser/new_tab_page/microsoft_auth/microsoft_auth_service.h"
|
||||
#include "chrome/browser/new_tab_page/microsoft_auth/microsoft_auth_service_factory.h"
|
||||
#include "chrome/browser/user_annotations/user_annotations_service_factory.h"
|
||||
#include "chrome/browser/user_education/browser_user_education_storage_service.h"
|
||||
#include "chrome/browser/web_applications/web_app.h"
|
||||
#include "chrome/browser/web_applications/web_app_command_scheduler.h"
|
||||
#include "chrome/browser/web_applications/web_app_provider.h"
|
||||
#include "chrome/browser/web_applications/web_app_registrar.h"
|
||||
#include "chrome/browser/web_applications/web_app_utils.h"
|
||||
#include "components/user_annotations/user_annotations_service.h"
|
||||
#include "content/public/browser/isolated_web_apps_policy.h"
|
||||
#include "content/public/browser/storage_partition_config.h"
|
||||
#endif // !BUILDFLAG(IS_ANDROID)
|
||||
@ -1104,13 +1102,6 @@ void ChromeBrowsingDataRemoverDelegate::RemoveEmbedderData(
|
||||
FROM_HERE, base::DoNothing(),
|
||||
CreateTaskCompletionClosure(TracingDataType::kAutofillData));
|
||||
}
|
||||
#if !BUILDFLAG(IS_ANDROID)
|
||||
if (auto* user_annotations_service =
|
||||
UserAnnotationsServiceFactory::GetForProfile(profile_)) {
|
||||
user_annotations_service->RemoveAnnotationsInRange(delete_begin_,
|
||||
delete_end_);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -83,7 +83,6 @@
|
||||
#include "chrome/browser/tpcd/metadata/manager_factory.h"
|
||||
#include "chrome/browser/translate/chrome_translate_client.h"
|
||||
#include "chrome/browser/trusted_vault/trusted_vault_service_factory.h"
|
||||
#include "chrome/browser/user_annotations/user_annotations_service_factory.h"
|
||||
#include "chrome/browser/webdata_services/web_data_service_factory.h"
|
||||
#include "chrome/browser/webid/federated_identity_permission_context.h"
|
||||
#include "chrome/common/chrome_constants.h"
|
||||
@ -166,7 +165,6 @@
|
||||
#include "components/tpcd/metadata/browser/prefs.h"
|
||||
#include "components/tpcd/metadata/browser/test_support.h"
|
||||
#include "components/ukm/test_ukm_recorder.h"
|
||||
#include "components/user_annotations/test_user_annotations_service.h"
|
||||
#include "content/public/browser/background_tracing_manager.h"
|
||||
#include "content/public/browser/browser_context.h"
|
||||
#include "content/public/browser/browser_thread.h"
|
||||
@ -2526,51 +2524,6 @@ TEST_F(ChromeBrowsingDataRemoverDelegateTest,
|
||||
ASSERT_FALSE(tester.HasProfileAndCard());
|
||||
}
|
||||
|
||||
#if !BUILDFLAG(IS_ANDROID)
|
||||
class ChromeBrowsingDataRemoverDelegateUserAnnotationsTest
|
||||
: public ChromeBrowsingDataRemoverDelegateTest {
|
||||
public:
|
||||
static std::unique_ptr<KeyedService> CreateUserAnnotationsServiceFactory(
|
||||
content::BrowserContext* context) {
|
||||
return std::make_unique<user_annotations::TestUserAnnotationsService>();
|
||||
}
|
||||
|
||||
void SetUp() override { ChromeBrowsingDataRemoverDelegateTest::SetUp(); }
|
||||
|
||||
TestingProfile::TestingFactories GetTestingFactories() override {
|
||||
TestingProfile::TestingFactories factories =
|
||||
ChromeBrowsingDataRemoverDelegateTest::GetTestingFactories();
|
||||
factories.emplace_back(
|
||||
UserAnnotationsServiceFactory::GetInstance(),
|
||||
base::BindRepeating(&CreateUserAnnotationsServiceFactory));
|
||||
return factories;
|
||||
}
|
||||
|
||||
user_annotations::TestUserAnnotationsService* service() {
|
||||
// Overridden in GetTestingFactories().
|
||||
return static_cast<user_annotations::TestUserAnnotationsService*>(
|
||||
UserAnnotationsServiceFactory::GetForProfile(GetProfile()));
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(ChromeBrowsingDataRemoverDelegateUserAnnotationsTest,
|
||||
UserAnnotationsOnAutofillRemoveRange) {
|
||||
auto time_now = base::Time::Now();
|
||||
BlockUntilBrowsingDataRemoved(time_now, time_now + base::Hours(1),
|
||||
constants::DATA_TYPE_FORM_DATA, false);
|
||||
|
||||
// UserAnnotations should be empty when DATA_TYPE_FORM_DATA browsing data
|
||||
// gets deleted.
|
||||
EXPECT_EQ(constants::DATA_TYPE_FORM_DATA, GetRemovalMask());
|
||||
EXPECT_EQ(content::BrowsingDataRemover::ORIGIN_TYPE_UNPROTECTED_WEB,
|
||||
GetOriginTypeMask());
|
||||
|
||||
EXPECT_THAT(service()->last_received_remove_annotations_in_range(),
|
||||
testing::Pair(testing::Eq(time_now),
|
||||
testing::Eq(time_now + base::Hours(1))));
|
||||
}
|
||||
#endif
|
||||
|
||||
TEST_F(ChromeBrowsingDataRemoverDelegateTest, ZeroSuggestPrefsBasedCacheClear) {
|
||||
// Disable in-memory ZPS caching.
|
||||
base::test::ScopedFeatureList features;
|
||||
|
@ -21,7 +21,6 @@
|
||||
#include "chrome/browser/autofill/personal_data_manager_factory.h"
|
||||
#include "chrome/browser/profiles/profile.h"
|
||||
#include "chrome/browser/ui/browser.h"
|
||||
#include "chrome/browser/user_annotations/user_annotations_service_factory.h"
|
||||
#include "chrome/browser/webdata_services/web_data_service_factory.h"
|
||||
#include "chrome/test/base/in_process_browser_test.h"
|
||||
#include "components/autofill/core/browser/autofill_type.h"
|
||||
@ -37,9 +36,6 @@
|
||||
#include "components/browsing_data/core/browsing_data_utils.h"
|
||||
#include "components/browsing_data/core/pref_names.h"
|
||||
#include "components/prefs/pref_service.h"
|
||||
#include "components/user_annotations/test_user_annotations_service.h"
|
||||
#include "components/user_annotations/user_annotations_service.h"
|
||||
#include "components/user_annotations/user_annotations_types.h"
|
||||
#include "content/public/test/browser_test.h"
|
||||
|
||||
namespace {
|
||||
@ -63,8 +59,6 @@ class AutofillCounterTest : public InProcessBrowserTest {
|
||||
browser()->profile());
|
||||
web_data_service_ = WebDataServiceFactory::GetAutofillWebDataForProfile(
|
||||
browser()->profile(), ServiceAccessType::IMPLICIT_ACCESS);
|
||||
user_annotations_service_ =
|
||||
std::make_unique<user_annotations::TestUserAnnotationsService>();
|
||||
|
||||
SetAutofillDeletionPref(true);
|
||||
SetDeletionPeriodPref(browsing_data::TimePeriod::ALL_TIME);
|
||||
@ -148,12 +142,6 @@ class AutofillCounterTest : public InProcessBrowserTest {
|
||||
address_ids_.pop_back();
|
||||
}
|
||||
|
||||
// User annotations ----------------------------------------------------------
|
||||
|
||||
void SetUserAnnotations(user_annotations::UserAnnotationsEntries entries) {
|
||||
user_annotations_service_->ReplaceAllEntries(std::move(entries));
|
||||
}
|
||||
|
||||
// Other autofill utils ------------------------------------------------------
|
||||
|
||||
void ClearCreditCardsAndAddresses() {
|
||||
@ -185,11 +173,6 @@ class AutofillCounterTest : public InProcessBrowserTest {
|
||||
return web_data_service_;
|
||||
}
|
||||
|
||||
raw_ptr<user_annotations::TestUserAnnotationsService>
|
||||
GetUserAnnotationsService() {
|
||||
return user_annotations_service_.get();
|
||||
}
|
||||
|
||||
// Result retrieval ---------------------------------------------
|
||||
|
||||
browsing_data::BrowsingDataCounter::ResultInt GetNumSuggestions() {
|
||||
@ -204,10 +187,6 @@ class AutofillCounterTest : public InProcessBrowserTest {
|
||||
return num_addresses_;
|
||||
}
|
||||
|
||||
browsing_data::BrowsingDataCounter::ResultInt GetNumUserAnnotations() {
|
||||
return num_user_annotations_;
|
||||
}
|
||||
|
||||
browsing_data::AutofillCounter::ResultInt GetCounterValue() {
|
||||
return counter_value_;
|
||||
}
|
||||
@ -225,7 +204,6 @@ class AutofillCounterTest : public InProcessBrowserTest {
|
||||
counter_value_ = autofill_result->Value();
|
||||
num_credit_cards_ = autofill_result->num_credit_cards();
|
||||
num_addresses_ = autofill_result->num_addresses();
|
||||
num_user_annotations_ = autofill_result->num_user_annotation_entries();
|
||||
}
|
||||
|
||||
protected:
|
||||
@ -240,22 +218,18 @@ class AutofillCounterTest : public InProcessBrowserTest {
|
||||
|
||||
raw_ptr<autofill::PersonalDataManager> personal_data_manager_;
|
||||
scoped_refptr<autofill::AutofillWebDataService> web_data_service_;
|
||||
std::unique_ptr<user_annotations::TestUserAnnotationsService>
|
||||
user_annotations_service_;
|
||||
|
||||
browsing_data::BrowsingDataCounter::ResultInt counter_value_;
|
||||
browsing_data::BrowsingDataCounter::ResultInt num_suggestions_;
|
||||
browsing_data::BrowsingDataCounter::ResultInt num_credit_cards_;
|
||||
browsing_data::BrowsingDataCounter::ResultInt num_addresses_;
|
||||
browsing_data::BrowsingDataCounter::ResultInt num_user_annotations_;
|
||||
};
|
||||
|
||||
// Tests that we count the correct number of autocomplete suggestions.
|
||||
IN_PROC_BROWSER_TEST_F(AutofillCounterTest, AutocompleteSuggestions) {
|
||||
Profile* profile = browser()->profile();
|
||||
browsing_data::AutofillCounter counter(
|
||||
GetPersonalDataManager(), GetWebDataService(),
|
||||
/*user_annotations_service=*/nullptr, /*sync_service=*/nullptr);
|
||||
GetPersonalDataManager(), GetWebDataService(), /*sync_service=*/nullptr);
|
||||
|
||||
counter.Init(profile->GetPrefs(),
|
||||
browsing_data::ClearBrowsingDataTab::ADVANCED,
|
||||
@ -294,8 +268,7 @@ IN_PROC_BROWSER_TEST_F(AutofillCounterTest, AutocompleteSuggestions) {
|
||||
IN_PROC_BROWSER_TEST_F(AutofillCounterTest, CreditCards) {
|
||||
Profile* profile = browser()->profile();
|
||||
browsing_data::AutofillCounter counter(
|
||||
GetPersonalDataManager(), GetWebDataService(),
|
||||
/*user_annotations_service=*/nullptr, /*sync_service=*/nullptr);
|
||||
GetPersonalDataManager(), GetWebDataService(), /*sync_service=*/nullptr);
|
||||
|
||||
counter.Init(profile->GetPrefs(),
|
||||
browsing_data::ClearBrowsingDataTab::ADVANCED,
|
||||
@ -340,8 +313,7 @@ IN_PROC_BROWSER_TEST_F(AutofillCounterTest, CreditCards) {
|
||||
IN_PROC_BROWSER_TEST_F(AutofillCounterTest, Addresses) {
|
||||
Profile* profile = browser()->profile();
|
||||
browsing_data::AutofillCounter counter(
|
||||
GetPersonalDataManager(), GetWebDataService(),
|
||||
/*user_annotations_service=*/nullptr, /*sync_service=*/nullptr);
|
||||
GetPersonalDataManager(), GetWebDataService(), /*sync_service=*/nullptr);
|
||||
|
||||
counter.Init(profile->GetPrefs(),
|
||||
browsing_data::ClearBrowsingDataTab::ADVANCED,
|
||||
@ -382,26 +354,6 @@ IN_PROC_BROWSER_TEST_F(AutofillCounterTest, Addresses) {
|
||||
EXPECT_EQ(0, GetNumAddresses());
|
||||
}
|
||||
|
||||
// Tests that we count the correct number of user annotations.
|
||||
IN_PROC_BROWSER_TEST_F(AutofillCounterTest, UserAnnotations) {
|
||||
Profile* profile = browser()->profile();
|
||||
browsing_data::AutofillCounter counter(
|
||||
GetPersonalDataManager(), GetWebDataService(),
|
||||
GetUserAnnotationsService(), /*sync_service=*/nullptr);
|
||||
counter.Init(profile->GetPrefs(),
|
||||
browsing_data::ClearBrowsingDataTab::ADVANCED,
|
||||
future.GetRepeatingCallback());
|
||||
counter.Restart();
|
||||
WaitForResult();
|
||||
EXPECT_EQ(0, GetNumUserAnnotations());
|
||||
|
||||
SetUserAnnotations(
|
||||
std::vector(10, optimization_guide::proto::UserAnnotationsEntry{}));
|
||||
counter.Restart();
|
||||
WaitForResult();
|
||||
EXPECT_EQ(10, GetNumUserAnnotations());
|
||||
}
|
||||
|
||||
// Tests that we return the correct complex result when counting more than
|
||||
// one type of items.
|
||||
IN_PROC_BROWSER_TEST_F(AutofillCounterTest, ComplexResult) {
|
||||
@ -420,8 +372,7 @@ IN_PROC_BROWSER_TEST_F(AutofillCounterTest, ComplexResult) {
|
||||
|
||||
Profile* profile = browser()->profile();
|
||||
browsing_data::AutofillCounter counter(
|
||||
GetPersonalDataManager(), GetWebDataService(),
|
||||
/*user_annotations_service=*/nullptr, /*sync_service=*/nullptr);
|
||||
GetPersonalDataManager(), GetWebDataService(), /*sync_service=*/nullptr);
|
||||
|
||||
counter.Init(profile->GetPrefs(),
|
||||
browsing_data::ClearBrowsingDataTab::ADVANCED,
|
||||
@ -466,20 +417,17 @@ IN_PROC_BROWSER_TEST_F(AutofillCounterTest, TimeRanges) {
|
||||
const browsing_data::BrowsingDataCounter::ResultInt
|
||||
expected_num_credit_cards;
|
||||
const browsing_data::BrowsingDataCounter::ResultInt expected_num_addresses;
|
||||
const browsing_data::BrowsingDataCounter::ResultInt
|
||||
expected_num_user_annotations;
|
||||
};
|
||||
auto test_cases = std::to_array<TestCase>({
|
||||
{base::Time(), 2, 3, 3, 0},
|
||||
{kTime1, 2, 3, 3, 0},
|
||||
{kTime2, 1, 2, 2, 0},
|
||||
{kTime3, 1, 1, 0, 0},
|
||||
{base::Time(), 2, 3, 3},
|
||||
{kTime1, 2, 3, 3},
|
||||
{kTime2, 1, 2, 2},
|
||||
{kTime3, 1, 1, 0},
|
||||
});
|
||||
|
||||
Profile* profile = browser()->profile();
|
||||
browsing_data::AutofillCounter counter(
|
||||
GetPersonalDataManager(), GetWebDataService(),
|
||||
/*user_annotations_service=*/nullptr, /*sync_service=*/nullptr);
|
||||
GetPersonalDataManager(), GetWebDataService(), /*sync_service=*/nullptr);
|
||||
|
||||
counter.Init(profile->GetPrefs(),
|
||||
browsing_data::ClearBrowsingDataTab::ADVANCED,
|
||||
@ -496,7 +444,6 @@ IN_PROC_BROWSER_TEST_F(AutofillCounterTest, TimeRanges) {
|
||||
EXPECT_EQ(test_case.expected_num_suggestions, GetCounterValue());
|
||||
EXPECT_EQ(test_case.expected_num_credit_cards, GetNumCreditCards());
|
||||
EXPECT_EQ(test_case.expected_num_addresses, GetNumAddresses());
|
||||
EXPECT_EQ(test_case.expected_num_user_annotations, GetNumUserAnnotations());
|
||||
future.Clear();
|
||||
}
|
||||
|
||||
@ -509,7 +456,6 @@ IN_PROC_BROWSER_TEST_F(AutofillCounterTest, TimeRanges) {
|
||||
EXPECT_EQ(1, GetCounterValue());
|
||||
EXPECT_EQ(1, GetNumCreditCards());
|
||||
EXPECT_EQ(1, GetNumAddresses());
|
||||
EXPECT_EQ(0, GetNumUserAnnotations());
|
||||
|
||||
counter.SetPeriodEndForTesting(kTime3);
|
||||
counter.Restart();
|
||||
@ -519,7 +465,6 @@ IN_PROC_BROWSER_TEST_F(AutofillCounterTest, TimeRanges) {
|
||||
EXPECT_EQ(1, GetCounterValue());
|
||||
EXPECT_EQ(2, GetNumCreditCards());
|
||||
EXPECT_EQ(3, GetNumAddresses());
|
||||
EXPECT_EQ(0, GetNumUserAnnotations());
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
@ -39,7 +39,6 @@
|
||||
#endif
|
||||
|
||||
#if !BUILDFLAG(IS_ANDROID)
|
||||
#include "chrome/browser/user_annotations/user_annotations_service_factory.h"
|
||||
#include "content/public/browser/host_zoom_map.h"
|
||||
#else
|
||||
#include "chrome/browser/browsing_data/counters/tabs_counter.h"
|
||||
@ -109,11 +108,6 @@ BrowsingDataCounterFactory::GetForProfileAndPref(Profile* profile,
|
||||
autofill::PersonalDataManagerFactory::GetForBrowserContext(profile),
|
||||
WebDataServiceFactory::GetAutofillWebDataForProfile(
|
||||
profile, ServiceAccessType::EXPLICIT_ACCESS),
|
||||
#if !BUILDFLAG(IS_ANDROID)
|
||||
UserAnnotationsServiceFactory::GetForProfile(profile),
|
||||
#else
|
||||
/*user_annotations_service=*/nullptr,
|
||||
#endif
|
||||
SyncServiceFactory::GetForProfile(profile));
|
||||
}
|
||||
|
||||
|
@ -113,7 +113,7 @@ IN_PROC_BROWSER_TEST_F(SyncAwareCounterTest, AutofillCounter) {
|
||||
autofill::PersonalDataManagerFactory::GetForBrowserContext(profile),
|
||||
WebDataServiceFactory::GetAutofillWebDataForProfile(
|
||||
profile, ServiceAccessType::IMPLICIT_ACCESS),
|
||||
/*user_annotations_service=*/nullptr, sync_service);
|
||||
sync_service);
|
||||
|
||||
counter.Init(profile->GetPrefs(),
|
||||
browsing_data::ClearBrowsingDataTab::ADVANCED,
|
||||
|
@ -33,7 +33,6 @@ source_set("autofill_private") {
|
||||
"//chrome/browser/search_engines:search_engines",
|
||||
"//chrome/browser/sync:sync",
|
||||
"//chrome/browser/ui/user_education",
|
||||
"//chrome/browser/user_annotations",
|
||||
"//chrome/common/extensions/api:api",
|
||||
"//components/autofill/content/browser",
|
||||
"//components/autofill/core/browser",
|
||||
@ -44,7 +43,6 @@ source_set("autofill_private") {
|
||||
"//components/strings:components_branded_strings_grit",
|
||||
"//components/strings:components_strings_grit",
|
||||
"//components/sync/service:service",
|
||||
"//components/user_annotations",
|
||||
"//extensions/browser:browser",
|
||||
"//skia",
|
||||
"//third_party/libaddressinput:util",
|
||||
|
@ -6,7 +6,6 @@
|
||||
#define CHROME_BROWSER_EXTENSIONS_API_AUTOFILL_PRIVATE_AUTOFILL_PRIVATE_API_H_
|
||||
|
||||
#include "components/prefs/pref_service.h"
|
||||
#include "components/user_annotations/user_annotations_types.h"
|
||||
#include "extensions/browser/extension_function.h"
|
||||
#include "extensions/browser/extension_function_histogram_value.h"
|
||||
|
||||
|
@ -122,7 +122,6 @@ source_set("profile_util") {
|
||||
"//components/enterprise/common/proto:upload_request_response",
|
||||
"//components/keyed_service/core",
|
||||
"//components/password_manager/core/browser/password_store:password_store_interface",
|
||||
"//components/user_annotations:user_annotations",
|
||||
"//device/fido:fido",
|
||||
"//mojo/public/cpp/bindings",
|
||||
"//services/preferences/public/mojom",
|
||||
@ -195,10 +194,7 @@ source_set("profile_util_impl") {
|
||||
]
|
||||
|
||||
if (!is_android) {
|
||||
deps += [
|
||||
"//chrome/browser/ui:browser_list",
|
||||
"//chrome/browser/user_annotations:user_annotations",
|
||||
]
|
||||
deps += [ "//chrome/browser/ui:browser_list" ]
|
||||
}
|
||||
|
||||
if (is_chromeos) {
|
||||
@ -316,7 +312,6 @@ source_set("profiles_extra_parts_impl") {
|
||||
"//chrome/browser/ui/views/side_panel",
|
||||
"//chrome/browser/ui/webui/signin",
|
||||
"//chrome/browser/ui/webui/signin:login",
|
||||
"//chrome/browser/user_annotations",
|
||||
]
|
||||
}
|
||||
|
||||
|
@ -221,7 +221,6 @@
|
||||
#include "chrome/browser/unified_consent/unified_consent_service_factory.h"
|
||||
#include "chrome/browser/updates/announcement_notification/announcement_notification_service_factory.h"
|
||||
#include "chrome/browser/usb/usb_chooser_context_factory.h"
|
||||
#include "chrome/browser/user_annotations/user_annotations_service_factory.h"
|
||||
#include "chrome/browser/visited_url_ranking/visited_url_ranking_service_factory.h"
|
||||
#include "chrome/browser/webauthn/enclave_manager_factory.h"
|
||||
#include "chrome/browser/webdata_services/web_data_service_factory.h"
|
||||
@ -1339,7 +1338,6 @@ void ChromeBrowserMainExtraPartsProfiles::
|
||||
UsbChooserContextFactory::GetInstance();
|
||||
#if !BUILDFLAG(IS_ANDROID)
|
||||
UsbConnectionTrackerFactory::GetInstance();
|
||||
UserAnnotationsServiceFactory::GetInstance();
|
||||
UserEducationServiceFactory::GetInstance();
|
||||
#endif
|
||||
#if BUILDFLAG(ENABLE_EXTENSIONS)
|
||||
|
@ -16,7 +16,6 @@ ProfileStatistics::ProfileStatistics(
|
||||
scoped_refptr<password_manager::PasswordStoreInterface>
|
||||
profile_password_store,
|
||||
PrefService* pref_service,
|
||||
user_annotations::UserAnnotationsService* user_annotations_service,
|
||||
std::unique_ptr<device::fido::PlatformCredentialStore>
|
||||
platform_credential_store)
|
||||
: autofill_web_data_service_(std::move(autofill_web_data_service)),
|
||||
@ -25,7 +24,6 @@ ProfileStatistics::ProfileStatistics(
|
||||
history_service_(history_service),
|
||||
profile_password_store_(profile_password_store),
|
||||
pref_service_(pref_service),
|
||||
user_annotations_service_(user_annotations_service),
|
||||
platform_credential_store_(std::move(platform_credential_store)),
|
||||
aggregator_(nullptr) {}
|
||||
|
||||
@ -37,7 +35,7 @@ void ProfileStatistics::GatherStatistics(
|
||||
aggregator_ = std::make_unique<ProfileStatisticsAggregator>(
|
||||
autofill_web_data_service_, personal_data_manager_, bookmark_model_,
|
||||
history_service_, profile_password_store_, pref_service_,
|
||||
user_annotations_service_, std::move(platform_credential_store_),
|
||||
std::move(platform_credential_store_),
|
||||
base::BindOnce(&ProfileStatistics::DeregisterAggregator,
|
||||
weak_ptr_factory_.GetWeakPtr()));
|
||||
}
|
||||
|
@ -13,7 +13,6 @@
|
||||
#include "components/autofill/core/browser/webdata/autofill_webdata_service.h"
|
||||
#include "components/keyed_service/core/keyed_service.h"
|
||||
#include "components/password_manager/core/browser/password_store/password_store_interface.h"
|
||||
#include "components/user_annotations/user_annotations_service.h"
|
||||
#include "device/fido/platform_credential_store.h"
|
||||
|
||||
class PrefService;
|
||||
@ -45,7 +44,6 @@ class ProfileStatistics : public KeyedService {
|
||||
scoped_refptr<password_manager::PasswordStoreInterface>
|
||||
profile_password_store,
|
||||
PrefService* pref_service,
|
||||
user_annotations::UserAnnotationsService* user_annotations_service,
|
||||
std::unique_ptr<device::fido::PlatformCredentialStore>
|
||||
platform_credential_store);
|
||||
~ProfileStatistics() override;
|
||||
@ -69,8 +67,6 @@ class ProfileStatistics : public KeyedService {
|
||||
const scoped_refptr<password_manager::PasswordStoreInterface>
|
||||
profile_password_store_;
|
||||
const raw_ptr<PrefService> pref_service_;
|
||||
const raw_ptr<user_annotations::UserAnnotationsService>
|
||||
user_annotations_service_;
|
||||
|
||||
std::unique_ptr<device::fido::PlatformCredentialStore>
|
||||
platform_credential_store_;
|
||||
|
@ -26,7 +26,6 @@ ProfileStatisticsAggregator::ProfileStatisticsAggregator(
|
||||
scoped_refptr<password_manager::PasswordStoreInterface>
|
||||
profile_password_store,
|
||||
PrefService* pref_service,
|
||||
user_annotations::UserAnnotationsService* user_annotations_service,
|
||||
std::unique_ptr<device::fido::PlatformCredentialStore>
|
||||
platform_credential_store,
|
||||
base::OnceClosure done_callback)
|
||||
@ -36,7 +35,6 @@ ProfileStatisticsAggregator::ProfileStatisticsAggregator(
|
||||
history_service_(history_service),
|
||||
profile_password_store_(profile_password_store),
|
||||
pref_service_(pref_service),
|
||||
user_annotations_service_(user_annotations_service),
|
||||
platform_credential_store_(std::move(platform_credential_store)),
|
||||
done_callback_(std::move(done_callback)) {}
|
||||
|
||||
@ -84,7 +82,6 @@ void ProfileStatisticsAggregator::StartAggregator() {
|
||||
// Initiate autofill counting.
|
||||
AddCounter(std::make_unique<browsing_data::AutofillCounter>(
|
||||
personal_data_manager_, autofill_web_data_service_,
|
||||
user_annotations_service_,
|
||||
/*sync_service=*/nullptr));
|
||||
}
|
||||
|
||||
|
@ -14,7 +14,6 @@
|
||||
#include "components/autofill/core/browser/webdata/autofill_webdata_service.h"
|
||||
#include "components/browsing_data/core/counters/browsing_data_counter.h"
|
||||
#include "components/password_manager/core/browser/password_store/password_store_interface.h"
|
||||
#include "components/user_annotations/user_annotations_service.h"
|
||||
#include "device/fido/platform_credential_store.h"
|
||||
|
||||
class PrefService;
|
||||
@ -47,7 +46,6 @@ class ProfileStatisticsAggregator {
|
||||
scoped_refptr<password_manager::PasswordStoreInterface>
|
||||
profile_password_store,
|
||||
PrefService* pref_service,
|
||||
user_annotations::UserAnnotationsService* user_annotations_service,
|
||||
std::unique_ptr<device::fido::PlatformCredentialStore>
|
||||
platform_credential_store,
|
||||
base::OnceClosure done_callback);
|
||||
@ -83,8 +81,6 @@ class ProfileStatisticsAggregator {
|
||||
const scoped_refptr<password_manager::PasswordStoreInterface>
|
||||
profile_password_store_;
|
||||
const raw_ptr<PrefService> pref_service_;
|
||||
const raw_ptr<user_annotations::UserAnnotationsService>
|
||||
user_annotations_service_;
|
||||
|
||||
std::unique_ptr<device::fido::PlatformCredentialStore>
|
||||
platform_credential_store_;
|
||||
|
@ -81,7 +81,6 @@ class ProfileStatisticsAggregatorTest : public testing::Test {
|
||||
return std::make_unique<ProfileStatisticsAggregator>(
|
||||
autofill_web_data_service_, &personal_data_manager_, &bookmark_model_,
|
||||
&history_service_, profile_password_store_, &pref_service_,
|
||||
/*user_annotations_service=*/nullptr,
|
||||
/*platform_credential_store=*/nullptr, std::move(done_callback));
|
||||
}
|
||||
|
||||
|
@ -11,7 +11,6 @@
|
||||
#include "chrome/browser/password_manager/profile_password_store_factory.h"
|
||||
#include "chrome/browser/profiles/profile.h"
|
||||
#include "chrome/browser/profiles/profile_statistics.h"
|
||||
#include "chrome/browser/user_annotations/user_annotations_service_factory.h"
|
||||
#include "chrome/browser/webauthn/chrome_web_authentication_delegate.h"
|
||||
#include "chrome/browser/webdata_services/web_data_service_factory.h"
|
||||
#include "components/keyed_service/core/service_access_type.h"
|
||||
@ -25,10 +24,6 @@
|
||||
#include "device/fido/cros/credential_store.h"
|
||||
#endif
|
||||
|
||||
#if !BUILDFLAG(IS_ANDROID)
|
||||
#include "chrome/browser/user_annotations/user_annotations_service_factory.h"
|
||||
#endif
|
||||
|
||||
// static
|
||||
ProfileStatistics* ProfileStatisticsFactory::GetForProfile(Profile* profile) {
|
||||
return static_cast<ProfileStatistics*>(
|
||||
@ -83,10 +78,5 @@ ProfileStatisticsFactory::BuildServiceInstanceForBrowserContext(
|
||||
ProfilePasswordStoreFactory::GetForProfile(
|
||||
profile, ServiceAccessType::EXPLICIT_ACCESS),
|
||||
profile->GetPrefs(),
|
||||
#if !BUILDFLAG(IS_ANDROID)
|
||||
UserAnnotationsServiceFactory::GetForProfile(profile),
|
||||
#else
|
||||
/*user_annotations_service=*/nullptr,
|
||||
#endif
|
||||
std::move(credential_store));
|
||||
}
|
||||
|
@ -1777,7 +1777,6 @@ static_library("ui") {
|
||||
"//chrome/browser/ui/webui/whats_new:impl",
|
||||
"//chrome/browser/ui/window_sizer",
|
||||
"//chrome/browser/ui/window_sizer:impl",
|
||||
"//chrome/browser/user_annotations",
|
||||
"//chrome/browser/web_applications",
|
||||
"//chrome/browser/web_applications:features",
|
||||
"//chrome/common:buildflags",
|
||||
|
@ -41,7 +41,6 @@ source_set("autofill") {
|
||||
"//components/keyed_service/core",
|
||||
"//components/optimization_guide/proto:optimization_guide_proto",
|
||||
"//components/signin/public/identity_manager",
|
||||
"//components/user_annotations:types",
|
||||
"//components/zoom",
|
||||
"//content/public/browser",
|
||||
"//ui/gfx",
|
||||
|
@ -12,7 +12,6 @@
|
||||
#include "base/types/optional_ref.h"
|
||||
#include "components/autofill/core/browser/integrators/autofill_ai_delegate.h"
|
||||
#include "components/autofill_ai/core/browser/autofill_ai_client.h"
|
||||
#include "components/user_annotations/user_annotations_types.h"
|
||||
#include "content/public/browser/web_contents.h"
|
||||
|
||||
namespace autofill {
|
||||
|
@ -36,7 +36,6 @@
|
||||
#include "components/autofill/core/browser/ui/payments/card_unmask_prompt_options.h"
|
||||
#include "components/optimization_guide/proto/features/common_quality_data.pb.h"
|
||||
#include "components/signin/public/identity_manager/account_info.h"
|
||||
#include "components/user_annotations/user_annotations_types.h"
|
||||
#include "content/public/browser/visibility.h"
|
||||
#include "content/public/browser/web_contents_observer.h"
|
||||
|
||||
|
@ -1,68 +0,0 @@
|
||||
# Copyright 2024 The Chromium Authors
|
||||
# Use of this source code is governed by a BSD-style license that can be
|
||||
# found in the LICENSE file.
|
||||
|
||||
import("//build/buildflag_header.gni")
|
||||
import("//build/config/chromeos/ui_mode.gni")
|
||||
import("//build/config/ui.gni")
|
||||
import("//chrome/version.gni")
|
||||
import("//components/optimization_guide/features.gni")
|
||||
import("//extensions/buildflags/buildflags.gni")
|
||||
|
||||
assert(!is_fuchsia, "Fuchsia shouldn't use anything in //chrome")
|
||||
|
||||
static_library("user_annotations") {
|
||||
sources = [
|
||||
"user_annotations_service_factory.cc",
|
||||
"user_annotations_service_factory.h",
|
||||
]
|
||||
public_deps = [
|
||||
"//base",
|
||||
"//chrome/browser:browser_public_dependencies",
|
||||
"//chrome/browser/profiles:profile",
|
||||
"//chrome/browser/profiles:profile_util",
|
||||
"//content/public/browser",
|
||||
]
|
||||
deps = [
|
||||
"//chrome/browser:browser_process",
|
||||
"//chrome/browser/optimization_guide",
|
||||
"//chrome/browser/ui/autofill",
|
||||
"//components/autofill/content/browser:browser",
|
||||
"//components/compose:buildflags",
|
||||
"//components/user_annotations",
|
||||
"//ui/accessibility",
|
||||
]
|
||||
if (is_chromeos_ash) {
|
||||
deps += [ "//chrome/browser/ash/profiles" ]
|
||||
}
|
||||
}
|
||||
|
||||
if (!is_android) {
|
||||
source_set("browser_tests") {
|
||||
testonly = true
|
||||
|
||||
defines = [ "HAS_OUT_OF_PROC_TEST_RUNNER" ]
|
||||
|
||||
sources = [ "user_annotations_service_browsertest.cc" ]
|
||||
|
||||
public_deps = [ "//content/test:test_support" ]
|
||||
|
||||
deps = [
|
||||
":user_annotations",
|
||||
"//chrome/browser/optimization_guide:test_support",
|
||||
"//chrome/browser/ui",
|
||||
"//chrome/test:test_support",
|
||||
"//chrome/test:test_support_ui",
|
||||
"//components/autofill/core/common",
|
||||
"//components/autofill_ai/core/browser",
|
||||
"//components/signin/public/base",
|
||||
"//components/signin/public/identity_manager",
|
||||
"//components/user_annotations",
|
||||
"//content/test:test_support",
|
||||
]
|
||||
|
||||
if (is_chromeos_ash) {
|
||||
deps += [ "//chrome/browser/ash/login/test:test_support" ]
|
||||
}
|
||||
}
|
||||
}
|
@ -1 +0,0 @@
|
||||
file://components/optimization_guide/OWNERS
|
@ -1,297 +0,0 @@
|
||||
// Copyright 2024 The Chromium Authors
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "components/user_annotations/user_annotations_service.h"
|
||||
|
||||
#include <optional>
|
||||
|
||||
#include "base/run_loop.h"
|
||||
#include "base/test/metrics/histogram_tester.h"
|
||||
#include "base/test/scoped_feature_list.h"
|
||||
#include "base/test/test_future.h"
|
||||
#include "chrome/browser/optimization_guide/browser_test_util.h"
|
||||
#include "chrome/browser/optimization_guide/optimization_guide_keyed_service.h"
|
||||
#include "chrome/browser/optimization_guide/optimization_guide_keyed_service_factory.h"
|
||||
#include "chrome/browser/profiles/profile.h"
|
||||
#include "chrome/browser/signin/identity_test_environment_profile_adaptor.h"
|
||||
#include "chrome/browser/ui/browser.h"
|
||||
#include "chrome/browser/user_annotations/user_annotations_service_factory.h"
|
||||
#include "chrome/common/chrome_switches.h"
|
||||
#include "chrome/test/base/in_process_browser_test.h"
|
||||
#include "chrome/test/base/ui_test_utils.h"
|
||||
#include "components/autofill/core/common/autofill_prefs.h"
|
||||
#include "components/autofill_ai/core/browser/autofill_ai_features.h"
|
||||
#include "components/optimization_guide/proto/features/common_quality_data.pb.h"
|
||||
#include "components/signin/public/base/signin_switches.h"
|
||||
#include "components/signin/public/identity_manager/account_capabilities_test_mutator.h"
|
||||
#include "components/user_annotations/user_annotations_types.h"
|
||||
#include "content/public/test/browser_test.h"
|
||||
#include "content/public/test/browser_test_utils.h"
|
||||
#include "net/dns/mock_host_resolver.h"
|
||||
|
||||
#if BUILDFLAG(IS_CHROMEOS_ASH)
|
||||
#include "chrome/browser/ash/login/test/device_state_mixin.h"
|
||||
#include "chrome/browser/ash/login/test/guest_session_mixin.h"
|
||||
#include "chrome/test/base/mixin_based_in_process_browser_test.h"
|
||||
#endif
|
||||
|
||||
namespace user_annotations {
|
||||
|
||||
class UserAnnotationsServiceDisabledBrowserTest : public InProcessBrowserTest {
|
||||
public:
|
||||
void SetUp() override {
|
||||
feature_list_.InitAndDisableFeature(autofill_ai::kAutofillAi);
|
||||
InProcessBrowserTest::SetUp();
|
||||
}
|
||||
|
||||
private:
|
||||
base::test::ScopedFeatureList feature_list_;
|
||||
};
|
||||
|
||||
IN_PROC_BROWSER_TEST_F(UserAnnotationsServiceDisabledBrowserTest,
|
||||
ServiceNotCreatedWhenFeatureDisabled) {
|
||||
ASSERT_FALSE(
|
||||
UserAnnotationsServiceFactory::GetForProfile(browser()->profile()));
|
||||
}
|
||||
|
||||
class UserAnnotationsServiceKioskModeBrowserTest : public InProcessBrowserTest {
|
||||
public:
|
||||
UserAnnotationsServiceKioskModeBrowserTest() {
|
||||
scoped_feature_list_.InitAndEnableFeature(autofill_ai::kAutofillAi);
|
||||
}
|
||||
|
||||
void SetUpCommandLine(base::CommandLine* command_line) override {
|
||||
command_line->AppendSwitch(::switches::kKioskMode);
|
||||
}
|
||||
|
||||
private:
|
||||
base::test::ScopedFeatureList scoped_feature_list_;
|
||||
};
|
||||
|
||||
IN_PROC_BROWSER_TEST_F(UserAnnotationsServiceKioskModeBrowserTest,
|
||||
DisabledInKioskMode) {
|
||||
EXPECT_EQ(nullptr,
|
||||
UserAnnotationsServiceFactory::GetForProfile(browser()->profile()));
|
||||
}
|
||||
|
||||
#if BUILDFLAG(IS_CHROMEOS_ASH)
|
||||
class UserAnnotationsServiceEphemeralProfileBrowserTest
|
||||
: public MixinBasedInProcessBrowserTest {
|
||||
public:
|
||||
UserAnnotationsServiceEphemeralProfileBrowserTest() {
|
||||
scoped_feature_list_.InitAndEnableFeature(autofill_ai::kAutofillAi);
|
||||
}
|
||||
|
||||
private:
|
||||
ash::GuestSessionMixin guest_session_{&mixin_host_};
|
||||
|
||||
base::test::ScopedFeatureList scoped_feature_list_;
|
||||
};
|
||||
|
||||
IN_PROC_BROWSER_TEST_F(UserAnnotationsServiceEphemeralProfileBrowserTest,
|
||||
EphemeralProfileDoesNotInstantiateService) {
|
||||
EXPECT_EQ(nullptr,
|
||||
UserAnnotationsServiceFactory::GetForProfile(browser()->profile()));
|
||||
}
|
||||
#endif
|
||||
|
||||
class UserAnnotationsServiceBrowserTest : public InProcessBrowserTest {
|
||||
public:
|
||||
void SetUp() override {
|
||||
InitializeFeatureList();
|
||||
InProcessBrowserTest::SetUp();
|
||||
}
|
||||
|
||||
void SetUpOnMainThread() override {
|
||||
host_resolver()->AddRule("*", "127.0.0.1");
|
||||
InProcessBrowserTest::SetUpOnMainThread();
|
||||
|
||||
browser()->profile()->GetPrefs()->SetBoolean(
|
||||
autofill::prefs::kAutofillPredictionImprovementsEnabled, true);
|
||||
|
||||
identity_test_env_adaptor_ =
|
||||
std::make_unique<IdentityTestEnvironmentProfileAdaptor>(
|
||||
browser()->profile());
|
||||
embedded_test_server()->ServeFilesFromSourceDirectory(
|
||||
"components/test/data/autofill");
|
||||
ASSERT_TRUE(embedded_test_server()->Start());
|
||||
}
|
||||
|
||||
void SetUpInProcessBrowserTestFixture() override {
|
||||
create_services_subscription_ =
|
||||
BrowserContextDependencyManager::GetInstance()
|
||||
->RegisterCreateServicesCallbackForTesting(
|
||||
base::BindRepeating(&UserAnnotationsServiceBrowserTest::
|
||||
OnWillCreateBrowserContextServices,
|
||||
base::Unretained(this)));
|
||||
}
|
||||
|
||||
void EnableSignin() {
|
||||
auto account_info =
|
||||
identity_test_env_adaptor_->identity_test_env()
|
||||
->MakePrimaryAccountAvailable("user@gmail.com",
|
||||
signin::ConsentLevel::kSignin);
|
||||
AccountCapabilitiesTestMutator mutator(&account_info.capabilities);
|
||||
mutator.set_can_use_model_execution_features(true);
|
||||
identity_test_env_adaptor_->identity_test_env()
|
||||
->UpdateAccountInfoForAccount(account_info);
|
||||
identity_test_env_adaptor_->identity_test_env()
|
||||
->SetAutomaticIssueOfAccessTokens(true);
|
||||
}
|
||||
|
||||
testing::AssertionResult SubmitForm(content::RenderFrameHost* rfh) {
|
||||
return content::ExecJs(rfh, R"(document.forms[0].submit();)");
|
||||
}
|
||||
|
||||
testing::AssertionResult FillForm(content::RenderFrameHost* rfh) {
|
||||
return content::ExecJs(rfh, R"(
|
||||
document.getElementsByName("name")[0].value="John Doe";
|
||||
document.getElementsByName("address")[0].value="123 Main Street";
|
||||
document.getElementsByName("city")[0].value="Knightdale";
|
||||
document.getElementsByName("state")[0].selectedIndex=3;
|
||||
document.getElementsByName("zip")[0].value="27545";
|
||||
document.getElementsByName("country")[0].value="United States";
|
||||
document.getElementsByName("email")[0].value="jd@example.com";
|
||||
document.getElementsByName("phone")[0].value="919-555-5555";
|
||||
)");
|
||||
}
|
||||
|
||||
protected:
|
||||
UserAnnotationsService* service() {
|
||||
return UserAnnotationsServiceFactory::GetForProfile(browser()->profile());
|
||||
}
|
||||
|
||||
content::WebContents* web_contents() {
|
||||
return browser()->tab_strip_model()->GetActiveWebContents();
|
||||
}
|
||||
|
||||
virtual void InitializeFeatureList() {
|
||||
feature_list_.InitWithFeatures({autofill_ai::kAutofillAi}, {});
|
||||
}
|
||||
|
||||
base::test::ScopedFeatureList feature_list_;
|
||||
|
||||
private:
|
||||
void OnWillCreateBrowserContextServices(content::BrowserContext* context) {
|
||||
IdentityTestEnvironmentProfileAdaptor::
|
||||
SetIdentityTestEnvironmentFactoriesOnBrowserContext(context);
|
||||
}
|
||||
|
||||
// Identity test support.
|
||||
std::unique_ptr<IdentityTestEnvironmentProfileAdaptor>
|
||||
identity_test_env_adaptor_;
|
||||
base::CallbackListSubscription create_services_subscription_;
|
||||
};
|
||||
|
||||
IN_PROC_BROWSER_TEST_F(UserAnnotationsServiceBrowserTest, ServiceFactoryWorks) {
|
||||
EXPECT_TRUE(service());
|
||||
}
|
||||
|
||||
IN_PROC_BROWSER_TEST_F(UserAnnotationsServiceBrowserTest,
|
||||
ServiceNotCreatedForIncognito) {
|
||||
Browser* otr_browser = CreateIncognitoBrowser(browser()->profile());
|
||||
EXPECT_EQ(nullptr, UserAnnotationsServiceFactory::GetForProfile(
|
||||
otr_browser->profile()));
|
||||
}
|
||||
|
||||
// TODO(crbug.com/367201367): Re-enable once flakiness is resolved for Windows
|
||||
// ASAN. Also flaky on Mac.
|
||||
IN_PROC_BROWSER_TEST_F(UserAnnotationsServiceBrowserTest,
|
||||
DISABLED_FormSubmissionFlow) {
|
||||
EnableSignin();
|
||||
|
||||
base::HistogramTester histogram_tester;
|
||||
|
||||
GURL url(
|
||||
embedded_test_server()->GetURL("a.com", "/autofill_address_form.html"));
|
||||
OptimizationGuideKeyedServiceFactory::GetForProfile(browser()->profile())
|
||||
->AddHintForTesting(url, optimization_guide::proto::FORMS_ANNOTATIONS,
|
||||
std::nullopt);
|
||||
|
||||
ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), url));
|
||||
|
||||
ASSERT_TRUE(FillForm(web_contents()->GetPrimaryMainFrame()));
|
||||
ASSERT_TRUE(SubmitForm(web_contents()->GetPrimaryMainFrame()));
|
||||
|
||||
EXPECT_EQ(
|
||||
1, optimization_guide::RetryForHistogramUntilCountReached(
|
||||
&histogram_tester, "UserAnnotations.AddFormSubmissionResult", 1));
|
||||
histogram_tester.ExpectTotalCount("UserAnnotations.AddFormSubmissionResult",
|
||||
1);
|
||||
}
|
||||
|
||||
IN_PROC_BROWSER_TEST_F(UserAnnotationsServiceBrowserTest, NotOnAllowlist) {
|
||||
EnableSignin();
|
||||
|
||||
base::HistogramTester histogram_tester;
|
||||
|
||||
GURL url(embedded_test_server()->GetURL("notallowed.com",
|
||||
"/autofill_address_form.html"));
|
||||
ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), url));
|
||||
|
||||
ASSERT_TRUE(FillForm(web_contents()->GetPrimaryMainFrame()));
|
||||
ASSERT_TRUE(SubmitForm(web_contents()->GetPrimaryMainFrame()));
|
||||
base::RunLoop().RunUntilIdle();
|
||||
|
||||
histogram_tester.ExpectTotalCount("UserAnnotations.AddFormSubmissionResult",
|
||||
0);
|
||||
}
|
||||
|
||||
// TODO: b/361692317 - Delete below once optimization guide populates list.
|
||||
|
||||
class UserAnnotationsServiceExplicitAllowlistBrowserTest
|
||||
: public UserAnnotationsServiceBrowserTest {
|
||||
protected:
|
||||
void InitializeFeatureList() override {
|
||||
feature_list_.InitWithFeaturesAndParameters(
|
||||
{{autofill_ai::kAutofillAi,
|
||||
{{"allowed_hosts_for_form_submissions", "allowed.com"}}}},
|
||||
{});
|
||||
}
|
||||
|
||||
private:
|
||||
base::test::ScopedFeatureList feature_list_;
|
||||
};
|
||||
|
||||
IN_PROC_BROWSER_TEST_F(UserAnnotationsServiceExplicitAllowlistBrowserTest,
|
||||
NotOnAllowlist) {
|
||||
EnableSignin();
|
||||
|
||||
base::HistogramTester histogram_tester;
|
||||
|
||||
GURL url(embedded_test_server()->GetURL("notallowed.com",
|
||||
"/autofill_address_form.html"));
|
||||
ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), url));
|
||||
|
||||
ASSERT_TRUE(FillForm(web_contents()->GetPrimaryMainFrame()));
|
||||
ASSERT_TRUE(SubmitForm(web_contents()->GetPrimaryMainFrame()));
|
||||
base::RunLoop().RunUntilIdle();
|
||||
|
||||
histogram_tester.ExpectTotalCount("UserAnnotations.AddFormSubmissionResult",
|
||||
0);
|
||||
}
|
||||
|
||||
// TODO(crbug.com/367201367): Re-enable once flakiness is resolved for Windows
|
||||
// ASAN. Also flaky on Mac.
|
||||
IN_PROC_BROWSER_TEST_F(UserAnnotationsServiceExplicitAllowlistBrowserTest,
|
||||
DISABLED_OnAllowlist) {
|
||||
EnableSignin();
|
||||
|
||||
base::HistogramTester histogram_tester;
|
||||
|
||||
GURL url(embedded_test_server()->GetURL("allowed.com",
|
||||
"/autofill_address_form.html"));
|
||||
ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), url));
|
||||
|
||||
ASSERT_TRUE(FillForm(web_contents()->GetPrimaryMainFrame()));
|
||||
ASSERT_TRUE(SubmitForm(web_contents()->GetPrimaryMainFrame()));
|
||||
|
||||
EXPECT_EQ(
|
||||
1, optimization_guide::RetryForHistogramUntilCountReached(
|
||||
&histogram_tester, "UserAnnotations.AddFormSubmissionResult", 1));
|
||||
histogram_tester.ExpectTotalCount("UserAnnotations.AddFormSubmissionResult",
|
||||
1);
|
||||
}
|
||||
|
||||
} // namespace user_annotations
|
@ -1,89 +0,0 @@
|
||||
// Copyright 2024 The Chromium Authors
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "chrome/browser/user_annotations/user_annotations_service_factory.h"
|
||||
|
||||
#include "chrome/browser/app_mode/app_mode_utils.h"
|
||||
#include "chrome/browser/browser_process.h"
|
||||
#include "chrome/browser/optimization_guide/optimization_guide_keyed_service.h"
|
||||
#include "chrome/browser/optimization_guide/optimization_guide_keyed_service_factory.h"
|
||||
#include "chrome/browser/profiles/profile.h"
|
||||
#include "chrome/browser/profiles/profile_attributes_entry.h"
|
||||
#include "chrome/browser/profiles/profile_attributes_storage.h"
|
||||
#include "chrome/browser/profiles/profile_manager.h"
|
||||
#include "components/user_annotations/user_annotations_features.h"
|
||||
#include "components/user_annotations/user_annotations_service.h"
|
||||
|
||||
#if BUILDFLAG(IS_CHROMEOS_ASH)
|
||||
#include "chrome/browser/ash/profiles/profile_helper.h"
|
||||
#endif
|
||||
|
||||
namespace {
|
||||
|
||||
bool IsEphemeralProfile(Profile* profile) {
|
||||
#if BUILDFLAG(IS_CHROMEOS_ASH)
|
||||
if (ash::ProfileHelper::IsEphemeralUserProfile(profile)) {
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Catch additional logic that may not be caught by the existing Ash check.
|
||||
ProfileAttributesStorage& storage =
|
||||
g_browser_process->profile_manager()->GetProfileAttributesStorage();
|
||||
ProfileAttributesEntry* entry =
|
||||
storage.GetProfileAttributesWithPath(profile->GetPath());
|
||||
return entry && entry->IsEphemeral();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
// static
|
||||
user_annotations::UserAnnotationsService*
|
||||
UserAnnotationsServiceFactory::GetForProfile(Profile* profile) {
|
||||
return static_cast<user_annotations::UserAnnotationsService*>(
|
||||
GetInstance()->GetServiceForBrowserContext(profile, /*create=*/true));
|
||||
}
|
||||
|
||||
// static
|
||||
UserAnnotationsServiceFactory* UserAnnotationsServiceFactory::GetInstance() {
|
||||
static base::NoDestructor<UserAnnotationsServiceFactory> instance;
|
||||
return instance.get();
|
||||
}
|
||||
|
||||
UserAnnotationsServiceFactory::UserAnnotationsServiceFactory()
|
||||
: ProfileKeyedServiceFactory(
|
||||
"UserAnnotationsService",
|
||||
ProfileSelections::Builder()
|
||||
.WithRegular(ProfileSelection::kOriginalOnly)
|
||||
.Build()) {
|
||||
DependsOn(OptimizationGuideKeyedServiceFactory::GetInstance());
|
||||
}
|
||||
|
||||
UserAnnotationsServiceFactory::~UserAnnotationsServiceFactory() = default;
|
||||
|
||||
std::unique_ptr<KeyedService>
|
||||
UserAnnotationsServiceFactory::BuildServiceInstanceForBrowserContext(
|
||||
content::BrowserContext* context) const {
|
||||
if (!user_annotations::IsUserAnnotationsEnabled()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto* profile = Profile::FromBrowserContext(context);
|
||||
|
||||
// This is not useful in kiosk or ephemeral profile mode, so simply never
|
||||
// construct the service for those users.
|
||||
if (IsRunningInAppMode() || IsEphemeralProfile(profile)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
OptimizationGuideKeyedService* ogks =
|
||||
OptimizationGuideKeyedServiceFactory::GetForProfile(profile);
|
||||
if (!ogks) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return std::make_unique<user_annotations::UserAnnotationsService>(
|
||||
ogks, ogks->GetModelQualityLogsUploaderService(), profile->GetPath(),
|
||||
g_browser_process->os_crypt_async(), ogks);
|
||||
}
|
@ -1,50 +0,0 @@
|
||||
// Copyright 2024 The Chromium Authors
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef CHROME_BROWSER_USER_ANNOTATIONS_USER_ANNOTATIONS_SERVICE_FACTORY_H_
|
||||
#define CHROME_BROWSER_USER_ANNOTATIONS_USER_ANNOTATIONS_SERVICE_FACTORY_H_
|
||||
|
||||
#include "base/no_destructor.h"
|
||||
#include "chrome/browser/profiles/profile_keyed_service_factory.h"
|
||||
|
||||
namespace content {
|
||||
class BrowserContext;
|
||||
} // namespace content
|
||||
|
||||
namespace user_annotations {
|
||||
class UserAnnotationsService;
|
||||
} // namespace user_annotations
|
||||
|
||||
class Profile;
|
||||
|
||||
// LazyInstance that owns all UserAnnotationsService(s) and associates
|
||||
// them with Profiles.
|
||||
class UserAnnotationsServiceFactory : public ProfileKeyedServiceFactory {
|
||||
public:
|
||||
// Gets the UserAnnotationsService for the profile.
|
||||
//
|
||||
// Returns null if the features that allow for this to provide useful
|
||||
// information are disabled.
|
||||
static user_annotations::UserAnnotationsService* GetForProfile(
|
||||
Profile* profile);
|
||||
|
||||
// Gets the LazyInstance that owns all UserAnnotationsService(s).
|
||||
static UserAnnotationsServiceFactory* GetInstance();
|
||||
|
||||
UserAnnotationsServiceFactory(const UserAnnotationsServiceFactory&) = delete;
|
||||
UserAnnotationsServiceFactory& operator=(
|
||||
const UserAnnotationsServiceFactory&) = delete;
|
||||
|
||||
private:
|
||||
friend base::NoDestructor<UserAnnotationsServiceFactory>;
|
||||
|
||||
UserAnnotationsServiceFactory();
|
||||
~UserAnnotationsServiceFactory() override;
|
||||
|
||||
// BrowserContextKeyedServiceFactory:
|
||||
std::unique_ptr<KeyedService> BuildServiceInstanceForBrowserContext(
|
||||
content::BrowserContext* context) const override;
|
||||
};
|
||||
|
||||
#endif // CHROME_BROWSER_USER_ANNOTATIONS_USER_ANNOTATIONS_SERVICE_FACTORY_H_
|
@ -2216,7 +2216,6 @@ if (!is_android) {
|
||||
"//chrome/browser/ui/webui/top_chrome",
|
||||
"//chrome/browser/ui/webui/top_chrome:test_support",
|
||||
"//chrome/browser/ui/webui/whats_new",
|
||||
"//chrome/browser/user_annotations:browser_tests",
|
||||
"//chrome/browser/web_applications:browser_tests",
|
||||
"//chrome/browser/web_applications:features",
|
||||
"//chrome/browser/web_applications:prevent_close_test_support",
|
||||
@ -2493,7 +2492,6 @@ if (!is_android) {
|
||||
"//components/url_formatter/spoof_checks/top_domains:generate_top_domains_test_trie",
|
||||
"//components/url_formatter/spoof_checks/top_domains:test_top_bucket_domains",
|
||||
"//components/url_formatter/spoof_checks/top_domains:test_top_bucket_domains_header",
|
||||
"//components/user_annotations",
|
||||
"//components/user_education/common",
|
||||
"//components/user_education/test",
|
||||
"//components/user_education/webui:webui",
|
||||
@ -4525,7 +4523,6 @@ if (!is_android) {
|
||||
# when tests that include chrome_zoom_level_prefs.h get modularized, eg
|
||||
# tabs_test.cc, app_browsertest.cc, host_zoom_map_browsertest.cc and ats_browsertest.cc.
|
||||
"//chrome/browser/ui/zoom",
|
||||
"//chrome/browser/user_annotations:user_annotations",
|
||||
"//chrome/browser/web_applications/extensions",
|
||||
"//chrome/common/extensions/api",
|
||||
"//chrome/services/media_gallery_util/public/cpp:browser_tests",
|
||||
@ -4538,13 +4535,11 @@ if (!is_android) {
|
||||
"//components/media_router/browser:test_support",
|
||||
"//components/media_router/common:test_support",
|
||||
"//components/optimization_guide/optimization_guide_internals/webui",
|
||||
"//components/user_annotations:test_support",
|
||||
"//components/web_package",
|
||||
|
||||
# TODO(rockot) bug 505926: The chrome_extensions_browsertests_sources
|
||||
# target should be deleted and this line removed. See the
|
||||
# chrome_extensions_browsertests_sources target for more.
|
||||
"//components/user_annotations:test_support",
|
||||
"//extensions:chrome_extensions_browsertests_sources",
|
||||
"//extensions/browser:test_support",
|
||||
"//extensions/browser/api/storage:settings_namespace",
|
||||
@ -6796,7 +6791,6 @@ test("unit_tests") {
|
||||
"//components/url_formatter/spoof_checks/top_domains:generate_top_domains_test_trie",
|
||||
"//components/url_formatter/spoof_checks/top_domains:test_top_bucket_domains",
|
||||
"//components/url_formatter/spoof_checks/top_domains:test_top_bucket_domains_header",
|
||||
"//components/user_annotations:test_support",
|
||||
"//components/user_education/common",
|
||||
"//components/user_education/test",
|
||||
"//components/user_manager",
|
||||
@ -8124,7 +8118,6 @@ test("unit_tests") {
|
||||
"//chrome/browser/ui/zoom",
|
||||
"//chrome/browser/ui/zoom:unit_tests",
|
||||
"//chrome/browser/upgrade_detector:build_state_observer",
|
||||
"//chrome/browser/user_annotations",
|
||||
"//chrome/browser/web_applications:features",
|
||||
"//chrome/browser/web_applications:web_applications_test_support",
|
||||
"//chrome/browser/webauthn:test_support",
|
||||
@ -8176,8 +8169,6 @@ test("unit_tests") {
|
||||
"//components/soda:constants",
|
||||
"//components/supervised_user/core/browser",
|
||||
"//components/sync:test_support",
|
||||
"//components/user_annotations",
|
||||
"//components/user_annotations:test_support",
|
||||
"//components/user_education/common",
|
||||
"//components/user_education/test",
|
||||
"//components/webapps/browser",
|
||||
@ -10845,7 +10836,6 @@ if (!is_android && !is_chromeos_device) {
|
||||
"//chrome/browser/ui/views/page_action",
|
||||
"//chrome/browser/ui/views/side_panel",
|
||||
"//chrome/browser/ui/views/toolbar",
|
||||
"//chrome/browser/user_annotations:user_annotations",
|
||||
"//chrome/browser/web_applications:features",
|
||||
"//chrome/browser/web_applications:interactive_ui_tests",
|
||||
"//chrome/browser/web_applications:web_applications_test_support",
|
||||
@ -10919,7 +10909,6 @@ if (!is_android && !is_chromeos_device) {
|
||||
"//components/translate/content/browser:test_support",
|
||||
"//components/ukm:test_support",
|
||||
"//components/ukm:ukm_test_helper",
|
||||
"//components/user_annotations:user_annotations",
|
||||
"//components/user_education/common",
|
||||
"//components/user_education/test",
|
||||
"//components/webapps/browser:test_support",
|
||||
|
@ -366,7 +366,6 @@ test("components_unittests") {
|
||||
"//components/url_formatter/spoof_checks/top_domains:unit_tests",
|
||||
"//components/url_matcher:unit_tests",
|
||||
"//components/url_pattern_index:unit_tests",
|
||||
"//components/user_annotations:unit_tests",
|
||||
"//components/variations:unit_tests",
|
||||
"//components/variations/field_trial_config:unit_tests",
|
||||
"//components/variations/service:unit_tests",
|
||||
|
@ -838,7 +838,6 @@ static_library("browser") {
|
||||
"//components/strings",
|
||||
"//components/sync",
|
||||
"//components/translate/core/common",
|
||||
"//components/user_annotations:types",
|
||||
"//components/variations",
|
||||
"//components/variations/net",
|
||||
"//components/version_info",
|
||||
@ -1110,7 +1109,6 @@ static_library("test_support") {
|
||||
"//components/translate/core/browser:test_support",
|
||||
"//components/ukm",
|
||||
"//components/ukm:test_support",
|
||||
"//components/user_annotations:types",
|
||||
"//components/variations",
|
||||
"//components/variations:test_support",
|
||||
"//components/variations/net",
|
||||
|
@ -28,7 +28,6 @@ include_rules = [
|
||||
"+components/sync_preferences",
|
||||
"+components/translate/core/browser",
|
||||
"+components/translate/core/common",
|
||||
"+components/user_annotations",
|
||||
"+components/variations",
|
||||
"+components/version_info",
|
||||
"+components/webdata/common",
|
||||
|
@ -4,7 +4,6 @@ include_rules = [
|
||||
"+components/optimization_guide/proto",
|
||||
"+components/prefs",
|
||||
"+components/strings/grit",
|
||||
"+components/user_annotations",
|
||||
"+ui/base",
|
||||
"+ui/native_theme",
|
||||
]
|
||||
|
@ -41,7 +41,8 @@
|
||||
#include "testing/gtest/include/gtest/gtest.h"
|
||||
|
||||
// TODO(crbug.com/389629573): Refactor this test to handle only the
|
||||
// implementation under `autofill::features::kAutofillAiWithDataSchema` flag.
|
||||
// implementation under `autofill::features::kAutofillAiWithDataSchema`
|
||||
// flag.
|
||||
namespace autofill_ai {
|
||||
namespace {
|
||||
|
||||
|
@ -43,7 +43,6 @@ static_library("core") {
|
||||
"//components/prefs",
|
||||
"//components/strings",
|
||||
"//components/sync",
|
||||
"//components/user_annotations",
|
||||
"//components/version_info",
|
||||
"//components/webdata/common",
|
||||
"//ui/base",
|
||||
|
@ -12,7 +12,6 @@ include_rules = [
|
||||
"+components/sync/service",
|
||||
"+components/sync/test",
|
||||
"+components/sync_preferences",
|
||||
"+components/user_annotations",
|
||||
"+components/version_info",
|
||||
"+components/webdata/common",
|
||||
"+net",
|
||||
|
@ -318,18 +318,7 @@ std::u16string GetCounterTextFromResult(
|
||||
NOTREACHED();
|
||||
}
|
||||
|
||||
AutofillCounter::ResultInt num_user_annotations =
|
||||
autofill_result->num_user_annotation_entries();
|
||||
if (num_user_annotations) {
|
||||
return l10n_util::GetStringFUTF16(
|
||||
IDS_DEL_AUTOFILL_SYNCABLE_NON_SYNCABLE_COMBINATION,
|
||||
payment_methods_addresses_autocomplete_entries_part,
|
||||
l10n_util::GetPluralStringFUTF16(
|
||||
IDS_DEL_AUTOFILL_COUNTER_USER_ANNOTATION_ENTRIES,
|
||||
num_user_annotations));
|
||||
} else {
|
||||
return payment_methods_addresses_autocomplete_entries_part;
|
||||
}
|
||||
return payment_methods_addresses_autocomplete_entries_part;
|
||||
}
|
||||
|
||||
NOTREACHED();
|
||||
|
@ -64,8 +64,7 @@ class BrowsingDataUtilsTest : public testing::Test {
|
||||
TEST_F(BrowsingDataUtilsTest, AutofillCounterResult) {
|
||||
autofill::TestPersonalDataManager test_personal_data_manager;
|
||||
AutofillCounter counter(&test_personal_data_manager,
|
||||
base::MakeRefCounted<FakeWebDataService>(), nullptr,
|
||||
nullptr);
|
||||
base::MakeRefCounted<FakeWebDataService>(), nullptr);
|
||||
|
||||
// Test all configurations of zero and nonzero partial results for datatypes.
|
||||
// Test singular and plural for each datatype.
|
||||
@ -73,34 +72,29 @@ TEST_F(BrowsingDataUtilsTest, AutofillCounterResult) {
|
||||
int num_credit_cards;
|
||||
int num_addresses;
|
||||
int num_suggestions;
|
||||
int num_user_annotation_entries;
|
||||
bool sync_enabled;
|
||||
std::string expected_output;
|
||||
} kTestCases[] = {
|
||||
{0, 0, 0, 0, false, "None"},
|
||||
{0, 0, 0, 0, true, "None"},
|
||||
{1, 0, 0, 0, false, "1 payment method"},
|
||||
{0, 5, 0, 0, false, "5 addresses"},
|
||||
{0, 0, 1, 0, false, "1 suggestion"},
|
||||
{0, 0, 2, 0, false, "2 suggestions"},
|
||||
{0, 0, 2, 0, true, "2 suggestions (synced)"},
|
||||
{4, 7, 0, 0, false, "4 payment methods, 7 addresses"},
|
||||
{4, 7, 0, 0, true, "4 payment methods, 7 addresses (synced)"},
|
||||
{3, 0, 9, 0, false, "3 payment methods, 9 other suggestions"},
|
||||
{0, 1, 1, 0, false, "1 address, 1 other suggestion"},
|
||||
{9, 6, 3, 0, false, "9 payment methods, 6 addresses, 3 others"},
|
||||
{4, 2, 1, 0, false, "4 payment methods, 2 addresses, 1 other"},
|
||||
{4, 2, 1, 0, true, "4 payment methods, 2 addresses, 1 other (synced)"},
|
||||
{1, 0, 0, 1, false, "1 payment method; 1 suggestion (device only)"},
|
||||
{1, 1, 0, 2, true,
|
||||
"1 payment method, 1 address (synced); 2 suggestions (device only)"},
|
||||
{0, 0, 0, false, "None"},
|
||||
{0, 0, 0, true, "None"},
|
||||
{1, 0, 0, false, "1 payment method"},
|
||||
{0, 5, 0, false, "5 addresses"},
|
||||
{0, 0, 1, false, "1 suggestion"},
|
||||
{0, 0, 2, false, "2 suggestions"},
|
||||
{0, 0, 2, true, "2 suggestions (synced)"},
|
||||
{4, 7, 0, false, "4 payment methods, 7 addresses"},
|
||||
{4, 7, 0, true, "4 payment methods, 7 addresses (synced)"},
|
||||
{3, 0, 9, false, "3 payment methods, 9 other suggestions"},
|
||||
{0, 1, 1, false, "1 address, 1 other suggestion"},
|
||||
{9, 6, 3, false, "9 payment methods, 6 addresses, 3 others"},
|
||||
{4, 2, 1, false, "4 payment methods, 2 addresses, 1 other"},
|
||||
{4, 2, 1, true, "4 payment methods, 2 addresses, 1 other (synced)"},
|
||||
};
|
||||
|
||||
for (const TestCase& test_case : kTestCases) {
|
||||
AutofillCounter::AutofillResult result(
|
||||
&counter, test_case.num_suggestions, test_case.num_credit_cards,
|
||||
test_case.num_addresses, test_case.num_user_annotation_entries,
|
||||
test_case.sync_enabled);
|
||||
test_case.num_addresses, test_case.sync_enabled);
|
||||
|
||||
SCOPED_TRACE(
|
||||
base::StringPrintf("Test params: %d payment method(s), "
|
||||
|
@ -34,11 +34,9 @@ namespace browsing_data {
|
||||
AutofillCounter::AutofillCounter(
|
||||
autofill::PersonalDataManager* personal_data_manager,
|
||||
scoped_refptr<autofill::AutofillWebDataService> web_data_service,
|
||||
user_annotations::UserAnnotationsService* user_annotations_service,
|
||||
syncer::SyncService* sync_service)
|
||||
: personal_data_manager_(personal_data_manager),
|
||||
web_data_service_(web_data_service),
|
||||
user_annotations_service_(user_annotations_service),
|
||||
sync_tracker_(this, sync_service),
|
||||
suggestions_query_(0),
|
||||
num_suggestions_(0) {}
|
||||
@ -118,19 +116,6 @@ void AutofillCounter::Count() {
|
||||
start, end,
|
||||
base::BindOnce(&AutofillCounter::OnWebDataServiceRequestDone,
|
||||
weak_ptr_factory_.GetWeakPtr()));
|
||||
|
||||
num_user_annotations_.reset();
|
||||
|
||||
// Not all platforms support user annotations, for those the service is not
|
||||
// provided and the value is set to 0 immediately.
|
||||
if (user_annotations_service_) {
|
||||
user_annotations_service_->GetCountOfValuesContainedBetween(
|
||||
start, end,
|
||||
base::BindOnce(&AutofillCounter::OnUserAnnotationsServiceResponse,
|
||||
user_annotations_requirest_weak_factory_.GetWeakPtr()));
|
||||
} else {
|
||||
num_user_annotations_ = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void AutofillCounter::OnWebDataServiceRequestDone(
|
||||
@ -152,42 +137,31 @@ void AutofillCounter::OnWebDataServiceRequestDone(
|
||||
ReportResultIfReady();
|
||||
}
|
||||
|
||||
void AutofillCounter::OnUserAnnotationsServiceResponse(
|
||||
int num_user_annotations) {
|
||||
num_user_annotations_ = num_user_annotations;
|
||||
|
||||
ReportResultIfReady();
|
||||
}
|
||||
|
||||
void AutofillCounter::CancelAllRequests() {
|
||||
if (suggestions_query_)
|
||||
if (suggestions_query_) {
|
||||
web_data_service_->CancelRequest(suggestions_query_);
|
||||
|
||||
user_annotations_requirest_weak_factory_.InvalidateWeakPtrs();
|
||||
}
|
||||
}
|
||||
|
||||
void AutofillCounter::ReportResultIfReady() {
|
||||
if (num_suggestions_.has_value() && num_user_annotations_.has_value()) {
|
||||
if (num_suggestions_.has_value()) {
|
||||
auto reported_result = std::make_unique<AutofillResult>(
|
||||
this, *num_suggestions_, num_credit_cards_, num_addresses_,
|
||||
*num_user_annotations_, sync_tracker_.IsSyncActive());
|
||||
sync_tracker_.IsSyncActive());
|
||||
ReportResult(std::move(reported_result));
|
||||
}
|
||||
}
|
||||
|
||||
// AutofillCounter::AutofillResult ---------------------------------------------
|
||||
|
||||
AutofillCounter::AutofillResult::AutofillResult(
|
||||
const AutofillCounter* source,
|
||||
ResultInt num_suggestions,
|
||||
ResultInt num_credit_cards,
|
||||
ResultInt num_addresses,
|
||||
ResultInt num_user_annotation_entries,
|
||||
bool autofill_sync_enabled_)
|
||||
AutofillCounter::AutofillResult::AutofillResult(const AutofillCounter* source,
|
||||
ResultInt num_suggestions,
|
||||
ResultInt num_credit_cards,
|
||||
ResultInt num_addresses,
|
||||
bool autofill_sync_enabled_)
|
||||
: SyncResult(source, num_suggestions, autofill_sync_enabled_),
|
||||
num_credit_cards_(num_credit_cards),
|
||||
num_addresses_(num_addresses),
|
||||
num_user_annotation_entries_(num_user_annotation_entries) {}
|
||||
num_addresses_(num_addresses) {}
|
||||
|
||||
AutofillCounter::AutofillResult::~AutofillResult() = default;
|
||||
|
||||
|
@ -12,7 +12,6 @@
|
||||
#include "components/autofill/core/browser/webdata/autofill_webdata_service.h"
|
||||
#include "components/browsing_data/core/counters/browsing_data_counter.h"
|
||||
#include "components/browsing_data/core/counters/sync_tracker.h"
|
||||
#include "components/user_annotations/user_annotations_service.h"
|
||||
|
||||
namespace autofill {
|
||||
class AutofillWebDataService;
|
||||
@ -29,7 +28,6 @@ class AutofillCounter : public browsing_data::BrowsingDataCounter {
|
||||
ResultInt num_suggestions,
|
||||
ResultInt num_credit_cards,
|
||||
ResultInt num_addresses,
|
||||
ResultInt num_user_annotation_entries,
|
||||
bool autofill_sync_enabled_);
|
||||
|
||||
AutofillResult(const AutofillResult&) = delete;
|
||||
@ -39,20 +37,15 @@ class AutofillCounter : public browsing_data::BrowsingDataCounter {
|
||||
|
||||
ResultInt num_credit_cards() const { return num_credit_cards_; }
|
||||
ResultInt num_addresses() const { return num_addresses_; }
|
||||
ResultInt num_user_annotation_entries() const {
|
||||
return num_user_annotation_entries_;
|
||||
}
|
||||
|
||||
private:
|
||||
ResultInt num_credit_cards_;
|
||||
ResultInt num_addresses_;
|
||||
ResultInt num_user_annotation_entries_;
|
||||
};
|
||||
|
||||
AutofillCounter(
|
||||
autofill::PersonalDataManager* personal_data_manager,
|
||||
scoped_refptr<autofill::AutofillWebDataService> web_data_service,
|
||||
user_annotations::UserAnnotationsService* user_annotations_service,
|
||||
syncer::SyncService* sync_service);
|
||||
|
||||
AutofillCounter(const AutofillCounter&) = delete;
|
||||
@ -82,40 +75,30 @@ class AutofillCounter : public browsing_data::BrowsingDataCounter {
|
||||
void OnWebDataServiceRequestDone(WebDataServiceBase::Handle handle,
|
||||
std::unique_ptr<WDTypedResult> result);
|
||||
|
||||
void OnUserAnnotationsServiceResponse(int num_user_annotations);
|
||||
|
||||
// Cancel all pending requests to AutofillWebdataService.
|
||||
void CancelAllRequests();
|
||||
|
||||
// This methods checks whether the asynchronous pieces (`num_suggestions_`
|
||||
// and `num_user_annotations_` for now) are ready, and if they are, creates
|
||||
// a `AutofillResult` and calls `ReportResult()`. It should be called each
|
||||
// time the report data readiness may change.
|
||||
// This methods checks whether the asynchronous pieces (`num_suggestions_` for
|
||||
// now) are ready, and if they are, creates a `AutofillResult` and calls
|
||||
// `ReportResult()`. It should be called each time the report data readiness
|
||||
// may change.
|
||||
void ReportResultIfReady();
|
||||
|
||||
base::ThreadChecker thread_checker_;
|
||||
|
||||
raw_ptr<autofill::PersonalDataManager> personal_data_manager_;
|
||||
scoped_refptr<autofill::AutofillWebDataService> web_data_service_;
|
||||
raw_ptr<user_annotations::UserAnnotationsService> user_annotations_service_;
|
||||
SyncTracker sync_tracker_;
|
||||
|
||||
WebDataServiceBase::Handle suggestions_query_;
|
||||
|
||||
std::optional<ResultInt> num_suggestions_;
|
||||
std::optional<ResultInt> num_user_annotations_;
|
||||
ResultInt num_credit_cards_;
|
||||
ResultInt num_addresses_;
|
||||
|
||||
base::Time period_start_for_testing_;
|
||||
base::Time period_end_for_testing_;
|
||||
|
||||
// UserAnnotationsService doesn't provide API for canceling requests. Pointers
|
||||
// from this factory are used to bind to its request callbacks, which allows
|
||||
// to cancel them if needed.
|
||||
base::WeakPtrFactory<AutofillCounter>
|
||||
user_annotations_requirest_weak_factory_{this};
|
||||
|
||||
base::WeakPtrFactory<AutofillCounter> weak_ptr_factory_{this};
|
||||
};
|
||||
|
||||
|
@ -1,84 +0,0 @@
|
||||
# Copyright 2024 The Chromium Authors
|
||||
# Use of this source code is governed by a BSD-style license that can be
|
||||
# found in the LICENSE file.
|
||||
|
||||
import("//components/optimization_guide/features.gni")
|
||||
|
||||
source_set("types") {
|
||||
sources = [
|
||||
"user_annotations_types.cc",
|
||||
"user_annotations_types.h",
|
||||
]
|
||||
public_deps = [
|
||||
"//base",
|
||||
"//components/optimization_guide/proto:optimization_guide_proto",
|
||||
]
|
||||
}
|
||||
|
||||
static_library("user_annotations") {
|
||||
sources = [
|
||||
"form_submission_handler.cc",
|
||||
"form_submission_handler.h",
|
||||
"user_annotations_database.cc",
|
||||
"user_annotations_database.h",
|
||||
"user_annotations_features.cc",
|
||||
"user_annotations_features.h",
|
||||
"user_annotations_service.cc",
|
||||
"user_annotations_service.h",
|
||||
"user_annotations_switches.cc",
|
||||
"user_annotations_switches.h",
|
||||
"user_annotations_types.h",
|
||||
]
|
||||
|
||||
public_deps = [
|
||||
":types",
|
||||
"//base",
|
||||
"//components/autofill/core/browser",
|
||||
"//components/autofill/core/common",
|
||||
"//components/keyed_service/core",
|
||||
"//components/optimization_guide/core",
|
||||
"//components/optimization_guide/proto:optimization_guide_proto",
|
||||
]
|
||||
|
||||
deps = [
|
||||
"//components/autofill_ai/core/browser:features",
|
||||
"//components/os_crypt/async/browser",
|
||||
"//components/os_crypt/async/common",
|
||||
"//sql",
|
||||
"//url",
|
||||
]
|
||||
}
|
||||
|
||||
static_library("test_support") {
|
||||
testonly = true
|
||||
sources = [
|
||||
"test_user_annotations_service.cc",
|
||||
"test_user_annotations_service.h",
|
||||
]
|
||||
|
||||
deps = [ ":user_annotations" ]
|
||||
}
|
||||
|
||||
source_set("unit_tests") {
|
||||
testonly = true
|
||||
sources = [
|
||||
"user_annotations_database_unittest.cc",
|
||||
"user_annotations_features_unittest.cc",
|
||||
"user_annotations_switches_unittest.cc",
|
||||
]
|
||||
if (build_with_model_execution) {
|
||||
sources += [ "user_annotations_service_unittest.cc" ]
|
||||
}
|
||||
deps = [
|
||||
":test_support",
|
||||
":user_annotations",
|
||||
"//base/test:test_support",
|
||||
"//components/autofill/core/browser:test_support",
|
||||
"//components/autofill_ai/core/browser:features",
|
||||
"//components/optimization_guide/core:test_support",
|
||||
"//components/os_crypt/async/browser:test_support",
|
||||
"//components/prefs:test_support",
|
||||
"//testing/gtest",
|
||||
"//url",
|
||||
]
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
include_rules = [
|
||||
"+components/autofill/core/browser",
|
||||
"+components/autofill/core/common",
|
||||
"+components/autofill_ai/core/browser",
|
||||
"+components/keyed_service/core",
|
||||
"+components/optimization_guide/core",
|
||||
"+components/optimization_guide/proto",
|
||||
"+components/os_crypt/async",
|
||||
"+components/prefs",
|
||||
"+sql",
|
||||
];
|
@ -1 +0,0 @@
|
||||
mixins: "//components/optimization_guide/COMMON_METADATA"
|
@ -1 +0,0 @@
|
||||
file://components/optimization_guide/OWNERS
|
@ -1,195 +0,0 @@
|
||||
// Copyright 2024 The Chromium Authors
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "components/user_annotations/form_submission_handler.h"
|
||||
|
||||
#include <optional>
|
||||
|
||||
#include "base/metrics/histogram_functions.h"
|
||||
#include "components/autofill/core/browser/form_processing/optimization_guide_proto_util.h"
|
||||
#include "components/autofill/core/browser/form_structure.h"
|
||||
#include "components/optimization_guide/core/model_quality/model_execution_logging_wrappers.h"
|
||||
#include "components/optimization_guide/core/model_quality/model_quality_log_entry.h"
|
||||
#include "components/optimization_guide/core/optimization_guide_util.h"
|
||||
#include "components/optimization_guide/proto/features/forms_annotations.pb.h"
|
||||
#include "components/user_annotations/user_annotations_features.h"
|
||||
#include "components/user_annotations/user_annotations_service.h"
|
||||
|
||||
namespace user_annotations {
|
||||
|
||||
FormSubmissionHandler::FormSubmissionHandler(
|
||||
UserAnnotationsService* user_annotations_service,
|
||||
const GURL& url,
|
||||
const std::string& title,
|
||||
optimization_guide::proto::AXTreeUpdate ax_tree_update,
|
||||
std::unique_ptr<autofill::FormStructure> form,
|
||||
ImportFormCallback callback)
|
||||
: url_(url),
|
||||
title_(title),
|
||||
ax_tree_update_(std::move(ax_tree_update)),
|
||||
form_(std::move(form)),
|
||||
callback_(std::move(callback)),
|
||||
user_annotations_service_(user_annotations_service) {}
|
||||
|
||||
FormSubmissionHandler::~FormSubmissionHandler() = default;
|
||||
|
||||
void FormSubmissionHandler::Start() {
|
||||
completion_timer_.Start(
|
||||
FROM_HERE, GetFormSubmissionCompletionTimeout(),
|
||||
base::BindOnce(&FormSubmissionHandler::OnCompletionTimeout,
|
||||
weak_ptr_factory_.GetWeakPtr()));
|
||||
user_annotations_service_->RetrieveAllEntries(
|
||||
base::BindOnce(&FormSubmissionHandler::ExecuteModelWithEntries,
|
||||
weak_ptr_factory_.GetWeakPtr()));
|
||||
}
|
||||
|
||||
void FormSubmissionHandler::OnCompletionTimeout() {
|
||||
// TODO: 372715386 - Handle the timeout and notify the save prompt UX.
|
||||
}
|
||||
|
||||
void FormSubmissionHandler::ExecuteModelWithEntries(
|
||||
UserAnnotationsEntries entries) {
|
||||
// Construct request.
|
||||
optimization_guide::proto::FormsAnnotationsRequest request;
|
||||
optimization_guide::proto::PageContext* page_context =
|
||||
request.mutable_page_context();
|
||||
page_context->set_url(url_.spec());
|
||||
page_context->set_title(title_);
|
||||
*page_context->mutable_ax_tree_data() = std::move(ax_tree_update_);
|
||||
*request.mutable_form_data() = autofill::ToFormDataProto(*form_);
|
||||
*request.mutable_entries() = {std::make_move_iterator(entries.begin()),
|
||||
std::make_move_iterator(entries.end())};
|
||||
optimization_guide::ModelExecutionCallbackWithLogging<
|
||||
optimization_guide::proto::FormsAnnotationsLoggingData>
|
||||
wrapper_callback = base::BindOnce(&FormSubmissionHandler::OnModelExecuted,
|
||||
weak_ptr_factory_.GetWeakPtr());
|
||||
optimization_guide::ExecuteModelWithLogging(
|
||||
user_annotations_service_->model_executor(),
|
||||
optimization_guide::ModelBasedCapabilityKey::kFormsAnnotations, request,
|
||||
std::nullopt, std::move(wrapper_callback));
|
||||
}
|
||||
|
||||
void FormSubmissionHandler::OnModelExecuted(
|
||||
optimization_guide::OptimizationGuideModelExecutionResult result,
|
||||
std::unique_ptr<optimization_guide::proto::FormsAnnotationsLoggingData>
|
||||
logging_data) {
|
||||
CHECK(logging_data);
|
||||
auto log_entry = std::make_unique<optimization_guide::ModelQualityLogEntry>(
|
||||
user_annotations_service_->logs_uploader());
|
||||
*log_entry->log_ai_data_request()->mutable_forms_annotations() =
|
||||
*logging_data;
|
||||
if (!result.response.has_value()) {
|
||||
SendFormSubmissionResult(
|
||||
base::unexpected(UserAnnotationsExecutionResult::kResponseError),
|
||||
std::move(log_entry));
|
||||
return;
|
||||
}
|
||||
|
||||
std::optional<optimization_guide::proto::FormsAnnotationsResponse>
|
||||
maybe_response = optimization_guide::ParsedAnyMetadata<
|
||||
optimization_guide::proto::FormsAnnotationsResponse>(
|
||||
result.response.value());
|
||||
if (!maybe_response) {
|
||||
SendFormSubmissionResult(
|
||||
base::unexpected(UserAnnotationsExecutionResult::kResponseMalformed),
|
||||
std::move(log_entry));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!user_annotations_service_->IsDatabaseReady()) {
|
||||
SendFormSubmissionResult(
|
||||
base::unexpected(UserAnnotationsExecutionResult::kCryptNotInitialized),
|
||||
std::move(log_entry));
|
||||
return;
|
||||
}
|
||||
|
||||
SendFormSubmissionResult(base::ok(maybe_response.value()),
|
||||
std::move(log_entry));
|
||||
}
|
||||
|
||||
void FormSubmissionHandler::SendFormSubmissionResult(
|
||||
FormSubmissionResult result,
|
||||
std::unique_ptr<optimization_guide::ModelQualityLogEntry> log_entry) {
|
||||
base::UmaHistogramEnumeration(
|
||||
"UserAnnotations.AddFormSubmissionResult",
|
||||
result.error_or(UserAnnotationsExecutionResult::kSuccess));
|
||||
if (!result.has_value()) {
|
||||
CHECK_NE(result.error(), UserAnnotationsExecutionResult::kSuccess);
|
||||
optimization_guide::ModelQualityLogEntry::Drop(std::move(log_entry));
|
||||
if (callback_) {
|
||||
std::move(callback_).Run(
|
||||
std::move(form_),
|
||||
/*form_annotation_response=*/nullptr,
|
||||
/*prompt_acceptance_callback=*/base::DoNothing());
|
||||
}
|
||||
NotifyCompletion();
|
||||
return;
|
||||
}
|
||||
|
||||
if (result->upserted_entries().empty()) {
|
||||
optimization_guide::ModelQualityLogEntry::Drop(std::move(log_entry));
|
||||
std::move(callback_).Run(std::move(form_),
|
||||
/*form_annotation_response=*/nullptr,
|
||||
/*prompt_acceptance_callback=*/base::DoNothing());
|
||||
NotifyCompletion();
|
||||
return;
|
||||
}
|
||||
auto form_annotation_response = std::make_unique<FormAnnotationResponse>(
|
||||
UserAnnotationsEntries(result->upserted_entries().begin(),
|
||||
result->upserted_entries().end()),
|
||||
log_entry->model_execution_id());
|
||||
std::move(callback_).Run(
|
||||
std::move(form_), std::move(form_annotation_response),
|
||||
base::BindOnce(&FormSubmissionHandler::OnImportFormConfirmation,
|
||||
weak_ptr_factory_.GetWeakPtr(), std::move(result),
|
||||
std::move(log_entry)));
|
||||
}
|
||||
|
||||
void FormSubmissionHandler::OnImportFormConfirmation(
|
||||
FormSubmissionResult result,
|
||||
std::unique_ptr<optimization_guide::ModelQualityLogEntry> log_entry,
|
||||
PromptAcceptanceResult prompt_acceptance_result) {
|
||||
if (!prompt_acceptance_result.did_user_interact &&
|
||||
!prompt_acceptance_result.did_thumbs_down_triggered &&
|
||||
!prompt_acceptance_result.did_thumbs_up_triggered) {
|
||||
// Drop the log entry, when the user did no interaction with the save prompt
|
||||
// bubble.
|
||||
optimization_guide::ModelQualityLogEntry::Drop(std::move(log_entry));
|
||||
NotifyCompletion();
|
||||
return;
|
||||
}
|
||||
if (log_entry) {
|
||||
auto* quality_entry = log_entry->log_ai_data_request()
|
||||
->mutable_forms_annotations()
|
||||
->mutable_quality();
|
||||
if (prompt_acceptance_result.did_thumbs_down_triggered) {
|
||||
quality_entry->set_user_feedback(
|
||||
optimization_guide::proto::UserFeedback::USER_FEEDBACK_THUMBS_DOWN);
|
||||
} else if (prompt_acceptance_result.did_thumbs_up_triggered) {
|
||||
quality_entry->set_user_feedback(
|
||||
optimization_guide::proto::UserFeedback::USER_FEEDBACK_THUMBS_UP);
|
||||
}
|
||||
quality_entry->set_save_prompt_action(
|
||||
prompt_acceptance_result.prompt_was_accepted
|
||||
? optimization_guide::proto::FormsAnnotationsSavePromptAction::
|
||||
FORMS_ANNOTATIONS_SAVE_PROMPT_ACTION_ACCEPTED
|
||||
: optimization_guide::proto::FormsAnnotationsSavePromptAction::
|
||||
FORMS_ANNOTATIONS_SAVE_PROMPT_ACTION_REJECTED);
|
||||
optimization_guide::ModelQualityLogEntry::Upload(std::move(log_entry));
|
||||
}
|
||||
|
||||
if (!prompt_acceptance_result.prompt_was_accepted) {
|
||||
NotifyCompletion();
|
||||
return;
|
||||
}
|
||||
user_annotations_service_->SaveEntries(result.value());
|
||||
NotifyCompletion();
|
||||
}
|
||||
|
||||
void FormSubmissionHandler::NotifyCompletion() {
|
||||
completion_timer_.Stop();
|
||||
user_annotations_service_->OnFormSubmissionComplete();
|
||||
}
|
||||
|
||||
} // namespace user_annotations
|
@ -1,101 +0,0 @@
|
||||
// Copyright 2024 The Chromium Authors
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef COMPONENTS_USER_ANNOTATIONS_FORM_SUBMISSION_HANDLER_H_
|
||||
#define COMPONENTS_USER_ANNOTATIONS_FORM_SUBMISSION_HANDLER_H_
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "base/memory/raw_ptr.h"
|
||||
#include "base/memory/weak_ptr.h"
|
||||
#include "base/timer/timer.h"
|
||||
#include "base/types/expected.h"
|
||||
#include "components/optimization_guide/proto/features/forms_annotations.pb.h"
|
||||
#include "components/user_annotations/user_annotations_service.h"
|
||||
#include "components/user_annotations/user_annotations_types.h"
|
||||
|
||||
namespace autofill {
|
||||
class FormStructure;
|
||||
} // namespace autofill
|
||||
|
||||
namespace optimization_guide {
|
||||
class OptimizationGuideDecider;
|
||||
namespace proto {
|
||||
class AXTreeUpdate;
|
||||
} // namespace proto
|
||||
} // namespace optimization_guide
|
||||
|
||||
namespace user_annotations {
|
||||
|
||||
// Handles the various stages of one form submission. First, the existing
|
||||
// annotations are retrieved from database, and sent along with the form entries
|
||||
// to the form annotations model execution. Then the returned annotations are
|
||||
// sent for user confirmation, before they are persisted to the database.
|
||||
class FormSubmissionHandler {
|
||||
public:
|
||||
FormSubmissionHandler(UserAnnotationsService* user_annotations_service,
|
||||
const GURL& url,
|
||||
const std::string& title,
|
||||
optimization_guide::proto::AXTreeUpdate ax_tree_update,
|
||||
std::unique_ptr<autofill::FormStructure> form,
|
||||
ImportFormCallback callback);
|
||||
~FormSubmissionHandler();
|
||||
|
||||
FormSubmissionHandler(const FormSubmissionHandler&) = delete;
|
||||
FormSubmissionHandler& operator=(const FormSubmissionHandler&) = delete;
|
||||
|
||||
// Starts the form submission process.
|
||||
void Start();
|
||||
|
||||
private:
|
||||
using FormSubmissionResult =
|
||||
base::expected<optimization_guide::proto::FormsAnnotationsResponse,
|
||||
UserAnnotationsExecutionResult>;
|
||||
|
||||
void ExecuteModelWithEntries(UserAnnotationsEntries entries);
|
||||
|
||||
// Processes model execution response. Invoked when model execution has been
|
||||
// received.
|
||||
void OnModelExecuted(
|
||||
optimization_guide::OptimizationGuideModelExecutionResult result,
|
||||
std::unique_ptr<optimization_guide::proto::FormsAnnotationsLoggingData>
|
||||
logging_data);
|
||||
|
||||
// Sends the result of form submission.
|
||||
void SendFormSubmissionResult(
|
||||
FormSubmissionResult result,
|
||||
std::unique_ptr<optimization_guide::ModelQualityLogEntry> log_entry);
|
||||
|
||||
// Called when decision has been made whether to import form entries.
|
||||
// `prompt_was_accepted` is the user decision, and `entries` will be
|
||||
// persisted to database when true.
|
||||
void OnImportFormConfirmation(
|
||||
FormSubmissionResult result,
|
||||
std::unique_ptr<optimization_guide::ModelQualityLogEntry> log_entry,
|
||||
PromptAcceptanceResult prompt_acceptance_result);
|
||||
|
||||
// Called when the timeout is triggered.
|
||||
void OnCompletionTimeout();
|
||||
|
||||
// Notifies the service that the form submission stages have been complete.
|
||||
void NotifyCompletion();
|
||||
|
||||
GURL url_;
|
||||
std::string title_;
|
||||
optimization_guide::proto::AXTreeUpdate ax_tree_update_;
|
||||
std::unique_ptr<autofill::FormStructure> form_;
|
||||
ImportFormCallback callback_;
|
||||
|
||||
// Guaranteed to outlive `this`.
|
||||
raw_ptr<UserAnnotationsService> user_annotations_service_;
|
||||
|
||||
// Timer to enforce timeout on the form submission completion.
|
||||
base::OneShotTimer completion_timer_;
|
||||
|
||||
base::WeakPtrFactory<FormSubmissionHandler> weak_ptr_factory_{this};
|
||||
};
|
||||
|
||||
} // namespace user_annotations
|
||||
|
||||
#endif // COMPONENTS_USER_ANNOTATIONS_FORM_SUBMISSION_HANDLER_H_
|
@ -1,107 +0,0 @@
|
||||
// Copyright 2024 The Chromium Authors
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "components/user_annotations/test_user_annotations_service.h"
|
||||
|
||||
#include "base/containers/contains.h"
|
||||
#include "base/strings/utf_string_conversions.h"
|
||||
#include "components/autofill/core/browser/form_structure.h"
|
||||
#include "components/autofill/core/common/form_data.h"
|
||||
#include "components/autofill/core/common/form_field_data.h"
|
||||
#include "components/optimization_guide/proto/features/common_quality_data.pb.h"
|
||||
#include "components/user_annotations/user_annotations_types.h"
|
||||
|
||||
namespace user_annotations {
|
||||
|
||||
TestUserAnnotationsService::TestUserAnnotationsService() = default;
|
||||
TestUserAnnotationsService::~TestUserAnnotationsService() = default;
|
||||
|
||||
void TestUserAnnotationsService::ReplaceAllEntries(
|
||||
UserAnnotationsEntries entries) {
|
||||
entries_ = std::move(entries);
|
||||
}
|
||||
|
||||
void TestUserAnnotationsService::RemoveEntry(EntryID entry_id,
|
||||
base::OnceClosure callback) {
|
||||
size_t count = 0;
|
||||
for (const optimization_guide::proto::UserAnnotationsEntry& entry :
|
||||
entries_) {
|
||||
if (entry_id == entry.entry_id()) {
|
||||
entries_.erase(entries_.begin() + count);
|
||||
break;
|
||||
}
|
||||
count++;
|
||||
}
|
||||
std::move(callback).Run();
|
||||
}
|
||||
|
||||
void TestUserAnnotationsService::RemoveAllEntries(base::OnceClosure callback) {
|
||||
entries_.clear();
|
||||
std::move(callback).Run();
|
||||
}
|
||||
|
||||
void TestUserAnnotationsService::AddFormSubmission(
|
||||
const GURL& url,
|
||||
const std::string& title,
|
||||
optimization_guide::proto::AXTreeUpdate ax_tree_update,
|
||||
std::unique_ptr<autofill::FormStructure> form,
|
||||
ImportFormCallback callback) {
|
||||
if (should_import_form_data_) {
|
||||
int64_t entry_id = 0;
|
||||
for (const std::unique_ptr<autofill::AutofillField>& field :
|
||||
form->fields()) {
|
||||
optimization_guide::proto::UserAnnotationsEntry entry;
|
||||
entry.set_entry_id(entry_id++);
|
||||
entry.set_key(base::UTF16ToUTF8(field->label()));
|
||||
entry.set_value(
|
||||
base::UTF16ToUTF8(field->value(autofill::ValueSemantics::kCurrent)));
|
||||
entries_.emplace_back(std::move(entry));
|
||||
}
|
||||
std::move(callback).Run(std::move(form),
|
||||
std::make_unique<FormAnnotationResponse>(
|
||||
entries_, /*model_execution_id=*/std::string()),
|
||||
/*prompt_acceptance_callback=*/base::DoNothing());
|
||||
return;
|
||||
}
|
||||
std::move(callback).Run(std::move(form), /*form_annotation_response=*/nullptr,
|
||||
/*prompt_acceptance_callback=*/base::DoNothing());
|
||||
}
|
||||
|
||||
void TestUserAnnotationsService::RetrieveAllEntries(
|
||||
base::OnceCallback<void(UserAnnotationsEntries)> callback) {
|
||||
count_entries_retrieved_++;
|
||||
std::move(callback).Run(entries_);
|
||||
}
|
||||
|
||||
void TestUserAnnotationsService::AddHostToFormAnnotationsAllowlist(
|
||||
const std::string& host) {
|
||||
allowed_forms_annotations_hosts_.insert(host);
|
||||
}
|
||||
|
||||
bool TestUserAnnotationsService::ShouldAddFormSubmissionForURL(
|
||||
const GURL& url) {
|
||||
return base::Contains(allowed_forms_annotations_hosts_, url.host());
|
||||
}
|
||||
|
||||
void TestUserAnnotationsService::RemoveAnnotationsInRange(
|
||||
const base::Time& delete_begin,
|
||||
const base::Time& delete_end) {
|
||||
last_received_remove_annotations_in_range_ =
|
||||
std::make_pair(delete_begin, delete_end);
|
||||
}
|
||||
|
||||
void TestUserAnnotationsService::GetCountOfValuesContainedBetween(
|
||||
base::Time,
|
||||
base::Time,
|
||||
base::OnceCallback<void(int)> callback) {
|
||||
std::move(callback).Run(entries_.size());
|
||||
}
|
||||
|
||||
void TestUserAnnotationsService::SaveAutofillProfile(
|
||||
const autofill::AutofillProfile& autofill_profile,
|
||||
base::OnceCallback<void(UserAnnotationsExecutionResult)> callback) {
|
||||
std::move(callback).Run(UserAnnotationsExecutionResult::kSuccess);
|
||||
}
|
||||
|
||||
} // namespace user_annotations
|
@ -1,95 +0,0 @@
|
||||
// Copyright 2024 The Chromium Authors
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef COMPONENTS_USER_ANNOTATIONS_TEST_USER_ANNOTATIONS_SERVICE_H_
|
||||
#define COMPONENTS_USER_ANNOTATIONS_TEST_USER_ANNOTATIONS_SERVICE_H_
|
||||
|
||||
#include <set>
|
||||
#include <vector>
|
||||
|
||||
#include "components/user_annotations/user_annotations_service.h"
|
||||
#include "components/user_annotations/user_annotations_types.h"
|
||||
|
||||
namespace autofill {
|
||||
class FormStructure;
|
||||
}
|
||||
|
||||
namespace optimization_guide::proto {
|
||||
class UserAnnotationsEntry;
|
||||
} // namespace optimization_guide::proto
|
||||
|
||||
namespace user_annotations {
|
||||
|
||||
class TestUserAnnotationsService : public UserAnnotationsService {
|
||||
public:
|
||||
TestUserAnnotationsService();
|
||||
TestUserAnnotationsService(const TestUserAnnotationsService&) = delete;
|
||||
TestUserAnnotationsService& operator=(const TestUserAnnotationsService&) =
|
||||
delete;
|
||||
~TestUserAnnotationsService() override;
|
||||
|
||||
// Replaces all entries in the service with `entries`.
|
||||
void ReplaceAllEntries(UserAnnotationsEntries entries);
|
||||
|
||||
// `AddFormSubmission()` will only import form data if
|
||||
// `should_import_form_data` is set to `true`.
|
||||
void SetShouldImportFormData(bool should_import_form_data) {
|
||||
should_import_form_data_ = should_import_form_data;
|
||||
}
|
||||
|
||||
// Adds `host` to set of hosts that forms annotations are allowed on.
|
||||
void AddHostToFormAnnotationsAllowlist(const std::string& host);
|
||||
|
||||
// UserAnnotationsService:
|
||||
bool ShouldAddFormSubmissionForURL(const GURL& url) override;
|
||||
void AddFormSubmission(const GURL& url,
|
||||
const std::string& title,
|
||||
optimization_guide::proto::AXTreeUpdate ax_tree_update,
|
||||
std::unique_ptr<autofill::FormStructure> form,
|
||||
ImportFormCallback callback) override;
|
||||
void RetrieveAllEntries(
|
||||
base::OnceCallback<void(UserAnnotationsEntries)> callback) override;
|
||||
void RemoveEntry(EntryID entry_id, base::OnceClosure callback) override;
|
||||
void RemoveAllEntries(base::OnceClosure callback) override;
|
||||
void RemoveAnnotationsInRange(const base::Time& delete_begin,
|
||||
const base::Time& delete_end) override;
|
||||
|
||||
// Returns the number of entries set via `ReplaceAllEntries()` ignoring
|
||||
// the `begin` and `end` arguments.
|
||||
void GetCountOfValuesContainedBetween(
|
||||
base::Time begin,
|
||||
base::Time end,
|
||||
base::OnceCallback<void(int)> callback) override;
|
||||
size_t count_entries_retrieved() const { return count_entries_retrieved_; }
|
||||
|
||||
std::pair<base::Time, base::Time> last_received_remove_annotations_in_range()
|
||||
const {
|
||||
return last_received_remove_annotations_in_range_;
|
||||
}
|
||||
|
||||
void SaveAutofillProfile(
|
||||
const autofill::AutofillProfile& autofill_profile,
|
||||
base::OnceCallback<void(UserAnnotationsExecutionResult)> callback)
|
||||
override;
|
||||
|
||||
private:
|
||||
// An in-memory representation of the "database" of user annotation entries.
|
||||
std::vector<optimization_guide::proto::UserAnnotationsEntry> entries_;
|
||||
|
||||
// Used in `AddFormSubmission()` to decide if form data should be imported.
|
||||
bool should_import_form_data_ = true;
|
||||
|
||||
// Hosts allowed for forms annotations.
|
||||
std::set<std::string> allowed_forms_annotations_hosts_;
|
||||
|
||||
// Saves the last call for `RemoveAnnotationsInRange`.
|
||||
std::pair<base::Time, base::Time> last_received_remove_annotations_in_range_;
|
||||
|
||||
// The number of times entries have been retrieved.
|
||||
size_t count_entries_retrieved_ = 0;
|
||||
};
|
||||
|
||||
} // namespace user_annotations
|
||||
|
||||
#endif // COMPONENTS_USER_ANNOTATIONS_TEST_USER_ANNOTATIONS_SERVICE_H_
|
@ -1,237 +0,0 @@
|
||||
// Copyright 2024 The Chromium Authors
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "components/user_annotations/user_annotations_database.h"
|
||||
|
||||
#include <utility>
|
||||
|
||||
#include "base/files/file_path.h"
|
||||
#include "base/metrics/histogram_functions.h"
|
||||
#include "base/sequence_checker.h"
|
||||
#include "build/build_config.h"
|
||||
#include "components/os_crypt/async/common/encryptor.h"
|
||||
#include "components/user_annotations/user_annotations_features.h"
|
||||
#include "components/user_annotations/user_annotations_service.h"
|
||||
#include "sql/init_status.h"
|
||||
#include "sql/meta_table.h"
|
||||
#include "sql/statement.h"
|
||||
#include "sql/transaction.h"
|
||||
|
||||
namespace user_annotations {
|
||||
|
||||
inline constexpr base::FilePath::CharType kUserAnnotationsName[] =
|
||||
FILE_PATH_LITERAL("UserAnnotations");
|
||||
|
||||
// These database versions should roll together unless we develop migrations.
|
||||
constexpr int kLowestSupportedDatabaseVersion = 1;
|
||||
constexpr int kCurrentDatabaseVersion = 1;
|
||||
|
||||
namespace {
|
||||
|
||||
[[nodiscard]] bool CreateTable(sql::Database& db) {
|
||||
static constexpr char kSqlCreateTablePassages[] =
|
||||
"CREATE TABLE IF NOT EXISTS entries("
|
||||
// The ID of the entry.
|
||||
"entry_id INTEGER PRIMARY KEY AUTOINCREMENT,"
|
||||
// The key of the entry.
|
||||
"key VARCHAR NOT NULL,"
|
||||
// An opaque encrypted blob of value.
|
||||
"value BLOB NOT NULL,"
|
||||
// The time the entry was created.
|
||||
"creation_time INTEGER NOT NULL,"
|
||||
// The time the entry was last modified.
|
||||
"last_modified_time INTEGER NOT NULL);";
|
||||
|
||||
return db.Execute(kSqlCreateTablePassages);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
UserAnnotationsDatabase::UserAnnotationsDatabase(
|
||||
const base::FilePath& storage_dir,
|
||||
os_crypt_async::Encryptor encryptor)
|
||||
: encryptor_(std::move(encryptor)) {
|
||||
InitInternal(storage_dir);
|
||||
// TODO(b:361696651): Record the DB init status.
|
||||
}
|
||||
|
||||
UserAnnotationsDatabase::~UserAnnotationsDatabase() = default;
|
||||
|
||||
sql::InitStatus UserAnnotationsDatabase::InitInternal(
|
||||
const base::FilePath& storage_dir) {
|
||||
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
|
||||
|
||||
base::FilePath db_file_path = storage_dir.Append(kUserAnnotationsName);
|
||||
if (!db_.Open(db_file_path)) {
|
||||
return sql::InitStatus::INIT_FAILURE;
|
||||
}
|
||||
|
||||
// Raze old incompatible databases.
|
||||
if (sql::MetaTable::RazeIfIncompatible(&db_, kLowestSupportedDatabaseVersion,
|
||||
kCurrentDatabaseVersion) ==
|
||||
sql::RazeIfIncompatibleResult::kFailed) {
|
||||
return sql::InitStatus::INIT_FAILURE;
|
||||
}
|
||||
|
||||
// Wrap initialization in a transaction to make it atomic.
|
||||
sql::Transaction transaction(&db_);
|
||||
if (!transaction.Begin()) {
|
||||
return sql::InitStatus::INIT_FAILURE;
|
||||
}
|
||||
|
||||
// Initialize the current version meta table. Safest to leave the compatible
|
||||
// version equal to the current version - unless we know we're making a very
|
||||
// safe backwards-compatible schema change.
|
||||
sql::MetaTable meta_table;
|
||||
if (!meta_table.Init(&db_, kCurrentDatabaseVersion,
|
||||
/*compatible_version=*/kCurrentDatabaseVersion)) {
|
||||
return sql::InitStatus::INIT_FAILURE;
|
||||
}
|
||||
if (meta_table.GetCompatibleVersionNumber() > kCurrentDatabaseVersion) {
|
||||
return sql::INIT_TOO_NEW;
|
||||
}
|
||||
|
||||
if (!CreateTable(db_)) {
|
||||
return sql::INIT_FAILURE;
|
||||
}
|
||||
|
||||
if (!transaction.Commit()) {
|
||||
return sql::INIT_FAILURE;
|
||||
}
|
||||
|
||||
return sql::InitStatus::INIT_OK;
|
||||
}
|
||||
|
||||
UserAnnotationsExecutionResult UserAnnotationsDatabase::UpdateEntries(
|
||||
const UserAnnotationsEntries& upserted_entries,
|
||||
const std::set<EntryID>& deleted_entry_ids) {
|
||||
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
|
||||
|
||||
sql::Transaction transaction(&db_);
|
||||
if (!transaction.Begin()) {
|
||||
return UserAnnotationsExecutionResult::kSqlError;
|
||||
}
|
||||
auto now_time = base::Time::Now();
|
||||
for (const auto& entry : upserted_entries) {
|
||||
auto encrypted_value = encryptor_.EncryptString(entry.value());
|
||||
if (!encrypted_value) {
|
||||
return UserAnnotationsExecutionResult::kCryptError;
|
||||
}
|
||||
if (entry.entry_id() == 0) {
|
||||
// New entry.
|
||||
static constexpr char kSqlInsertEntry[] =
|
||||
"INSERT INTO entries(key, value, creation_time, "
|
||||
"last_modified_time) "
|
||||
"VALUES(?,?,?,?)";
|
||||
sql::Statement statement(
|
||||
db_.GetCachedStatement(SQL_FROM_HERE, kSqlInsertEntry));
|
||||
statement.BindString(0, entry.key());
|
||||
statement.BindBlob(1, *encrypted_value);
|
||||
statement.BindTime(2, now_time);
|
||||
statement.BindTime(3, now_time);
|
||||
if (!statement.Run()) {
|
||||
return UserAnnotationsExecutionResult::kSqlError;
|
||||
}
|
||||
} else {
|
||||
static constexpr char kSqlUpdateEntry[] =
|
||||
"UPDATE entries SET key=?, value=?, last_modified_time=? WHERE "
|
||||
"entry_id=?";
|
||||
sql::Statement statement(
|
||||
db_.GetCachedStatement(SQL_FROM_HERE, kSqlUpdateEntry));
|
||||
statement.BindString(0, entry.key());
|
||||
statement.BindBlob(1, *encrypted_value);
|
||||
statement.BindTime(2, now_time);
|
||||
statement.BindInt64(3, entry.entry_id());
|
||||
if (!statement.Run()) {
|
||||
return UserAnnotationsExecutionResult::kSqlError;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (const auto& entry_id : deleted_entry_ids) {
|
||||
static constexpr char kSqlDeleteEntries[] =
|
||||
"DELETE FROM entries WHERE entry_id = ?";
|
||||
sql::Statement statement(
|
||||
db_.GetCachedStatement(SQL_FROM_HERE, kSqlDeleteEntries));
|
||||
statement.BindInt64(0, entry_id);
|
||||
if (!statement.Run()) {
|
||||
return UserAnnotationsExecutionResult::kSqlError;
|
||||
}
|
||||
}
|
||||
if (!transaction.Commit()) {
|
||||
return UserAnnotationsExecutionResult::kSqlError;
|
||||
}
|
||||
return UserAnnotationsExecutionResult::kSuccess;
|
||||
}
|
||||
|
||||
UserAnnotationsEntryRetrievalResult
|
||||
UserAnnotationsDatabase::RetrieveAllEntries() {
|
||||
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
|
||||
|
||||
UserAnnotationsEntries entries;
|
||||
static constexpr char kSqlSelectAllEntries[] =
|
||||
"SELECT entry_id, key, value FROM entries";
|
||||
sql::Statement statement(
|
||||
db_.GetCachedStatement(SQL_FROM_HERE, kSqlSelectAllEntries));
|
||||
while (statement.Step()) {
|
||||
optimization_guide::proto::UserAnnotationsEntry entry;
|
||||
entry.set_entry_id(statement.ColumnInt64(0));
|
||||
entry.set_key(statement.ColumnString(1));
|
||||
auto decrypted_value = encryptor_.DecryptData(statement.ColumnBlob(2));
|
||||
if (!decrypted_value) {
|
||||
return base::unexpected(UserAnnotationsExecutionResult::kCryptError);
|
||||
}
|
||||
entry.set_value(*decrypted_value);
|
||||
entries.push_back(std::move(entry));
|
||||
}
|
||||
|
||||
return entries;
|
||||
}
|
||||
|
||||
bool UserAnnotationsDatabase::RemoveEntry(EntryID entry_id) {
|
||||
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
|
||||
sql::Statement delete_statement(db_.GetCachedStatement(
|
||||
SQL_FROM_HERE, "DELETE FROM entries WHERE entry_id=?"));
|
||||
delete_statement.BindInt64(0, entry_id);
|
||||
return delete_statement.Run();
|
||||
}
|
||||
|
||||
bool UserAnnotationsDatabase::RemoveAllEntries() {
|
||||
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
|
||||
sql::Statement delete_statement(
|
||||
db_.GetCachedStatement(SQL_FROM_HERE, "DELETE FROM entries"));
|
||||
return delete_statement.Run();
|
||||
}
|
||||
|
||||
void UserAnnotationsDatabase::RemoveAnnotationsInRange(
|
||||
const base::Time& delete_begin,
|
||||
const base::Time& delete_end) {
|
||||
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
|
||||
sql::Statement delete_statement(
|
||||
db_.GetCachedStatement(SQL_FROM_HERE,
|
||||
"DELETE FROM entries WHERE last_modified_time > ? "
|
||||
"AND last_modified_time < ?"));
|
||||
delete_statement.BindTime(0, delete_begin);
|
||||
delete_statement.BindTime(1, delete_end);
|
||||
delete_statement.Run();
|
||||
}
|
||||
|
||||
int UserAnnotationsDatabase::GetCountOfValuesContainedBetween(base::Time begin,
|
||||
base::Time end) {
|
||||
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
|
||||
sql::Statement s(
|
||||
db_.GetCachedStatement(SQL_FROM_HERE,
|
||||
"SELECT COUNT(DISTINCT(entry_id)) FROM entries "
|
||||
"WHERE last_modified_time > ? "
|
||||
"AND last_modified_time < ?"));
|
||||
s.BindTime(0, begin);
|
||||
s.BindTime(1, end);
|
||||
|
||||
if (!s.Step()) {
|
||||
// This might happen in case of I/O errors. See crbug.com/332263206.
|
||||
return 0;
|
||||
}
|
||||
return s.ColumnInt(0);
|
||||
}
|
||||
|
||||
} // namespace user_annotations
|
@ -1,76 +0,0 @@
|
||||
// Copyright 2024 The Chromium Authors
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef COMPONENTS_USER_ANNOTATIONS_USER_ANNOTATIONS_DATABASE_H_
|
||||
#define COMPONENTS_USER_ANNOTATIONS_USER_ANNOTATIONS_DATABASE_H_
|
||||
|
||||
#include "base/files/file_path.h"
|
||||
#include "base/sequence_checker.h"
|
||||
#include "base/thread_annotations.h"
|
||||
#include "base/types/expected.h"
|
||||
#include "components/optimization_guide/proto/features/common_quality_data.pb.h"
|
||||
#include "components/os_crypt/async/common/encryptor.h"
|
||||
#include "components/user_annotations/user_annotations_service.h"
|
||||
#include "components/user_annotations/user_annotations_types.h"
|
||||
#include "sql/database.h"
|
||||
#include "sql/init_status.h"
|
||||
|
||||
namespace user_annotations {
|
||||
|
||||
// Wraps the SQLite database that provides on-disk storage for user annotation
|
||||
// entries. This class is expected to be created and accessed on a backend
|
||||
// sequence.
|
||||
class UserAnnotationsDatabase {
|
||||
public:
|
||||
// `storage_dir` will generally be the Profile directory where the DB will be
|
||||
// opened from, or created if not exists.
|
||||
UserAnnotationsDatabase(const base::FilePath& storage_dir,
|
||||
os_crypt_async::Encryptor encryptor);
|
||||
|
||||
UserAnnotationsDatabase(const UserAnnotationsDatabase&) = delete;
|
||||
UserAnnotationsDatabase& operator=(const UserAnnotationsDatabase&) = delete;
|
||||
~UserAnnotationsDatabase();
|
||||
|
||||
// Updates the database and returns whether it succeeded. `upserted_entries`
|
||||
// contains entries that are new or updated. `deleted_entry_ids` contains the
|
||||
// entry IDs to be deleted.
|
||||
UserAnnotationsExecutionResult UpdateEntries(
|
||||
const UserAnnotationsEntries& upserted_entries,
|
||||
const std::set<EntryID>& deleted_entry_ids);
|
||||
|
||||
// Returns all the annotations from database.
|
||||
UserAnnotationsEntryRetrievalResult RetrieveAllEntries();
|
||||
|
||||
// Remove the user annotation entry with `entry_id` and returns whether the
|
||||
// operation completed successfully. Returns true even when no entry is found.
|
||||
bool RemoveEntry(EntryID entry_id);
|
||||
|
||||
// Removes all the user annotation entries and returns whether the
|
||||
// operation completed successfully. Returns true even when there are no
|
||||
// entries to delete.
|
||||
bool RemoveAllEntries();
|
||||
|
||||
// Removes the user annotation entries that were last modified from
|
||||
// `delete_begin` to `delete_end`.
|
||||
void RemoveAnnotationsInRange(const base::Time& delete_begin,
|
||||
const base::Time& delete_end);
|
||||
|
||||
// Returns the number of unique user annotations that were last modified
|
||||
// between [`begin`, `end`).
|
||||
int GetCountOfValuesContainedBetween(base::Time begin, base::Time end);
|
||||
|
||||
private:
|
||||
sql::InitStatus InitInternal(const base::FilePath& storage_dir);
|
||||
|
||||
// The underlying SQL database.
|
||||
sql::Database db_ GUARDED_BY_CONTEXT(sequence_checker_) =
|
||||
sql::Database(sql::DatabaseOptions{}, /*tag=*/"UserAnnotations");
|
||||
os_crypt_async::Encryptor encryptor_ GUARDED_BY_CONTEXT(sequence_checker_);
|
||||
|
||||
SEQUENCE_CHECKER(sequence_checker_);
|
||||
};
|
||||
|
||||
} // namespace user_annotations
|
||||
|
||||
#endif // COMPONENTS_USER_ANNOTATIONS_USER_ANNOTATIONS_DATABASE_H_
|
@ -1,261 +0,0 @@
|
||||
// Copyright 2024 The Chromium Authors
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "components/user_annotations/user_annotations_database.h"
|
||||
|
||||
#include "base/files/file_path.h"
|
||||
#include "base/files/file_util.h"
|
||||
#include "base/files/scoped_temp_dir.h"
|
||||
#include "base/test/metrics/histogram_tester.h"
|
||||
#include "base/test/protobuf_matchers.h"
|
||||
#include "base/test/task_environment.h"
|
||||
#include "components/os_crypt/async/browser/test_utils.h"
|
||||
#include "components/user_annotations/user_annotations_features.h"
|
||||
#include "testing/gtest/include/gtest/gtest.h"
|
||||
|
||||
namespace user_annotations {
|
||||
|
||||
using ::base::test::EqualsProto;
|
||||
using ::optimization_guide::proto::UserAnnotationsEntry;
|
||||
using ::testing::UnorderedElementsAre;
|
||||
|
||||
UserAnnotationsEntry CreateUserAnnotationsEntry(const std::string& key,
|
||||
const std::string& value) {
|
||||
UserAnnotationsEntry entry;
|
||||
entry.set_key(key);
|
||||
entry.set_value(value);
|
||||
return entry;
|
||||
}
|
||||
|
||||
class UserAnnotationsDatabaseTest : public testing::Test {
|
||||
public:
|
||||
void SetUp() override {
|
||||
CHECK(temp_dir_.CreateUniqueTempDir());
|
||||
os_crypt_ = os_crypt_async::GetTestOSCryptAsyncForTesting(
|
||||
/*is_sync_for_unittests=*/true);
|
||||
CreateDatabase();
|
||||
}
|
||||
|
||||
void TearDown() override {
|
||||
database_.reset();
|
||||
CHECK(temp_dir_.Delete());
|
||||
}
|
||||
|
||||
void CreateDatabase() {
|
||||
base::RunLoop run_loop;
|
||||
on_database_created_closure_ = run_loop.QuitClosure();
|
||||
encryptor_ready_subscription_ = os_crypt_->GetInstance(
|
||||
base::BindOnce(&UserAnnotationsDatabaseTest::CreateDatabaseOnCryptReady,
|
||||
base::Unretained(this)));
|
||||
run_loop.Run();
|
||||
}
|
||||
|
||||
protected:
|
||||
void CreateDatabaseOnCryptReady(os_crypt_async::Encryptor encryptor,
|
||||
bool success) {
|
||||
ASSERT_TRUE(success);
|
||||
database_ = std::make_unique<UserAnnotationsDatabase>(temp_dir_.GetPath(),
|
||||
std::move(encryptor));
|
||||
std::move(on_database_created_closure_).Run();
|
||||
}
|
||||
|
||||
base::test::TaskEnvironment task_environment_{
|
||||
base::test::TaskEnvironment::TimeSource::MOCK_TIME};
|
||||
base::ScopedTempDir temp_dir_;
|
||||
std::unique_ptr<os_crypt_async::OSCryptAsync> os_crypt_;
|
||||
base::CallbackListSubscription encryptor_ready_subscription_;
|
||||
std::unique_ptr<UserAnnotationsDatabase> database_;
|
||||
base::OnceClosure on_database_created_closure_;
|
||||
};
|
||||
|
||||
TEST_F(UserAnnotationsDatabaseTest, StoreAndRetrieve) {
|
||||
EXPECT_TRUE(database_->RetrieveAllEntries()->empty());
|
||||
|
||||
std::vector<UserAnnotationsEntry> entries;
|
||||
entries.push_back(CreateUserAnnotationsEntry("foo", "foo_value"));
|
||||
entries.push_back(CreateUserAnnotationsEntry("bar", "bar_value"));
|
||||
|
||||
EXPECT_EQ(UserAnnotationsExecutionResult::kSuccess,
|
||||
database_->UpdateEntries(entries, /*deleted_entry_ids=*/{}));
|
||||
entries[0].set_entry_id(1);
|
||||
entries[1].set_entry_id(2);
|
||||
EXPECT_THAT(
|
||||
*database_->RetrieveAllEntries(),
|
||||
UnorderedElementsAre(EqualsProto(entries[0]), EqualsProto(entries[1])));
|
||||
|
||||
// Reopen the database, and it should have the entries.
|
||||
database_.reset();
|
||||
CreateDatabase();
|
||||
EXPECT_THAT(
|
||||
*database_->RetrieveAllEntries(),
|
||||
UnorderedElementsAre(EqualsProto(entries[0]), EqualsProto(entries[1])));
|
||||
}
|
||||
|
||||
TEST_F(UserAnnotationsDatabaseTest, EntriesNewAndChanged) {
|
||||
std::vector<UserAnnotationsEntry> entries;
|
||||
entries.push_back(CreateUserAnnotationsEntry("foo", "foo_value"));
|
||||
entries.push_back(CreateUserAnnotationsEntry("bar", "bar_value"));
|
||||
EXPECT_EQ(UserAnnotationsExecutionResult::kSuccess,
|
||||
database_->UpdateEntries(entries, /*deleted_entry_ids=*/{}));
|
||||
entries[0].set_entry_id(1);
|
||||
entries[1].set_entry_id(2);
|
||||
EXPECT_EQ(2U, database_->RetrieveAllEntries()->size());
|
||||
|
||||
// Add new entry, and change foo.
|
||||
auto bazEntry = (CreateUserAnnotationsEntry("baz", "baz_value"));
|
||||
entries[0].set_value("new_foo_value");
|
||||
EXPECT_EQ(UserAnnotationsExecutionResult::kSuccess,
|
||||
database_->UpdateEntries({entries[0], bazEntry},
|
||||
/*deleted_entry_ids=*/{}));
|
||||
bazEntry.set_entry_id(3);
|
||||
EXPECT_THAT(
|
||||
*database_->RetrieveAllEntries(),
|
||||
UnorderedElementsAre(EqualsProto(entries[0]), EqualsProto(entries[1]),
|
||||
EqualsProto(bazEntry)));
|
||||
}
|
||||
|
||||
TEST_F(UserAnnotationsDatabaseTest, EntriesChangedAndDeleted) {
|
||||
std::vector<UserAnnotationsEntry> entries;
|
||||
entries.push_back(CreateUserAnnotationsEntry("foo", "foo_value"));
|
||||
entries.push_back(CreateUserAnnotationsEntry("bar", "bar_value"));
|
||||
EXPECT_EQ(UserAnnotationsExecutionResult::kSuccess,
|
||||
database_->UpdateEntries(entries, /*deleted_entry_ids=*/{}));
|
||||
entries[0].set_entry_id(1);
|
||||
entries[1].set_entry_id(2);
|
||||
EXPECT_EQ(2U, database_->RetrieveAllEntries()->size());
|
||||
|
||||
// Change foo, and delete bar.
|
||||
entries[0].set_value("new_foo_value");
|
||||
EXPECT_EQ(UserAnnotationsExecutionResult::kSuccess,
|
||||
database_->UpdateEntries({entries[0]}, /*deleted_entry_ids=*/{2}));
|
||||
EXPECT_THAT(*database_->RetrieveAllEntries(),
|
||||
UnorderedElementsAre(EqualsProto(entries[0])));
|
||||
|
||||
// Delete foo.
|
||||
EXPECT_EQ(UserAnnotationsExecutionResult::kSuccess,
|
||||
database_->UpdateEntries({}, /*deleted_entry_ids=*/{1}));
|
||||
EXPECT_TRUE(database_->RetrieveAllEntries()->empty());
|
||||
}
|
||||
|
||||
TEST_F(UserAnnotationsDatabaseTest, RemoveEntry) {
|
||||
std::vector<UserAnnotationsEntry> entries;
|
||||
entries.push_back(CreateUserAnnotationsEntry("foo", "foo_value"));
|
||||
entries.push_back(CreateUserAnnotationsEntry("bar", "bar_value"));
|
||||
EXPECT_EQ(UserAnnotationsExecutionResult::kSuccess,
|
||||
database_->UpdateEntries(entries, /*deleted_entry_ids=*/{}));
|
||||
entries[0].set_entry_id(1);
|
||||
entries[1].set_entry_id(2);
|
||||
|
||||
auto db_entries = *database_->RetrieveAllEntries();
|
||||
EXPECT_EQ(2U, db_entries.size());
|
||||
EXPECT_TRUE(database_->RemoveEntry(db_entries[0].entry_id()));
|
||||
EXPECT_TRUE(database_->RemoveEntry(db_entries[1].entry_id()));
|
||||
EXPECT_TRUE(database_->RetrieveAllEntries()->empty());
|
||||
}
|
||||
|
||||
TEST_F(UserAnnotationsDatabaseTest, RemoveAllEntries) {
|
||||
std::vector<UserAnnotationsEntry> entries;
|
||||
entries.push_back(CreateUserAnnotationsEntry("foo", "foo_value"));
|
||||
entries.push_back(CreateUserAnnotationsEntry("bar", "bar_value"));
|
||||
EXPECT_EQ(UserAnnotationsExecutionResult::kSuccess,
|
||||
database_->UpdateEntries(entries, /*deleted_entry_ids=*/{}));
|
||||
EXPECT_TRUE(database_->RemoveAllEntries());
|
||||
EXPECT_TRUE(database_->RemoveAllEntries());
|
||||
EXPECT_TRUE(database_->RetrieveAllEntries()->empty());
|
||||
}
|
||||
|
||||
TEST_F(UserAnnotationsDatabaseTest, RemoveAllAnnotationsInRange) {
|
||||
auto foo_entry = CreateUserAnnotationsEntry("foo", "foo_value");
|
||||
auto bar_entry = CreateUserAnnotationsEntry("bar", "bar_value");
|
||||
EXPECT_EQ(UserAnnotationsExecutionResult::kSuccess,
|
||||
database_->UpdateEntries({foo_entry}, /*deleted_entry_ids=*/{}));
|
||||
task_environment_.FastForwardBy(base::Hours(1));
|
||||
EXPECT_EQ(UserAnnotationsExecutionResult::kSuccess,
|
||||
database_->UpdateEntries({bar_entry}, /*deleted_entry_ids=*/{}));
|
||||
EXPECT_EQ(2u, database_->RetrieveAllEntries()->size());
|
||||
|
||||
// Delete all.
|
||||
database_->RemoveAnnotationsInRange(base::Time::Min(), base::Time::Max());
|
||||
EXPECT_TRUE(database_->RetrieveAllEntries()->empty());
|
||||
}
|
||||
|
||||
TEST_F(UserAnnotationsDatabaseTest, RemoveAnnotationsInRange) {
|
||||
auto foo_entry = CreateUserAnnotationsEntry("foo", "foo_value");
|
||||
auto bar_entry = CreateUserAnnotationsEntry("bar", "bar_value");
|
||||
auto foo_create_time = base::Time::Now();
|
||||
EXPECT_EQ(UserAnnotationsExecutionResult::kSuccess,
|
||||
database_->UpdateEntries({foo_entry}, /*deleted_entry_ids=*/{}));
|
||||
task_environment_.FastForwardBy(base::Hours(1));
|
||||
auto bar_create_time = base::Time::Now();
|
||||
EXPECT_EQ(UserAnnotationsExecutionResult::kSuccess,
|
||||
database_->UpdateEntries({bar_entry}, /*deleted_entry_ids=*/{}));
|
||||
EXPECT_EQ(2u, database_->RetrieveAllEntries()->size());
|
||||
|
||||
// Delete foo.
|
||||
database_->RemoveAnnotationsInRange(foo_create_time - base::Seconds(1),
|
||||
foo_create_time + base::Seconds(1));
|
||||
bar_entry.set_entry_id(2);
|
||||
EXPECT_THAT(*database_->RetrieveAllEntries(),
|
||||
UnorderedElementsAre(EqualsProto(bar_entry)));
|
||||
|
||||
// Delete bar.
|
||||
database_->RemoveAnnotationsInRange(bar_create_time - base::Seconds(1),
|
||||
bar_create_time + base::Seconds(1));
|
||||
EXPECT_TRUE(database_->RetrieveAllEntries()->empty());
|
||||
}
|
||||
|
||||
TEST_F(UserAnnotationsDatabaseTest, RemoveAnnotationsInRangeBackward) {
|
||||
auto foo_entry = CreateUserAnnotationsEntry("foo", "foo_value");
|
||||
auto bar_entry = CreateUserAnnotationsEntry("bar", "bar_value");
|
||||
auto foo_create_time = base::Time::Now();
|
||||
EXPECT_EQ(UserAnnotationsExecutionResult::kSuccess,
|
||||
database_->UpdateEntries({foo_entry}, /*deleted_entry_ids=*/{}));
|
||||
task_environment_.FastForwardBy(base::Hours(1));
|
||||
auto bar_create_time = base::Time::Now();
|
||||
EXPECT_EQ(UserAnnotationsExecutionResult::kSuccess,
|
||||
database_->UpdateEntries({bar_entry}, /*deleted_entry_ids=*/{}));
|
||||
EXPECT_EQ(2u, database_->RetrieveAllEntries()->size());
|
||||
|
||||
// Delete bar.
|
||||
database_->RemoveAnnotationsInRange(bar_create_time - base::Seconds(1),
|
||||
bar_create_time + base::Seconds(1));
|
||||
foo_entry.set_entry_id(1);
|
||||
EXPECT_THAT(*database_->RetrieveAllEntries(),
|
||||
UnorderedElementsAre(EqualsProto(foo_entry)));
|
||||
|
||||
// Delete foo.
|
||||
database_->RemoveAnnotationsInRange(foo_create_time - base::Seconds(1),
|
||||
foo_create_time + base::Seconds(1));
|
||||
EXPECT_TRUE(database_->RetrieveAllEntries()->empty());
|
||||
}
|
||||
|
||||
TEST_F(UserAnnotationsDatabaseTest, GetCountOfValuesContainedBetween) {
|
||||
auto foo_entry = CreateUserAnnotationsEntry("foo", "foo_value");
|
||||
auto bar_entry = CreateUserAnnotationsEntry("bar", "bar_value");
|
||||
auto foo_create_time = base::Time::Now();
|
||||
EXPECT_EQ(UserAnnotationsExecutionResult::kSuccess,
|
||||
database_->UpdateEntries({foo_entry}, /*deleted_entry_ids=*/{}));
|
||||
task_environment_.FastForwardBy(base::Hours(1));
|
||||
auto bar_create_time = base::Time::Now();
|
||||
EXPECT_EQ(UserAnnotationsExecutionResult::kSuccess,
|
||||
database_->UpdateEntries({bar_entry}, /*deleted_entry_ids=*/{}));
|
||||
EXPECT_EQ(2u, database_->RetrieveAllEntries()->size());
|
||||
|
||||
// One entry: bar.
|
||||
int count = database_->GetCountOfValuesContainedBetween(
|
||||
bar_create_time - base::Seconds(1), bar_create_time + base::Seconds(1));
|
||||
EXPECT_EQ(1, count);
|
||||
|
||||
// One entry: foo.
|
||||
count = database_->GetCountOfValuesContainedBetween(
|
||||
foo_create_time - base::Seconds(1), foo_create_time + base::Seconds(1));
|
||||
EXPECT_EQ(1, count);
|
||||
|
||||
// All.
|
||||
count = database_->GetCountOfValuesContainedBetween(base::Time::Min(),
|
||||
base::Time::Max());
|
||||
EXPECT_EQ(2, count);
|
||||
}
|
||||
|
||||
} // namespace user_annotations
|
@ -1,37 +0,0 @@
|
||||
// Copyright 2024 The Chromium Authors
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "components/user_annotations/user_annotations_features.h"
|
||||
|
||||
#include "base/feature_list.h"
|
||||
#include "base/strings/string_split.h"
|
||||
#include "components/autofill_ai/core/browser/autofill_ai_features.h"
|
||||
|
||||
namespace user_annotations {
|
||||
|
||||
bool IsUserAnnotationsEnabled() {
|
||||
return base::FeatureList::IsEnabled(autofill_ai::kAutofillAi);
|
||||
}
|
||||
|
||||
std::vector<std::string> GetAllowedHostsForFormsAnnotations() {
|
||||
std::string allowed_hosts_string = base::GetFieldTrialParamValueByFeature(
|
||||
autofill_ai::kAutofillAi, "allowed_hosts_for_form_submissions");
|
||||
return base::SplitString(allowed_hosts_string, ",",
|
||||
base::WhitespaceHandling::TRIM_WHITESPACE,
|
||||
base::SplitResult::SPLIT_WANT_NONEMPTY);
|
||||
}
|
||||
|
||||
bool ShouldExtractAXTreeForFormsAnnotations() {
|
||||
return base::GetFieldTrialParamByFeatureAsBool(
|
||||
autofill_ai::kAutofillAi, "should_extract_ax_tree_for_forms_annotations",
|
||||
false);
|
||||
}
|
||||
|
||||
base::TimeDelta GetFormSubmissionCompletionTimeout() {
|
||||
return base::GetFieldTrialParamByFeatureAsTimeDelta(
|
||||
autofill_ai::kAutofillAi, "form_submission_completion_timeout",
|
||||
base::Seconds(30));
|
||||
}
|
||||
|
||||
} // namespace user_annotations
|
@ -1,29 +0,0 @@
|
||||
// Copyright 2024 The Chromium Authors
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef COMPONENTS_USER_ANNOTATIONS_USER_ANNOTATIONS_FEATURES_H_
|
||||
#define COMPONENTS_USER_ANNOTATIONS_USER_ANNOTATIONS_FEATURES_H_
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "base/feature_list.h"
|
||||
#include "base/metrics/field_trial_params.h"
|
||||
|
||||
namespace user_annotations {
|
||||
|
||||
// Whether the user annotations feature is enabled.
|
||||
bool IsUserAnnotationsEnabled();
|
||||
|
||||
// Returns the set of hosts that are allowed for forms annotations.
|
||||
std::vector<std::string> GetAllowedHostsForFormsAnnotations();
|
||||
|
||||
bool ShouldExtractAXTreeForFormsAnnotations();
|
||||
|
||||
// Returns the completion timeout for the entirety of forms submission stages.
|
||||
base::TimeDelta GetFormSubmissionCompletionTimeout();
|
||||
|
||||
} // namespace user_annotations
|
||||
|
||||
#endif // COMPONENTS_USER_ANNOTATIONS_USER_ANNOTATIONS_FEATURES_H_
|
@ -1,28 +0,0 @@
|
||||
// Copyright 2024 The Chromium Authors
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "components/user_annotations/user_annotations_features.h"
|
||||
|
||||
#include "base/test/scoped_feature_list.h"
|
||||
#include "components/autofill_ai/core/browser/autofill_ai_features.h"
|
||||
#include "testing/gmock/include/gmock/gmock.h"
|
||||
#include "testing/gtest/include/gtest/gtest.h"
|
||||
|
||||
namespace user_annotations {
|
||||
|
||||
namespace {
|
||||
|
||||
using ::testing::UnorderedElementsAre;
|
||||
|
||||
TEST(UserAnnotationsFeaturesTest, GetAllowedHostsForFormsAnnotations) {
|
||||
base::test::ScopedFeatureList scoped_feature_list;
|
||||
scoped_feature_list.InitAndEnableFeatureWithParameters(
|
||||
autofill_ai::kAutofillAi,
|
||||
{{"allowed_hosts_for_form_submissions", "example.com,otherhost.com"}});
|
||||
EXPECT_THAT(GetAllowedHostsForFormsAnnotations(),
|
||||
UnorderedElementsAre("example.com", "otherhost.com"));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace user_annotations
|
@ -1,346 +0,0 @@
|
||||
// Copyright 2024 The Chromium Authors
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "components/user_annotations/user_annotations_service.h"
|
||||
|
||||
#include "base/callback_list.h"
|
||||
#include "base/containers/contains.h"
|
||||
#include "base/containers/fixed_flat_map.h"
|
||||
#include "base/functional/callback.h"
|
||||
#include "base/metrics/histogram_functions.h"
|
||||
#include "base/strings/utf_string_conversions.h"
|
||||
#include "base/task/sequenced_task_runner.h"
|
||||
#include "base/task/task_traits.h"
|
||||
#include "base/task/thread_pool.h"
|
||||
#include "base/types/expected.h"
|
||||
#include "components/autofill/core/browser/data_model/addresses/autofill_profile.h"
|
||||
#include "components/autofill/core/browser/field_types.h"
|
||||
#include "components/autofill/core/browser/form_processing/optimization_guide_proto_util.h"
|
||||
#include "components/autofill/core/browser/form_structure.h"
|
||||
#include "components/autofill/core/browser/geo/phone_number_i18n.h"
|
||||
#include "components/optimization_guide/core/model_quality/model_quality_logs_uploader_service.h"
|
||||
#include "components/optimization_guide/core/optimization_guide_decider.h"
|
||||
#include "components/optimization_guide/core/optimization_guide_model_executor.h"
|
||||
#include "components/optimization_guide/core/optimization_guide_proto_util.h"
|
||||
#include "components/optimization_guide/core/optimization_guide_util.h"
|
||||
#include "components/optimization_guide/proto/features/common_quality_data.pb.h"
|
||||
#include "components/optimization_guide/proto/features/forms_annotations.pb.h"
|
||||
#include "components/os_crypt/async/browser/os_crypt_async.h"
|
||||
#include "components/os_crypt/async/common/encryptor.h"
|
||||
#include "components/user_annotations/form_submission_handler.h"
|
||||
#include "components/user_annotations/user_annotations_database.h"
|
||||
#include "components/user_annotations/user_annotations_features.h"
|
||||
#include "components/user_annotations/user_annotations_switches.h"
|
||||
#include "components/user_annotations/user_annotations_types.h"
|
||||
|
||||
namespace user_annotations {
|
||||
|
||||
namespace {
|
||||
|
||||
base::flat_map<autofill::FieldType, std::string>
|
||||
GetEntryKeyByAutofillFieldType() {
|
||||
return {
|
||||
{autofill::FieldType::NAME_FIRST, "First Name"},
|
||||
{autofill::FieldType::NAME_MIDDLE, "Middle Name"},
|
||||
{autofill::FieldType::NAME_LAST, "Last Name"},
|
||||
{autofill::FieldType::EMAIL_ADDRESS, "Email Address"},
|
||||
{autofill::FieldType::PHONE_HOME_WHOLE_NUMBER, "Phone Number [mobile]"},
|
||||
{autofill::FieldType::ADDRESS_HOME_CITY, "Address - City"},
|
||||
{autofill::FieldType::ADDRESS_HOME_STATE, "Address - State"},
|
||||
{autofill::FieldType::ADDRESS_HOME_ZIP, "Address - Zip Code"},
|
||||
{autofill::FieldType::ADDRESS_HOME_COUNTRY, "Address - Country"},
|
||||
{autofill::FieldType::ADDRESS_HOME_STREET_ADDRESS, "Address - Street"},
|
||||
};
|
||||
}
|
||||
|
||||
void RecordUserAnnotationsFormImportResult(
|
||||
UserAnnotationsExecutionResult result) {
|
||||
base::UmaHistogramEnumeration("UserAnnotations.FormImportResult", result);
|
||||
}
|
||||
|
||||
void RecordMemoryCountEntriesResult(int result) {
|
||||
base::UmaHistogramCounts1000("UserAnnotations.EntryCount", result);
|
||||
}
|
||||
|
||||
void ProcessEntryRetrieval(
|
||||
base::OnceCallback<void(UserAnnotationsEntries)> callback,
|
||||
UserAnnotationsEntryRetrievalResult user_annotations) {
|
||||
RecordMemoryCountEntriesResult(user_annotations->size());
|
||||
if (!user_annotations.has_value()) {
|
||||
std::move(callback).Run({});
|
||||
return;
|
||||
}
|
||||
std::move(callback).Run(std::move(user_annotations).value());
|
||||
}
|
||||
|
||||
void RecordRemoveEntryResult(UserAnnotationsExecutionResult result) {
|
||||
base::UmaHistogramEnumeration("UserAnnotations.RemoveEntry.Result", result);
|
||||
}
|
||||
|
||||
void RecordRemoveAllEntriesResult(UserAnnotationsExecutionResult result) {
|
||||
base::UmaHistogramEnumeration("UserAnnotations.RemoveAllEntries.Result",
|
||||
result);
|
||||
}
|
||||
|
||||
void RecordCountEntriesResult(UserAnnotationsExecutionResult result) {
|
||||
base::UmaHistogramEnumeration("UserAnnotations.CountEntries.Result", result);
|
||||
}
|
||||
|
||||
std::string GetEntryValueFromAutofillProfile(
|
||||
const autofill::AutofillProfile& autofill_profile,
|
||||
autofill::FieldType field_type) {
|
||||
if (field_type == autofill::FieldType::PHONE_HOME_WHOLE_NUMBER) {
|
||||
return autofill::i18n::FormatPhoneForDisplay(
|
||||
base::UTF16ToUTF8(autofill_profile.GetRawInfo(field_type)),
|
||||
base::UTF16ToUTF8(
|
||||
autofill_profile.GetRawInfo(autofill::PHONE_HOME_COUNTRY_CODE)));
|
||||
}
|
||||
return base::UTF16ToUTF8(autofill_profile.GetRawInfo(field_type));
|
||||
}
|
||||
|
||||
UserAnnotationsEntries ConvertAutofillProfileToEntries(
|
||||
const autofill::AutofillProfile& autofill_profile) {
|
||||
static const base::flat_map<autofill::FieldType, std::string>
|
||||
entry_key_by_autofill_field_type = GetEntryKeyByAutofillFieldType();
|
||||
UserAnnotationsEntries entries;
|
||||
for (const auto& [field_type, entry_key] : entry_key_by_autofill_field_type) {
|
||||
const std::string entry_value =
|
||||
GetEntryValueFromAutofillProfile(autofill_profile, field_type);
|
||||
if (entry_value.empty()) {
|
||||
continue;
|
||||
}
|
||||
optimization_guide::proto::UserAnnotationsEntry entry_proto;
|
||||
entry_proto.set_key(entry_key);
|
||||
entry_proto.set_value(std::move(entry_value));
|
||||
entries.emplace_back(std::move(entry_proto));
|
||||
}
|
||||
return entries;
|
||||
}
|
||||
|
||||
void NotifyAutofillProfileSaved(
|
||||
base::OnceCallback<void(UserAnnotationsExecutionResult)> callback,
|
||||
UserAnnotationsExecutionResult result) {
|
||||
std::move(callback).Run(result);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
UserAnnotationsService::UserAnnotationsService(
|
||||
optimization_guide::OptimizationGuideModelExecutor* model_executor,
|
||||
optimization_guide::ModelQualityLogsUploaderService* logs_uploader,
|
||||
const base::FilePath& storage_dir,
|
||||
os_crypt_async::OSCryptAsync* os_crypt_async,
|
||||
optimization_guide::OptimizationGuideDecider* optimization_guide_decider)
|
||||
: model_executor_(model_executor),
|
||||
logs_uploader_(logs_uploader->GetWeakPtr()),
|
||||
optimization_guide_decider_(optimization_guide_decider),
|
||||
allowed_hosts_for_forms_annotations_(
|
||||
GetAllowedHostsForFormsAnnotations()) {
|
||||
encryptor_ready_subscription_ = os_crypt_async->GetInstance(
|
||||
base::BindOnce(&UserAnnotationsService::OnOsCryptAsyncReady,
|
||||
weak_ptr_factory_.GetWeakPtr(), storage_dir));
|
||||
|
||||
if (optimization_guide_decider_) {
|
||||
optimization_guide_decider_->RegisterOptimizationTypes(
|
||||
{optimization_guide::proto::FORMS_ANNOTATIONS});
|
||||
}
|
||||
}
|
||||
|
||||
UserAnnotationsService::UserAnnotationsService() = default;
|
||||
|
||||
UserAnnotationsService::~UserAnnotationsService() = default;
|
||||
|
||||
bool UserAnnotationsService::ShouldAddFormSubmissionForURL(const GURL& url) {
|
||||
if (base::Contains(allowed_hosts_for_forms_annotations_, url.host())) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Only allow HTTPS sites.
|
||||
if (!url.SchemeIs("https")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Fall back to optimization guide if not in override list.
|
||||
if (optimization_guide_decider_) {
|
||||
optimization_guide::OptimizationGuideDecision decision =
|
||||
optimization_guide_decider_->CanApplyOptimization(
|
||||
url, optimization_guide::proto::FORMS_ANNOTATIONS,
|
||||
/*metadata=*/nullptr);
|
||||
return decision == optimization_guide::OptimizationGuideDecision::kTrue;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void UserAnnotationsService::AddFormSubmission(
|
||||
const GURL& url,
|
||||
const std::string& title,
|
||||
optimization_guide::proto::AXTreeUpdate ax_tree_update,
|
||||
std::unique_ptr<autofill::FormStructure> form,
|
||||
ImportFormCallback callback) {
|
||||
// `form` is assumed to never be `nullptr`.
|
||||
CHECK(form);
|
||||
pending_form_submissions_.emplace(std::make_unique<FormSubmissionHandler>(
|
||||
this, url, title, std::move(ax_tree_update), std::move(form),
|
||||
std::move(callback)));
|
||||
if (pending_form_submissions_.size() != 1) {
|
||||
return;
|
||||
}
|
||||
ProcessNextFormSubmission();
|
||||
}
|
||||
|
||||
void UserAnnotationsService::RetrieveAllEntries(
|
||||
base::OnceCallback<void(UserAnnotationsEntries)> callback) {
|
||||
if (!user_annotations_database_) {
|
||||
// TODO: b/361696651 - Record the failure.
|
||||
return;
|
||||
}
|
||||
user_annotations_database_
|
||||
.AsyncCall(&UserAnnotationsDatabase::RetrieveAllEntries)
|
||||
.Then(base::BindOnce(ProcessEntryRetrieval, std::move(callback)));
|
||||
}
|
||||
|
||||
void UserAnnotationsService::OnOsCryptAsyncReady(
|
||||
const base::FilePath& storage_dir,
|
||||
os_crypt_async::Encryptor encryptor,
|
||||
bool success) {
|
||||
if (!success) {
|
||||
// TODO: b/361696651 - Record the failure.
|
||||
return;
|
||||
}
|
||||
user_annotations_database_ = base::SequenceBound<UserAnnotationsDatabase>(
|
||||
base::ThreadPool::CreateSequencedTaskRunner(
|
||||
{base::MayBlock(), base::TaskPriority::USER_BLOCKING,
|
||||
base::TaskShutdownBehavior::BLOCK_SHUTDOWN}),
|
||||
storage_dir, std::move(encryptor));
|
||||
|
||||
if (auto manual_entries = switches::ParseFormsAnnotationsFromCommandLine()) {
|
||||
RemoveAllEntries(base::BindOnce(
|
||||
&UserAnnotationsService::InitializeFormsAnnotationsFromCommandLine,
|
||||
weak_ptr_factory_.GetWeakPtr(), *manual_entries));
|
||||
}
|
||||
}
|
||||
|
||||
void UserAnnotationsService::InitializeFormsAnnotationsFromCommandLine(
|
||||
const optimization_guide::proto::FormsAnnotationsResponse& manual_entries) {
|
||||
SaveEntries(manual_entries);
|
||||
}
|
||||
|
||||
void UserAnnotationsService::Shutdown() {}
|
||||
|
||||
bool UserAnnotationsService::IsDatabaseReady() {
|
||||
return !!user_annotations_database_;
|
||||
}
|
||||
|
||||
void UserAnnotationsService::SaveEntries(
|
||||
const optimization_guide::proto::FormsAnnotationsResponse& entries) {
|
||||
DCHECK(user_annotations_database_);
|
||||
|
||||
UserAnnotationsEntries upserted_entries = UserAnnotationsEntries(
|
||||
entries.upserted_entries().begin(), entries.upserted_entries().end());
|
||||
std::set<EntryID> deleted_entry_ids(entries.deleted_entry_ids().begin(),
|
||||
entries.deleted_entry_ids().end());
|
||||
user_annotations_database_.AsyncCall(&UserAnnotationsDatabase::UpdateEntries)
|
||||
.WithArgs(upserted_entries, deleted_entry_ids)
|
||||
.Then(base::BindOnce(RecordUserAnnotationsFormImportResult));
|
||||
}
|
||||
|
||||
void UserAnnotationsService::SaveAutofillProfile(
|
||||
const autofill::AutofillProfile& autofill_profile,
|
||||
base::OnceCallback<void(UserAnnotationsExecutionResult)> callback) {
|
||||
const UserAnnotationsEntries entries =
|
||||
ConvertAutofillProfileToEntries(autofill_profile);
|
||||
DCHECK(user_annotations_database_);
|
||||
|
||||
user_annotations_database_.AsyncCall(&UserAnnotationsDatabase::UpdateEntries)
|
||||
.WithArgs(entries, std::set<EntryID>{})
|
||||
.Then(base::BindOnce(NotifyAutofillProfileSaved, std::move(callback)));
|
||||
}
|
||||
|
||||
void UserAnnotationsService::OnFormSubmissionComplete() {
|
||||
pending_form_submissions_.pop();
|
||||
ProcessNextFormSubmission();
|
||||
}
|
||||
|
||||
void UserAnnotationsService::ProcessNextFormSubmission() {
|
||||
if (pending_form_submissions_.empty()) {
|
||||
return;
|
||||
}
|
||||
pending_form_submissions_.front()->Start();
|
||||
}
|
||||
|
||||
void UserAnnotationsService::RemoveEntry(EntryID entry_id,
|
||||
base::OnceClosure callback) {
|
||||
if (!user_annotations_database_) {
|
||||
RecordRemoveEntryResult(
|
||||
UserAnnotationsExecutionResult::kCryptNotInitialized);
|
||||
std::move(callback).Run();
|
||||
return;
|
||||
}
|
||||
user_annotations_database_.AsyncCall(&UserAnnotationsDatabase::RemoveEntry)
|
||||
.WithArgs(entry_id)
|
||||
.Then(base::BindOnce(
|
||||
[](base::OnceClosure callback, bool result) {
|
||||
RecordRemoveEntryResult(
|
||||
result ? UserAnnotationsExecutionResult::kSuccess
|
||||
: UserAnnotationsExecutionResult::kSqlError);
|
||||
std::move(callback).Run();
|
||||
},
|
||||
std::move(callback)));
|
||||
}
|
||||
|
||||
void UserAnnotationsService::RemoveAllEntries(base::OnceClosure callback) {
|
||||
if (!user_annotations_database_) {
|
||||
RecordRemoveAllEntriesResult(
|
||||
UserAnnotationsExecutionResult::kCryptNotInitialized);
|
||||
std::move(callback).Run();
|
||||
return;
|
||||
}
|
||||
user_annotations_database_
|
||||
.AsyncCall(&UserAnnotationsDatabase::RemoveAllEntries)
|
||||
.Then(base::BindOnce(
|
||||
[](base::OnceClosure callback, bool result) {
|
||||
RecordRemoveAllEntriesResult(
|
||||
result ? UserAnnotationsExecutionResult::kSuccess
|
||||
: UserAnnotationsExecutionResult::kSqlError);
|
||||
std::move(callback).Run();
|
||||
},
|
||||
std::move(callback)));
|
||||
}
|
||||
|
||||
void UserAnnotationsService::RemoveAnnotationsInRange(
|
||||
const base::Time& delete_begin,
|
||||
const base::Time& delete_end) {
|
||||
if (!user_annotations_database_) {
|
||||
return;
|
||||
}
|
||||
user_annotations_database_
|
||||
.AsyncCall(&UserAnnotationsDatabase::RemoveAnnotationsInRange)
|
||||
.WithArgs(delete_begin, delete_end);
|
||||
}
|
||||
|
||||
void UserAnnotationsService::GetCountOfValuesContainedBetween(
|
||||
base::Time begin,
|
||||
base::Time end,
|
||||
base::OnceCallback<void(int)> callback) {
|
||||
if (!user_annotations_database_) {
|
||||
RecordCountEntriesResult(
|
||||
UserAnnotationsExecutionResult::kCryptNotInitialized);
|
||||
std::move(callback).Run(0);
|
||||
return;
|
||||
}
|
||||
user_annotations_database_
|
||||
.AsyncCall(&UserAnnotationsDatabase::GetCountOfValuesContainedBetween)
|
||||
.WithArgs(begin, end)
|
||||
.Then(base::BindOnce(
|
||||
[](base::OnceCallback<void(int)> callback, int result) {
|
||||
RecordCountEntriesResult(
|
||||
result ? UserAnnotationsExecutionResult::kSuccess
|
||||
: UserAnnotationsExecutionResult::kSqlError);
|
||||
std::move(callback).Run(result);
|
||||
},
|
||||
std::move(callback)));
|
||||
}
|
||||
|
||||
} // namespace user_annotations
|
@ -1,187 +0,0 @@
|
||||
// Copyright 2024 The Chromium Authors
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef COMPONENTS_USER_ANNOTATIONS_USER_ANNOTATIONS_SERVICE_H_
|
||||
#define COMPONENTS_USER_ANNOTATIONS_USER_ANNOTATIONS_SERVICE_H_
|
||||
|
||||
#include <memory>
|
||||
#include <queue>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "base/callback_list.h"
|
||||
#include "base/containers/queue.h"
|
||||
#include "base/files/file_path.h"
|
||||
#include "base/functional/callback_helpers.h"
|
||||
#include "base/memory/raw_ptr.h"
|
||||
#include "base/memory/weak_ptr.h"
|
||||
#include "base/threading/sequence_bound.h"
|
||||
#include "components/keyed_service/core/keyed_service.h"
|
||||
#include "components/optimization_guide/core/optimization_guide_model_executor.h"
|
||||
#include "components/user_annotations/user_annotations_types.h"
|
||||
#include "url/gurl.h"
|
||||
|
||||
namespace autofill {
|
||||
class AutofillProfile;
|
||||
class FormStructure;
|
||||
} // namespace autofill
|
||||
|
||||
namespace optimization_guide {
|
||||
class OptimizationGuideDecider;
|
||||
namespace proto {
|
||||
class AXTreeUpdate;
|
||||
} // namespace proto
|
||||
} // namespace optimization_guide
|
||||
|
||||
namespace os_crypt_async {
|
||||
class Encryptor;
|
||||
class OSCryptAsync;
|
||||
} // namespace os_crypt_async
|
||||
|
||||
namespace user_annotations {
|
||||
|
||||
class FormSubmissionHandler;
|
||||
class UserAnnotationsDatabase;
|
||||
|
||||
class UserAnnotationsService : public KeyedService {
|
||||
public:
|
||||
UserAnnotationsService(
|
||||
optimization_guide::OptimizationGuideModelExecutor* model_executor,
|
||||
optimization_guide::ModelQualityLogsUploaderService* logs_uploader,
|
||||
const base::FilePath& storage_dir,
|
||||
os_crypt_async::OSCryptAsync* os_crypt_async,
|
||||
optimization_guide::OptimizationGuideDecider* optimization_guide_decider);
|
||||
|
||||
UserAnnotationsService(const UserAnnotationsService&) = delete;
|
||||
UserAnnotationsService& operator=(const UserAnnotationsService&) = delete;
|
||||
~UserAnnotationsService() override;
|
||||
|
||||
// Whether the form submission for `url` should be added to user annotations.
|
||||
// Virtual for testing.
|
||||
virtual bool ShouldAddFormSubmissionForURL(const GURL& url);
|
||||
|
||||
// Adds a form submission to the user annotations. Calls `callback` according
|
||||
// to the outcome of the import process. The `callback` will notify Autofill
|
||||
// code about the import attempt so they can show a save prompt to the user.
|
||||
// When the prompt is closed, the inner `prompt_acceptance_callback` will
|
||||
// notify `this` about the user's decision. `form` is assumed to never be
|
||||
// `nullptr`. Virtual for testing.
|
||||
virtual void AddFormSubmission(
|
||||
const GURL& url,
|
||||
const std::string& title,
|
||||
optimization_guide::proto::AXTreeUpdate ax_tree_update,
|
||||
std::unique_ptr<autofill::FormStructure> form,
|
||||
ImportFormCallback callback);
|
||||
|
||||
// Retrieves all entries from the database. Invokes `callback` when complete.
|
||||
// Virtual for testing.
|
||||
virtual void RetrieveAllEntries(
|
||||
base::OnceCallback<void(UserAnnotationsEntries)> callback);
|
||||
|
||||
// Remove the user annotation entry with `entry_id` and calls `callback` upon
|
||||
// completion.
|
||||
// Virtual for testing.
|
||||
virtual void RemoveEntry(EntryID entry_id, base::OnceClosure callback);
|
||||
|
||||
// Removes all the user annotation entries and calls `callback` upon
|
||||
// completion.
|
||||
// Virtual for testing.
|
||||
virtual void RemoveAllEntries(base::OnceClosure callback);
|
||||
|
||||
// Removes the user annotation entries that were last modified from
|
||||
// `delete_begin` to `delete_end`.
|
||||
// Virtual for testing.
|
||||
virtual void RemoveAnnotationsInRange(const base::Time& delete_begin,
|
||||
const base::Time& delete_end);
|
||||
|
||||
// Returns the number of unique user annotations that were last modified
|
||||
// between [`begin`, `end`).
|
||||
// Virtual for testing.
|
||||
virtual void GetCountOfValuesContainedBetween(
|
||||
base::Time begin,
|
||||
base::Time end,
|
||||
base::OnceCallback<void(int)> callback);
|
||||
|
||||
// KeyedService:
|
||||
void Shutdown() override;
|
||||
|
||||
// Saves `autofill_profile` to the database, then runs `callback`.
|
||||
virtual void SaveAutofillProfile(
|
||||
const autofill::AutofillProfile& autofill_profile,
|
||||
base::OnceCallback<void(UserAnnotationsExecutionResult)> callback);
|
||||
|
||||
private:
|
||||
friend class TestUserAnnotationsService;
|
||||
friend class FormSubmissionHandler;
|
||||
|
||||
// Used in testing, to construct the service without encryptor and database.
|
||||
UserAnnotationsService();
|
||||
|
||||
// Called when the encryptor is ready.
|
||||
void OnOsCryptAsyncReady(const base::FilePath& storage_dir,
|
||||
os_crypt_async::Encryptor encryptor,
|
||||
bool success);
|
||||
|
||||
void InitializeFormsAnnotationsFromCommandLine(
|
||||
const optimization_guide::proto::FormsAnnotationsResponse&
|
||||
manual_entries);
|
||||
|
||||
// Returns whether the database initialization is complete.
|
||||
bool IsDatabaseReady();
|
||||
|
||||
// Starts the processing of next pending form submission.
|
||||
void ProcessNextFormSubmission();
|
||||
|
||||
// Saves the entries to database.
|
||||
void SaveEntries(
|
||||
const optimization_guide::proto::FormsAnnotationsResponse& entries);
|
||||
|
||||
// Called when the form submission is fully complete.
|
||||
void OnFormSubmissionComplete();
|
||||
|
||||
optimization_guide::OptimizationGuideModelExecutor* model_executor() {
|
||||
return model_executor_;
|
||||
}
|
||||
|
||||
base::WeakPtr<optimization_guide::ModelQualityLogsUploaderService>
|
||||
logs_uploader() {
|
||||
return logs_uploader_;
|
||||
}
|
||||
|
||||
// Database used to persist the user annotation entries.
|
||||
base::SequenceBound<UserAnnotationsDatabase> user_annotations_database_;
|
||||
|
||||
// Maintains the subscription for `OSCryptAsync` and cancels upon destruction.
|
||||
base::CallbackListSubscription encryptor_ready_subscription_;
|
||||
|
||||
// The model executor to use to normalize entries. Guaranteed to outlive
|
||||
// `this`.
|
||||
raw_ptr<optimization_guide::OptimizationGuideModelExecutor> model_executor_;
|
||||
|
||||
// The service used to upload model quality logs.
|
||||
base::WeakPtr<optimization_guide::ModelQualityLogsUploaderService>
|
||||
logs_uploader_;
|
||||
|
||||
// The optimization guide decider to determine whether to generate user
|
||||
// annotations for a page. Guaranteed to outlive `this`.
|
||||
raw_ptr<optimization_guide::OptimizationGuideDecider>
|
||||
optimization_guide_decider_;
|
||||
|
||||
// The override list for allowed hosts for forms annotations.
|
||||
// TODO: b/361692317 - Remove this once optimization guide actually populates
|
||||
// list.
|
||||
const std::vector<std::string> allowed_hosts_for_forms_annotations_;
|
||||
|
||||
// The queue of form submissions pending to be processed. Each form submission
|
||||
// goes through multiple stages of processing, and until then the form
|
||||
// submissions will wait in this queue. The first entry is the one that is
|
||||
// currently being processed.
|
||||
base::queue<std::unique_ptr<FormSubmissionHandler>> pending_form_submissions_;
|
||||
|
||||
base::WeakPtrFactory<UserAnnotationsService> weak_ptr_factory_{this};
|
||||
};
|
||||
|
||||
} // namespace user_annotations
|
||||
|
||||
#endif // COMPONENTS_USER_ANNOTATIONS_USER_ANNOTATIONS_SERVICE_H_
|
@ -1,570 +0,0 @@
|
||||
// Copyright 2024 The Chromium Authors
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "components/user_annotations/user_annotations_service.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "base/base64.h"
|
||||
#include "base/command_line.h"
|
||||
#include "base/files/scoped_temp_dir.h"
|
||||
#include "base/test/bind.h"
|
||||
#include "base/test/gmock_callback_support.h"
|
||||
#include "base/test/gmock_move_support.h"
|
||||
#include "base/test/metrics/histogram_tester.h"
|
||||
#include "base/test/mock_callback.h"
|
||||
#include "base/test/protobuf_matchers.h"
|
||||
#include "base/test/scoped_feature_list.h"
|
||||
#include "base/test/task_environment.h"
|
||||
#include "base/test/test_future.h"
|
||||
#include "components/autofill/core/browser/country_type.h"
|
||||
#include "components/autofill/core/browser/form_structure.h"
|
||||
#include "components/autofill/core/browser/test_utils/autofill_test_utils.h"
|
||||
#include "components/autofill/core/common/form_data.h"
|
||||
#include "components/autofill_ai/core/browser/autofill_ai_features.h"
|
||||
#include "components/optimization_guide/core/mock_optimization_guide_model_executor.h"
|
||||
#include "components/optimization_guide/core/model_execution/model_execution_prefs.h"
|
||||
#include "components/optimization_guide/core/model_quality/test_model_quality_logs_uploader_service.h"
|
||||
#include "components/optimization_guide/core/optimization_guide_proto_util.h"
|
||||
#include "components/optimization_guide/core/test_optimization_guide_decider.h"
|
||||
#include "components/optimization_guide/proto/features/common_quality_data.pb.h"
|
||||
#include "components/os_crypt/async/browser/os_crypt_async.h"
|
||||
#include "components/os_crypt/async/browser/test_utils.h"
|
||||
#include "components/prefs/testing_pref_service.h"
|
||||
#include "components/user_annotations/user_annotations_switches.h"
|
||||
#include "components/user_annotations/user_annotations_types.h"
|
||||
#include "testing/gmock/include/gmock/gmock.h"
|
||||
#include "testing/gtest/include/gtest/gtest.h"
|
||||
|
||||
namespace user_annotations {
|
||||
namespace {
|
||||
|
||||
using ::base::test::EqualsProto;
|
||||
using ::testing::_;
|
||||
using ::testing::An;
|
||||
using ::testing::IsEmpty;
|
||||
|
||||
class TestOptimizationGuideDecider
|
||||
: public optimization_guide::TestOptimizationGuideDecider {
|
||||
public:
|
||||
optimization_guide::OptimizationGuideDecision CanApplyOptimization(
|
||||
const GURL& url,
|
||||
optimization_guide::proto::OptimizationType optimization_type,
|
||||
optimization_guide::OptimizationMetadata* optimization_metadata)
|
||||
override {
|
||||
CHECK_EQ(optimization_type, optimization_guide::proto::FORMS_ANNOTATIONS);
|
||||
if (url.host() == "allowed.com") {
|
||||
return optimization_guide::OptimizationGuideDecision::kTrue;
|
||||
}
|
||||
return optimization_guide::OptimizationGuideDecision::kFalse;
|
||||
}
|
||||
};
|
||||
|
||||
class UserAnnotationsServiceTest : public testing::Test {
|
||||
public:
|
||||
void SetUp() override {
|
||||
InitializeFeatureList();
|
||||
CHECK(temp_dir_.CreateUniqueTempDir());
|
||||
optimization_guide::model_execution::prefs::RegisterLocalStatePrefs(
|
||||
local_state_.registry());
|
||||
os_crypt_ = os_crypt_async::GetTestOSCryptAsyncForTesting(
|
||||
/*is_sync_for_unittests=*/true);
|
||||
optimization_guide_decider_ =
|
||||
std::make_unique<TestOptimizationGuideDecider>();
|
||||
logs_service_ = std::make_unique<
|
||||
optimization_guide::TestModelQualityLogsUploaderService>(&local_state_);
|
||||
service_ = std::make_unique<UserAnnotationsService>(
|
||||
&model_executor_, logs_service_.get(), temp_dir_.GetPath(), os_crypt_.get(),
|
||||
optimization_guide_decider_.get());
|
||||
}
|
||||
|
||||
virtual void InitializeFeatureList() {
|
||||
scoped_feature_list_.InitAndEnableFeature(autofill_ai::kAutofillAi);
|
||||
}
|
||||
|
||||
UserAnnotationsEntries AddAndImportFormSubmission(
|
||||
optimization_guide::proto::AXTreeUpdate ax_tree_update,
|
||||
const autofill::FormData& form_data) {
|
||||
UserAnnotationsEntries entries;
|
||||
std::unique_ptr<autofill::FormStructure> form =
|
||||
std::make_unique<autofill::FormStructure>(form_data);
|
||||
service()->AddFormSubmission(
|
||||
GURL("example.com"), "title", ax_tree_update, std::move(form),
|
||||
base::BindLambdaForTesting(
|
||||
[&entries](std::unique_ptr<autofill::FormStructure> form,
|
||||
std::unique_ptr<user_annotations::FormAnnotationResponse>
|
||||
form_annotation_response,
|
||||
PromptAcceptanceCallback prompt_acceptance_callback) {
|
||||
if (form_annotation_response) {
|
||||
entries = form_annotation_response->to_be_upserted_entries;
|
||||
}
|
||||
std::move(prompt_acceptance_callback)
|
||||
.Run({/*prompt_was_accepted=*/true,
|
||||
/*did_user_interact=*/true});
|
||||
}));
|
||||
task_environment_.RunUntilIdle();
|
||||
return entries;
|
||||
}
|
||||
|
||||
UserAnnotationsEntries GetAllUserAnnotationsEntries() {
|
||||
base::test::TestFuture<UserAnnotationsEntries> test_future;
|
||||
service()->RetrieveAllEntries(test_future.GetCallback());
|
||||
return test_future.Take();
|
||||
}
|
||||
|
||||
UserAnnotationsService* service() { return service_.get(); }
|
||||
|
||||
optimization_guide::MockOptimizationGuideModelExecutor* model_executor() {
|
||||
return &model_executor_;
|
||||
}
|
||||
|
||||
TestOptimizationGuideDecider* optimization_guide_decider() {
|
||||
return optimization_guide_decider_.get();
|
||||
}
|
||||
|
||||
optimization_guide::TestModelQualityLogsUploaderService* logs_service() {
|
||||
return logs_service_.get();
|
||||
}
|
||||
|
||||
std::unique_ptr<optimization_guide::ModelQualityLogEntry> CreateLogEntry() {
|
||||
return std::make_unique<optimization_guide::ModelQualityLogEntry>(
|
||||
logs_service_->GetWeakPtr());
|
||||
}
|
||||
|
||||
protected:
|
||||
base::test::ScopedFeatureList scoped_feature_list_;
|
||||
base::test::TaskEnvironment task_environment_{
|
||||
base::test::TaskEnvironment::TimeSource::MOCK_TIME};
|
||||
base::ScopedTempDir temp_dir_;
|
||||
TestingPrefServiceSimple local_state_;
|
||||
std::unique_ptr<optimization_guide::TestModelQualityLogsUploaderService>
|
||||
logs_service_;
|
||||
testing::NiceMock<optimization_guide::MockOptimizationGuideModelExecutor>
|
||||
model_executor_;
|
||||
std::unique_ptr<os_crypt_async::OSCryptAsync> os_crypt_;
|
||||
std::unique_ptr<TestOptimizationGuideDecider> optimization_guide_decider_;
|
||||
std::unique_ptr<UserAnnotationsService> service_;
|
||||
};
|
||||
|
||||
TEST_F(UserAnnotationsServiceTest, FormsAnnotationsTypeRegistered) {
|
||||
EXPECT_TRUE(base::Contains(
|
||||
optimization_guide_decider()->registered_optimization_types(),
|
||||
optimization_guide::proto::FORMS_ANNOTATIONS));
|
||||
}
|
||||
|
||||
TEST_F(UserAnnotationsServiceTest, ShouldAddFormSubmissionForURL) {
|
||||
EXPECT_FALSE(service()->ShouldAddFormSubmissionForURL(
|
||||
GURL("https://notallowed.com/whatever")));
|
||||
EXPECT_TRUE(service()->ShouldAddFormSubmissionForURL(
|
||||
GURL("https://allowed.com/whatever")));
|
||||
// Allowed host but not HTTPS.
|
||||
EXPECT_FALSE(service()->ShouldAddFormSubmissionForURL(
|
||||
GURL("http://allowed.com/whatever")));
|
||||
}
|
||||
|
||||
TEST_F(UserAnnotationsServiceTest, RetrieveAllEntriesNoDB) {
|
||||
base::HistogramTester histogram_tester;
|
||||
auto entries = GetAllUserAnnotationsEntries();
|
||||
histogram_tester.ExpectUniqueSample("UserAnnotations.EntryCount", 0, 1);
|
||||
EXPECT_TRUE(entries.empty());
|
||||
}
|
||||
|
||||
struct FormsAnnotationsTestRequest {
|
||||
optimization_guide::proto::Any forms_annotations_response;
|
||||
optimization_guide::proto::AXTreeUpdate ax_tree;
|
||||
autofill::FormData form_data;
|
||||
GURL url;
|
||||
std::string title;
|
||||
};
|
||||
|
||||
struct Entry {
|
||||
size_t entry_id;
|
||||
std::string key;
|
||||
std::string value;
|
||||
};
|
||||
|
||||
// Returns sample annotations for tests.
|
||||
FormsAnnotationsTestRequest CreateSampleFormsAnnotationsTestRequest(
|
||||
const std::vector<std::vector<std::u16string>>& request_entries =
|
||||
{
|
||||
{u"label", u"", u"whatever"},
|
||||
{u"", u"nolabel", u"value"},
|
||||
},
|
||||
const std::vector<Entry>& response_upserted_entries = {
|
||||
{0, "label", "whatever"},
|
||||
{0, "nolabel", "value"},
|
||||
}) {
|
||||
optimization_guide::proto::FormsAnnotationsResponse response;
|
||||
for (const auto& entry : response_upserted_entries) {
|
||||
optimization_guide::proto::UserAnnotationsEntry* new_entry =
|
||||
response.add_upserted_entries();
|
||||
new_entry->set_entry_id(entry.entry_id);
|
||||
new_entry->set_key(entry.key);
|
||||
new_entry->set_value(entry.value);
|
||||
}
|
||||
|
||||
std::vector<autofill::FormFieldData> form_fields;
|
||||
for (const auto& entry : request_entries) {
|
||||
autofill::FormFieldData form_field;
|
||||
form_field.set_label(entry[0]);
|
||||
form_field.set_name(entry[1]);
|
||||
form_field.set_value(entry[2]);
|
||||
form_fields.push_back(form_field);
|
||||
}
|
||||
autofill::FormData form_data;
|
||||
form_data.set_fields(form_fields);
|
||||
optimization_guide::proto::AXTreeUpdate ax_tree;
|
||||
ax_tree.mutable_tree_data()->set_title("title");
|
||||
|
||||
return {optimization_guide::AnyWrapProto(response), ax_tree, form_data,
|
||||
GURL("example.com"), "title"};
|
||||
}
|
||||
|
||||
TEST_F(UserAnnotationsServiceTest, ExecuteFailed) {
|
||||
base::HistogramTester histogram_tester;
|
||||
|
||||
EXPECT_CALL(
|
||||
*model_executor(),
|
||||
ExecuteModel(
|
||||
optimization_guide::ModelBasedCapabilityKey::kFormsAnnotations, _, _,
|
||||
An<optimization_guide::
|
||||
OptimizationGuideModelExecutionResultCallback>()))
|
||||
.WillOnce(base::test::RunOnceCallback<3>(
|
||||
optimization_guide::OptimizationGuideModelExecutionResult(
|
||||
base::unexpected(
|
||||
optimization_guide::OptimizationGuideModelExecutionError::
|
||||
FromModelExecutionError(
|
||||
optimization_guide::
|
||||
OptimizationGuideModelExecutionError::
|
||||
ModelExecutionError::kGenericFailure)),
|
||||
nullptr),
|
||||
CreateLogEntry()));
|
||||
|
||||
autofill::FormFieldData form_field_data;
|
||||
form_field_data.set_label(u"label");
|
||||
form_field_data.set_value(u"whatever");
|
||||
autofill::FormFieldData form_field_data2;
|
||||
form_field_data2.set_name(u"nolabel");
|
||||
form_field_data2.set_value(u"value");
|
||||
autofill::FormData form_data;
|
||||
form_data.set_fields({form_field_data, form_field_data2});
|
||||
optimization_guide::proto::AXTreeUpdate ax_tree;
|
||||
|
||||
EXPECT_TRUE(AddAndImportFormSubmission(ax_tree, form_data).empty());
|
||||
|
||||
histogram_tester.ExpectUniqueSample(
|
||||
"UserAnnotations.AddFormSubmissionResult",
|
||||
UserAnnotationsExecutionResult::kResponseError, 1);
|
||||
|
||||
EXPECT_TRUE(logs_service()->uploaded_logs().empty());
|
||||
}
|
||||
|
||||
TEST_F(UserAnnotationsServiceTest, UnexpectedResponseType) {
|
||||
base::HistogramTester histogram_tester;
|
||||
|
||||
optimization_guide::proto::Any any;
|
||||
EXPECT_CALL(
|
||||
*model_executor(),
|
||||
ExecuteModel(
|
||||
optimization_guide::ModelBasedCapabilityKey::kFormsAnnotations, _, _,
|
||||
An<optimization_guide::
|
||||
OptimizationGuideModelExecutionResultCallback>()))
|
||||
.WillOnce(base::test::RunOnceCallback<3>(
|
||||
optimization_guide::OptimizationGuideModelExecutionResult(any,
|
||||
nullptr),
|
||||
CreateLogEntry()));
|
||||
|
||||
autofill::FormFieldData form_field_data;
|
||||
form_field_data.set_label(u"label");
|
||||
form_field_data.set_value(u"whatever");
|
||||
autofill::FormFieldData form_field_data2;
|
||||
form_field_data2.set_name(u"nolabel");
|
||||
form_field_data2.set_value(u"value");
|
||||
autofill::FormData form_data;
|
||||
form_data.set_fields({form_field_data, form_field_data2});
|
||||
optimization_guide::proto::AXTreeUpdate ax_tree;
|
||||
EXPECT_TRUE(AddAndImportFormSubmission(ax_tree, form_data).empty());
|
||||
|
||||
histogram_tester.ExpectUniqueSample(
|
||||
"UserAnnotations.AddFormSubmissionResult",
|
||||
UserAnnotationsExecutionResult::kResponseMalformed, 1);
|
||||
|
||||
EXPECT_TRUE(logs_service()->uploaded_logs().empty());
|
||||
}
|
||||
|
||||
TEST_F(UserAnnotationsServiceTest, RemoveEntry) {
|
||||
base::HistogramTester histogram_tester;
|
||||
auto test_request = CreateSampleFormsAnnotationsTestRequest();
|
||||
EXPECT_CALL(
|
||||
*model_executor(),
|
||||
ExecuteModel(
|
||||
optimization_guide::ModelBasedCapabilityKey::kFormsAnnotations, _, _,
|
||||
An<optimization_guide::
|
||||
OptimizationGuideModelExecutionResultCallback>()))
|
||||
.WillOnce(base::test::RunOnceCallback<3>(
|
||||
optimization_guide::OptimizationGuideModelExecutionResult(
|
||||
test_request.forms_annotations_response, nullptr),
|
||||
CreateLogEntry()));
|
||||
|
||||
EXPECT_FALSE(
|
||||
AddAndImportFormSubmission(test_request.ax_tree, test_request.form_data)
|
||||
.empty());
|
||||
|
||||
auto entries = GetAllUserAnnotationsEntries();
|
||||
EXPECT_EQ(2u, entries.size());
|
||||
|
||||
base::test::TestFuture<void> test_future_remove_entry;
|
||||
service()->RemoveEntry(entries[0].entry_id(),
|
||||
test_future_remove_entry.GetCallback());
|
||||
EXPECT_TRUE(test_future_remove_entry.Wait());
|
||||
test_future_remove_entry.Clear();
|
||||
EXPECT_EQ(1u, GetAllUserAnnotationsEntries().size());
|
||||
histogram_tester.ExpectUniqueSample("UserAnnotations.RemoveEntry.Result",
|
||||
UserAnnotationsExecutionResult::kSuccess,
|
||||
1);
|
||||
|
||||
service()->RemoveEntry(entries[1].entry_id(),
|
||||
test_future_remove_entry.GetCallback());
|
||||
EXPECT_TRUE(test_future_remove_entry.Wait());
|
||||
histogram_tester.ExpectUniqueSample("UserAnnotations.RemoveEntry.Result",
|
||||
UserAnnotationsExecutionResult::kSuccess,
|
||||
2);
|
||||
EXPECT_TRUE(GetAllUserAnnotationsEntries().empty());
|
||||
}
|
||||
|
||||
TEST_F(UserAnnotationsServiceTest, RemoveAllEntries) {
|
||||
base::HistogramTester histogram_tester;
|
||||
auto test_request = CreateSampleFormsAnnotationsTestRequest();
|
||||
EXPECT_CALL(
|
||||
*model_executor(),
|
||||
ExecuteModel(
|
||||
optimization_guide::ModelBasedCapabilityKey::kFormsAnnotations, _, _,
|
||||
An<optimization_guide::
|
||||
OptimizationGuideModelExecutionResultCallback>()))
|
||||
.WillOnce(base::test::RunOnceCallback<3>(
|
||||
optimization_guide::OptimizationGuideModelExecutionResult(
|
||||
test_request.forms_annotations_response, nullptr),
|
||||
CreateLogEntry()));
|
||||
|
||||
EXPECT_FALSE(
|
||||
AddAndImportFormSubmission(test_request.ax_tree, test_request.form_data)
|
||||
.empty());
|
||||
|
||||
EXPECT_EQ(2u, GetAllUserAnnotationsEntries().size());
|
||||
|
||||
base::test::TestFuture<void> test_future_remove_entry;
|
||||
service()->RemoveAllEntries(test_future_remove_entry.GetCallback());
|
||||
EXPECT_TRUE(test_future_remove_entry.Wait());
|
||||
histogram_tester.ExpectUniqueSample("UserAnnotations.RemoveAllEntries.Result",
|
||||
UserAnnotationsExecutionResult::kSuccess,
|
||||
1);
|
||||
EXPECT_TRUE(GetAllUserAnnotationsEntries().empty());
|
||||
}
|
||||
|
||||
TEST_F(UserAnnotationsServiceTest, FormNotImported) {
|
||||
base::HistogramTester histogram_tester;
|
||||
auto test_request = CreateSampleFormsAnnotationsTestRequest();
|
||||
EXPECT_CALL(
|
||||
*model_executor(),
|
||||
ExecuteModel(
|
||||
optimization_guide::ModelBasedCapabilityKey::kFormsAnnotations, _, _,
|
||||
An<optimization_guide::
|
||||
OptimizationGuideModelExecutionResultCallback>()))
|
||||
.WillOnce(base::test::RunOnceCallback<3>(
|
||||
optimization_guide::OptimizationGuideModelExecutionResult(
|
||||
test_request.forms_annotations_response, nullptr),
|
||||
CreateLogEntry()));
|
||||
|
||||
service()->AddFormSubmission(
|
||||
test_request.url, test_request.title, test_request.ax_tree,
|
||||
std::make_unique<autofill::FormStructure>(test_request.form_data),
|
||||
base::BindLambdaForTesting(
|
||||
[](std::unique_ptr<autofill::FormStructure> form,
|
||||
std::unique_ptr<user_annotations::FormAnnotationResponse>
|
||||
form_annotation_response,
|
||||
PromptAcceptanceCallback prompt_acceptance_callback) {
|
||||
std::move(prompt_acceptance_callback)
|
||||
.Run({/*prompt_was_accepted=*/false});
|
||||
}));
|
||||
|
||||
EXPECT_TRUE(GetAllUserAnnotationsEntries().empty());
|
||||
}
|
||||
|
||||
TEST_F(UserAnnotationsServiceTest, ParallelFormSubmissions) {
|
||||
base::HistogramTester histogram_tester;
|
||||
auto first_test_request = CreateSampleFormsAnnotationsTestRequest();
|
||||
optimization_guide::OptimizationGuideModelExecutionResultCallback
|
||||
first_execute_callback,
|
||||
second_execute_callback;
|
||||
PromptAcceptanceCallback first_prompt_acceptance_callback,
|
||||
second_prompt_acceptance_callback;
|
||||
EXPECT_CALL(
|
||||
*model_executor(),
|
||||
ExecuteModel(
|
||||
optimization_guide::ModelBasedCapabilityKey::kFormsAnnotations, _, _,
|
||||
An<optimization_guide::
|
||||
OptimizationGuideModelExecutionResultCallback>()))
|
||||
.WillOnce(MoveArg<3>(&first_execute_callback))
|
||||
.WillOnce(MoveArg<3>(&second_execute_callback));
|
||||
|
||||
service()->AddFormSubmission(
|
||||
first_test_request.url, first_test_request.title,
|
||||
first_test_request.ax_tree,
|
||||
std::make_unique<autofill::FormStructure>(first_test_request.form_data),
|
||||
base::BindLambdaForTesting(
|
||||
[&first_prompt_acceptance_callback](
|
||||
std::unique_ptr<autofill::FormStructure> form,
|
||||
std::unique_ptr<user_annotations::FormAnnotationResponse>
|
||||
form_annotation_response,
|
||||
PromptAcceptanceCallback callback) {
|
||||
first_prompt_acceptance_callback = std::move(callback);
|
||||
}));
|
||||
|
||||
auto second_test_request =
|
||||
CreateSampleFormsAnnotationsTestRequest(/*request_entries=*/
|
||||
{
|
||||
{u"label", u"", u"whatever"},
|
||||
{u"", u"nolabel", u"value"},
|
||||
},
|
||||
/*response_upserted_entries=*/{
|
||||
{1, "label", "new_value"},
|
||||
{2, "nolabel",
|
||||
"new_nolabel_value"},
|
||||
});
|
||||
|
||||
service()->AddFormSubmission(
|
||||
second_test_request.url, second_test_request.title,
|
||||
second_test_request.ax_tree,
|
||||
std::make_unique<autofill::FormStructure>(second_test_request.form_data),
|
||||
base::BindLambdaForTesting(
|
||||
[&second_prompt_acceptance_callback](
|
||||
std::unique_ptr<autofill::FormStructure> form,
|
||||
std::unique_ptr<user_annotations::FormAnnotationResponse>
|
||||
form_annotation_response,
|
||||
PromptAcceptanceCallback callback) {
|
||||
second_prompt_acceptance_callback = std::move(callback);
|
||||
}));
|
||||
|
||||
// Only the first model execute should happen.
|
||||
task_environment_.RunUntilIdle();
|
||||
EXPECT_TRUE(first_execute_callback);
|
||||
EXPECT_FALSE(second_execute_callback);
|
||||
std::move(first_execute_callback)
|
||||
.Run(optimization_guide::OptimizationGuideModelExecutionResult(
|
||||
first_test_request.forms_annotations_response, nullptr),
|
||||
CreateLogEntry());
|
||||
|
||||
// Only the first prompt acceptance call should happen.
|
||||
task_environment_.RunUntilIdle();
|
||||
EXPECT_FALSE(second_execute_callback);
|
||||
EXPECT_TRUE(first_prompt_acceptance_callback);
|
||||
std::move(first_prompt_acceptance_callback)
|
||||
.Run({/*prompt_was_accepted=*/true, /*did_user_interact=*/true});
|
||||
histogram_tester.ExpectUniqueSample("UserAnnotations.AddFormSubmissionResult",
|
||||
UserAnnotationsExecutionResult::kSuccess,
|
||||
1);
|
||||
|
||||
auto entries = GetAllUserAnnotationsEntries();
|
||||
EXPECT_EQ(2u, entries.size());
|
||||
EXPECT_EQ(entries[0].key(), "label");
|
||||
EXPECT_EQ(entries[0].value(), "whatever");
|
||||
EXPECT_EQ(entries[1].key(), "nolabel");
|
||||
EXPECT_EQ(entries[1].value(), "value");
|
||||
|
||||
// Now the second form submission should happen.
|
||||
task_environment_.RunUntilIdle();
|
||||
std::move(second_execute_callback)
|
||||
.Run(optimization_guide::OptimizationGuideModelExecutionResult(
|
||||
second_test_request.forms_annotations_response, nullptr),
|
||||
CreateLogEntry());
|
||||
task_environment_.RunUntilIdle();
|
||||
std::move(second_prompt_acceptance_callback)
|
||||
.Run({/*prompt_was_accepted=*/true, /*did_user_interact=*/true});
|
||||
|
||||
histogram_tester.ExpectUniqueSample("UserAnnotations.AddFormSubmissionResult",
|
||||
UserAnnotationsExecutionResult::kSuccess,
|
||||
2);
|
||||
|
||||
entries = GetAllUserAnnotationsEntries();
|
||||
EXPECT_EQ(2u, entries.size());
|
||||
EXPECT_EQ(entries[0].key(), "label");
|
||||
EXPECT_EQ(entries[0].value(), "new_value");
|
||||
EXPECT_EQ(entries[1].key(), "nolabel");
|
||||
EXPECT_EQ(entries[1].value(), "new_nolabel_value");
|
||||
}
|
||||
|
||||
TEST_F(UserAnnotationsServiceTest, SaveAutofillProfile) {
|
||||
base::HistogramTester histogram_tester;
|
||||
autofill::AutofillProfile autofill_profile(AddressCountryCode("US"));
|
||||
autofill::test::SetProfileInfo(&autofill_profile, "Jane", "J", "Doe",
|
||||
"jd@example.com", "", "123 Main St", "",
|
||||
"Raleigh", "NC", "12345", "US", "9195555555");
|
||||
base::test::TestFuture<UserAnnotationsExecutionResult> test_future;
|
||||
service()->SaveAutofillProfile(autofill_profile, test_future.GetCallback());
|
||||
ASSERT_TRUE(test_future.Wait());
|
||||
const UserAnnotationsEntries entries = GetAllUserAnnotationsEntries();
|
||||
histogram_tester.ExpectUniqueSample("UserAnnotations.EntryCount", 10, 1);
|
||||
EXPECT_EQ(entries.size(), 10u);
|
||||
EXPECT_EQ(entries[0].key(), "First Name");
|
||||
EXPECT_EQ(entries[0].value(), "Jane");
|
||||
EXPECT_EQ(entries[1].key(), "Middle Name");
|
||||
EXPECT_EQ(entries[1].value(), "J");
|
||||
EXPECT_EQ(entries[2].key(), "Last Name");
|
||||
EXPECT_EQ(entries[2].value(), "Doe");
|
||||
EXPECT_EQ(entries[3].key(), "Email Address");
|
||||
EXPECT_EQ(entries[3].value(), "jd@example.com");
|
||||
EXPECT_EQ(entries[4].key(), "Phone Number [mobile]");
|
||||
EXPECT_EQ(entries[4].value(), "9195555555");
|
||||
EXPECT_EQ(entries[5].key(), "Address - City");
|
||||
EXPECT_EQ(entries[5].value(), "Raleigh");
|
||||
EXPECT_EQ(entries[6].key(), "Address - State");
|
||||
EXPECT_EQ(entries[6].value(), "NC");
|
||||
EXPECT_EQ(entries[7].key(), "Address - Zip Code");
|
||||
EXPECT_EQ(entries[7].value(), "12345");
|
||||
EXPECT_EQ(entries[8].key(), "Address - Country");
|
||||
EXPECT_EQ(entries[8].value(), "US");
|
||||
EXPECT_EQ(entries[9].key(), "Address - Street");
|
||||
EXPECT_EQ(entries[9].value(), "123 Main St");
|
||||
}
|
||||
|
||||
class UserAnnotationsServiceSeededAnnotationTest
|
||||
: public UserAnnotationsServiceTest {
|
||||
public:
|
||||
void SetUp() override {
|
||||
const std::vector<Entry>& response_upserted_entries = {
|
||||
{0, "label", "whatever"},
|
||||
{0, "nolabel", "value"},
|
||||
};
|
||||
optimization_guide::proto::FormsAnnotationsResponse response;
|
||||
for (const auto& entry : response_upserted_entries) {
|
||||
optimization_guide::proto::UserAnnotationsEntry* new_entry =
|
||||
response.add_upserted_entries();
|
||||
new_entry->set_entry_id(entry.entry_id);
|
||||
new_entry->set_key(entry.key);
|
||||
new_entry->set_value(entry.value);
|
||||
}
|
||||
|
||||
std::string encoded_annotations;
|
||||
response.SerializeToString(&encoded_annotations);
|
||||
encoded_annotations = base::Base64Encode(encoded_annotations);
|
||||
|
||||
base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
|
||||
switches::kFormsAnnotationsOverride, encoded_annotations);
|
||||
|
||||
UserAnnotationsServiceTest::SetUp();
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(UserAnnotationsServiceSeededAnnotationTest, SeedAnnotations) {
|
||||
task_environment_.RunUntilIdle();
|
||||
auto entries = GetAllUserAnnotationsEntries();
|
||||
EXPECT_EQ(2u, entries.size());
|
||||
EXPECT_EQ(entries[0].key(), "label");
|
||||
EXPECT_EQ(entries[0].value(), "whatever");
|
||||
EXPECT_EQ(entries[1].key(), "nolabel");
|
||||
EXPECT_EQ(entries[1].value(), "value");
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace user_annotations
|
@ -1,46 +0,0 @@
|
||||
#include "components/user_annotations/user_annotations_switches.h"
|
||||
|
||||
#include <optional>
|
||||
|
||||
#include "base/base64.h"
|
||||
#include "base/command_line.h"
|
||||
#include "base/logging.h"
|
||||
#include "base/strings/string_number_conversions.h"
|
||||
#include "base/strings/string_split.h"
|
||||
|
||||
namespace user_annotations {
|
||||
namespace switches {
|
||||
|
||||
// Overrides providing form annotations for seeding the annotation store.
|
||||
// The value should be a base64 encoded of an annotations response.
|
||||
const char kFormsAnnotationsOverride[] =
|
||||
"user-annotations-forms-annotation-override";
|
||||
|
||||
std::optional<optimization_guide::proto::FormsAnnotationsResponse>
|
||||
ParseFormsAnnotationsFromCommandLine() {
|
||||
base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess();
|
||||
if (!cmd_line->HasSwitch(kFormsAnnotationsOverride)) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::string b64_pb = cmd_line->GetSwitchValueASCII(kFormsAnnotationsOverride);
|
||||
|
||||
std::string binary_pb;
|
||||
if (!base::Base64Decode(b64_pb, &binary_pb)) {
|
||||
LOG(ERROR) << "Invalid base64 encoding of the Hints Proto Override";
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
optimization_guide::proto::FormsAnnotationsResponse forms_annotations =
|
||||
optimization_guide::proto::FormsAnnotationsResponse();
|
||||
|
||||
if (!forms_annotations.ParseFromString(binary_pb)) {
|
||||
LOG(ERROR) << "Invalid proto provided to the Forms Annotation Override";
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
return forms_annotations;
|
||||
}
|
||||
|
||||
} // namespace switches
|
||||
} // namespace user_annotations
|
@ -1,19 +0,0 @@
|
||||
#ifndef COMPONENTS_USER_ANNOTATIONS_USER_ANNOTATIONS_SWITCHES_H_
|
||||
#define COMPONENTS_USER_ANNOTATIONS_USER_ANNOTATIONS_SWITCHES_H_
|
||||
|
||||
#include <optional>
|
||||
|
||||
#include "components/optimization_guide/proto/features/forms_annotations.pb.h"
|
||||
|
||||
namespace user_annotations {
|
||||
namespace switches {
|
||||
|
||||
extern const char kFormsAnnotationsOverride[];
|
||||
|
||||
std::optional<optimization_guide::proto::FormsAnnotationsResponse>
|
||||
ParseFormsAnnotationsFromCommandLine();
|
||||
|
||||
} // namespace switches
|
||||
} // namespace user_annotations
|
||||
|
||||
#endif // COMPONENTS_USER_ANNOTATIONS_USER_ANNOTATIONS_SWITCHES_H_
|
@ -1,69 +0,0 @@
|
||||
// Copyright 2024 The Chromium Authors
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "components/user_annotations/user_annotations_switches.h"
|
||||
|
||||
#include "base/base64.h"
|
||||
#include "base/command_line.h"
|
||||
#include "base/test/protobuf_matchers.h"
|
||||
#include "base/test/scoped_feature_list.h"
|
||||
#include "build/build_config.h"
|
||||
#include "components/user_annotations/user_annotations_features.h"
|
||||
#include "testing/gmock/include/gmock/gmock.h"
|
||||
#include "testing/gtest/include/gtest/gtest.h"
|
||||
|
||||
namespace user_annotations {
|
||||
|
||||
namespace {
|
||||
|
||||
using ::base::test::EqualsProto;
|
||||
using ::testing::UnorderedElementsAre;
|
||||
|
||||
struct Entry {
|
||||
size_t entry_id;
|
||||
std::string key;
|
||||
std::string value;
|
||||
};
|
||||
|
||||
TEST(UserAnnotationsSwitchesTest, OverrideFormsAnnotations) {
|
||||
const std::vector<Entry>& response_upserted_entries = {
|
||||
{0, "label", "whatever"},
|
||||
{0, "nolabel", "value"},
|
||||
};
|
||||
optimization_guide::proto::FormsAnnotationsResponse response;
|
||||
for (const auto& entry : response_upserted_entries) {
|
||||
optimization_guide::proto::UserAnnotationsEntry* new_entry =
|
||||
response.add_upserted_entries();
|
||||
new_entry->set_entry_id(entry.entry_id);
|
||||
new_entry->set_key(entry.key);
|
||||
new_entry->set_value(entry.value);
|
||||
}
|
||||
|
||||
std::string encoded_annotations;
|
||||
response.SerializeToString(&encoded_annotations);
|
||||
encoded_annotations = base::Base64Encode(encoded_annotations);
|
||||
|
||||
base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
|
||||
switches::kFormsAnnotationsOverride, encoded_annotations);
|
||||
|
||||
auto output = switches::ParseFormsAnnotationsFromCommandLine();
|
||||
|
||||
EXPECT_TRUE(output.has_value());
|
||||
EXPECT_THAT(output.value(), EqualsProto(response));
|
||||
}
|
||||
|
||||
TEST(UserAnnotationsSwitchesTest, OverrideFormsAnnotationsBadFormat) {
|
||||
std::string encoded_annotations = "Not a proto";
|
||||
encoded_annotations = base::Base64Encode(encoded_annotations);
|
||||
|
||||
base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
|
||||
switches::kFormsAnnotationsOverride, encoded_annotations);
|
||||
|
||||
auto output = switches::ParseFormsAnnotationsFromCommandLine();
|
||||
|
||||
EXPECT_FALSE(output.has_value());
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace user_annotations
|
@ -1,18 +0,0 @@
|
||||
// Copyright 2024 The Chromium Authors
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "components/user_annotations/user_annotations_types.h"
|
||||
|
||||
namespace user_annotations {
|
||||
|
||||
FormAnnotationResponse::FormAnnotationResponse(
|
||||
const std::vector<optimization_guide::proto::UserAnnotationsEntry>&
|
||||
to_be_upserted_entries,
|
||||
const std::string& model_execution_id)
|
||||
: to_be_upserted_entries(to_be_upserted_entries),
|
||||
model_execution_id(model_execution_id) {}
|
||||
|
||||
FormAnnotationResponse::~FormAnnotationResponse() = default;
|
||||
|
||||
} // namespace user_annotations
|
@ -1,95 +0,0 @@
|
||||
// Copyright 2024 The Chromium Authors
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef COMPONENTS_USER_ANNOTATIONS_USER_ANNOTATIONS_TYPES_H_
|
||||
#define COMPONENTS_USER_ANNOTATIONS_USER_ANNOTATIONS_TYPES_H_
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "base/functional/callback_forward.h"
|
||||
#include "base/types/expected.h"
|
||||
#include "components/optimization_guide/proto/features/common_quality_data.pb.h"
|
||||
|
||||
namespace optimization_guide::proto {
|
||||
class UserAnnotationsEntry;
|
||||
}
|
||||
|
||||
namespace autofill {
|
||||
class FormStructure;
|
||||
} // namespace autofill
|
||||
|
||||
namespace user_annotations {
|
||||
|
||||
typedef int64_t EntryID;
|
||||
|
||||
typedef std::vector<optimization_guide::proto::UserAnnotationsEntry>
|
||||
UserAnnotationsEntries;
|
||||
|
||||
struct Entry {
|
||||
// The row ID of this entry from the user annotations database. This is
|
||||
// immutable except when retrieving the row from the database.
|
||||
EntryID entry_id;
|
||||
|
||||
// The proto for this entry.
|
||||
optimization_guide::proto::UserAnnotationsEntry entry_proto;
|
||||
};
|
||||
|
||||
// Encapsulates the result of various operations with user annotations entries.
|
||||
enum class UserAnnotationsExecutionResult {
|
||||
kSuccess = 0,
|
||||
kSqlError = 1,
|
||||
kCryptNotInitialized = 2,
|
||||
kCryptError = 3,
|
||||
kResponseError = 4,
|
||||
kResponseMalformed = 5,
|
||||
kResponseTimedOut = 6,
|
||||
|
||||
// Insert new values before this line. Should be in sync with
|
||||
// UserAnnotationsExecutionResult in user_annotations/enums.xml
|
||||
kMaxValue = kResponseTimedOut
|
||||
};
|
||||
|
||||
using UserAnnotationsEntryRetrievalResult =
|
||||
base::expected<std::vector<optimization_guide::proto::UserAnnotationsEntry>,
|
||||
UserAnnotationsExecutionResult>;
|
||||
|
||||
// Encapsulates the result of user interaction with the prediction improvements
|
||||
// prompt.
|
||||
struct PromptAcceptanceResult {
|
||||
bool prompt_was_accepted = false;
|
||||
bool did_user_interact = false;
|
||||
bool did_thumbs_up_triggered = false;
|
||||
bool did_thumbs_down_triggered = false;
|
||||
};
|
||||
|
||||
// Encapsulates the result of annotating a form submission.
|
||||
// `to_be_upserted_entries` is the updated entries, that will be shown in the
|
||||
// Autofill prediction improvements prompt. `model_execution_id` is the server
|
||||
// log id for model execution, and can be sent in any user submitted feedback.
|
||||
struct FormAnnotationResponse {
|
||||
std::vector<optimization_guide::proto::UserAnnotationsEntry>
|
||||
to_be_upserted_entries;
|
||||
std::string model_execution_id;
|
||||
|
||||
FormAnnotationResponse(
|
||||
const std::vector<optimization_guide::proto::UserAnnotationsEntry>&
|
||||
to_be_upserted_entries,
|
||||
const std::string& model_execution_id);
|
||||
~FormAnnotationResponse();
|
||||
};
|
||||
|
||||
using PromptAcceptanceCallback =
|
||||
base::OnceCallback<void(PromptAcceptanceResult result)>;
|
||||
|
||||
// Callback for notifying the form annotation result to Autofill. User decision
|
||||
// for importing the updated form entries is notified to
|
||||
// `UserAnnotationsService` via the `prompt_acceptance_callback`.
|
||||
using ImportFormCallback = base::OnceCallback<void(
|
||||
std::unique_ptr<autofill::FormStructure> form,
|
||||
std::unique_ptr<FormAnnotationResponse> form_annotation_response,
|
||||
PromptAcceptanceCallback prompt_acceptance_callback)>;
|
||||
|
||||
} // namespace user_annotations
|
||||
|
||||
#endif // COMPONENTS_USER_ANNOTATIONS_USER_ANNOTATIONS_TYPES_H_
|
@ -161,8 +161,6 @@ static_library("test_support") {
|
||||
"//components/prefs:test_support",
|
||||
"//components/sync_preferences:test_support",
|
||||
"//components/update_client",
|
||||
"//components/user_annotations",
|
||||
"//components/user_annotations:test_support",
|
||||
"//components/user_prefs",
|
||||
"//content/public/common",
|
||||
"//content/test:test_support",
|
||||
|
@ -66,7 +66,6 @@ CreateCounterForProfileAndPref(ProfileIOS* profile,
|
||||
autofill::PersonalDataManagerFactory::GetForProfile(profile),
|
||||
ios::WebDataServiceFactory::GetAutofillWebDataForProfile(
|
||||
profile, ServiceAccessType::EXPLICIT_ACCESS),
|
||||
/*user_annotations_service=*/nullptr,
|
||||
SyncServiceFactory::GetForProfile(profile));
|
||||
}
|
||||
|
||||
|
@ -193,10 +193,9 @@ class QuickDeleteMediatorTest : public PlatformTest {
|
||||
void triggerUpdateUICallbackForAutofillResults(int num_suggestions,
|
||||
int num_cards,
|
||||
int num_addresses) {
|
||||
browsing_data::AutofillCounter autofillCounter(nullptr, nullptr, nullptr,
|
||||
nullptr);
|
||||
browsing_data::AutofillCounter autofillCounter(nullptr, nullptr, nullptr);
|
||||
const browsing_data::AutofillCounter::AutofillResult autofillResult(
|
||||
&autofillCounter, num_suggestions, num_cards, num_addresses, 0, false);
|
||||
&autofillCounter, num_suggestions, num_cards, num_addresses, false);
|
||||
OCMExpect([consumer_
|
||||
setAutofillSummary:quick_delete_util::GetCounterTextFromResult(
|
||||
autofillResult, timeRange())]);
|
||||
@ -410,11 +409,11 @@ TEST_F(QuickDeleteMediatorTest, TestAddressesSummary) {
|
||||
triggerUpdateUICallbackForPasswordsResults(0);
|
||||
|
||||
// clang-format off
|
||||
const struct TestCase {
|
||||
int num_addresses;
|
||||
bool sync_enabled;
|
||||
NSString* expected_output;
|
||||
} kTestCases[] = {
|
||||
const struct TestCase {
|
||||
int num_addresses;
|
||||
bool sync_enabled;
|
||||
NSString* expected_output;
|
||||
} kTestCases[] = {
|
||||
{0, true, l10n_util::GetNSString(
|
||||
IDS_IOS_DELETE_BROWSING_DATA_SUMMARY_NO_DATA)},
|
||||
{0, false, l10n_util::GetNSString(
|
||||
@ -427,14 +426,14 @@ TEST_F(QuickDeleteMediatorTest, TestAddressesSummary) {
|
||||
IDS_IOS_DELETE_BROWSING_DATA_SUMMARY_ADRESSES, 2)},
|
||||
{2, false, l10n_util::GetPluralNSStringF(
|
||||
IDS_IOS_DELETE_BROWSING_DATA_SUMMARY_ADRESSES, 2)},
|
||||
};
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
browsing_data::AutofillCounter counter(nullptr, nullptr, nullptr, nullptr);
|
||||
browsing_data::AutofillCounter counter(nullptr, nullptr, nullptr);
|
||||
|
||||
for (const TestCase& test_case : kTestCases) {
|
||||
const browsing_data::AutofillCounter::AutofillResult result(
|
||||
&counter, 0, 0, test_case.num_addresses, 0, test_case.sync_enabled);
|
||||
&counter, 0, 0, test_case.num_addresses, test_case.sync_enabled);
|
||||
OCMExpect([consumer_ setBrowsingDataSummary:test_case.expected_output]);
|
||||
OCMExpect([consumer_
|
||||
setAutofillSummary:quick_delete_util::GetCounterTextFromResult(
|
||||
@ -462,11 +461,11 @@ TEST_F(QuickDeleteMediatorTest, TestCardsSummary) {
|
||||
triggerUpdateUICallbackForPasswordsResults(0);
|
||||
|
||||
// clang-format off
|
||||
const struct TestCase {
|
||||
int num_cards;
|
||||
bool sync_enabled;
|
||||
NSString* expected_output;
|
||||
} kTestCases[] = {
|
||||
const struct TestCase {
|
||||
int num_cards;
|
||||
bool sync_enabled;
|
||||
NSString* expected_output;
|
||||
} kTestCases[] = {
|
||||
{0, true, l10n_util::GetNSString(
|
||||
IDS_IOS_DELETE_BROWSING_DATA_SUMMARY_NO_DATA)},
|
||||
{0, false, l10n_util::GetNSString(
|
||||
@ -479,14 +478,14 @@ TEST_F(QuickDeleteMediatorTest, TestCardsSummary) {
|
||||
IDS_IOS_DELETE_BROWSING_DATA_SUMMARY_PAYMENT_METHODS, 2)},
|
||||
{2, false, l10n_util::GetPluralNSStringF(
|
||||
IDS_IOS_DELETE_BROWSING_DATA_SUMMARY_PAYMENT_METHODS, 2)},
|
||||
};
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
browsing_data::AutofillCounter counter(nullptr, nullptr, nullptr, nullptr);
|
||||
browsing_data::AutofillCounter counter(nullptr, nullptr, nullptr);
|
||||
|
||||
for (const TestCase& test_case : kTestCases) {
|
||||
const browsing_data::AutofillCounter::AutofillResult result(
|
||||
&counter, 0, test_case.num_cards, 0, 0, test_case.sync_enabled);
|
||||
&counter, 0, test_case.num_cards, 0, test_case.sync_enabled);
|
||||
|
||||
OCMExpect([consumer_ setBrowsingDataSummary:test_case.expected_output]);
|
||||
OCMExpect([consumer_
|
||||
@ -516,11 +515,11 @@ TEST_F(QuickDeleteMediatorTest, TestSuggestionsSummary) {
|
||||
triggerUpdateUICallbackForPasswordsResults(0);
|
||||
|
||||
// clang-format off
|
||||
const struct TestCase {
|
||||
int num_suggestions;
|
||||
bool sync_enabled;
|
||||
NSString* expected_output;
|
||||
} kTestCases[] = {
|
||||
const struct TestCase {
|
||||
int num_suggestions;
|
||||
bool sync_enabled;
|
||||
NSString* expected_output;
|
||||
} kTestCases[] = {
|
||||
{0, true, l10n_util::GetNSString(
|
||||
IDS_IOS_DELETE_BROWSING_DATA_SUMMARY_NO_DATA)},
|
||||
{0, false, l10n_util::GetNSString(
|
||||
@ -535,14 +534,14 @@ TEST_F(QuickDeleteMediatorTest, TestSuggestionsSummary) {
|
||||
2)},
|
||||
{2, false, l10n_util::GetPluralNSStringF(
|
||||
IDS_IOS_DELETE_BROWSING_DATA_SUMMARY_SUGGESTIONS, 2)},
|
||||
};
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
browsing_data::AutofillCounter counter(nullptr, nullptr, nullptr, nullptr);
|
||||
browsing_data::AutofillCounter counter(nullptr, nullptr, nullptr);
|
||||
|
||||
for (const TestCase& test_case : kTestCases) {
|
||||
const browsing_data::AutofillCounter::AutofillResult result(
|
||||
&counter, test_case.num_suggestions, 0, 0, 0, test_case.sync_enabled);
|
||||
&counter, test_case.num_suggestions, 0, 0, test_case.sync_enabled);
|
||||
OCMExpect([consumer_ setBrowsingDataSummary:test_case.expected_output]);
|
||||
OCMExpect([consumer_
|
||||
setAutofillSummary:quick_delete_util::GetCounterTextFromResult(
|
||||
|
@ -278,8 +278,6 @@ histograms_xml_files = [
|
||||
"//tools/metrics/histograms/metadata/uma/enums.xml",
|
||||
"//tools/metrics/histograms/metadata/uma/histograms.xml",
|
||||
"//tools/metrics/histograms/metadata/update_engine/histograms.xml",
|
||||
"//tools/metrics/histograms/metadata/user_annotations/enums.xml",
|
||||
"//tools/metrics/histograms/metadata/user_annotations/histograms.xml",
|
||||
"//tools/metrics/histograms/metadata/user_education/histograms.xml",
|
||||
"//tools/metrics/histograms/metadata/v8/enums.xml",
|
||||
"//tools/metrics/histograms/metadata/v8/histograms.xml",
|
||||
|
@ -1,7 +0,0 @@
|
||||
per-file OWNERS=file://tools/metrics/histograms/metadata/METRIC_REVIEWER_OWNERS
|
||||
|
||||
# Prefer sending CLs to the owners listed below.
|
||||
# Use chromium-metrics-reviews@google.com as a backup.
|
||||
mcrouse@chromium.org
|
||||
sophiechang@chromium.org
|
||||
tbansal@chromium.org
|
@ -1,41 +0,0 @@
|
||||
<!--
|
||||
Copyright 2024 The Chromium Authors
|
||||
Use of this source code is governed by a BSD-style license that can be
|
||||
found in the LICENSE file.
|
||||
-->
|
||||
|
||||
<!--
|
||||
|
||||
This file describes the enumerations referenced by entries in histograms.xml for
|
||||
this directory. Some enums may instead be listed in the central enums.xml file
|
||||
at src/tools/metrics/histograms/enums.xml when multiple files use them.
|
||||
|
||||
For best practices on writing enumerations descriptions, see
|
||||
https://chromium.googlesource.com/chromium/src.git/+/HEAD/tools/metrics/histograms/README.md#Enum-Histograms
|
||||
|
||||
Please follow the instructions in the OWNERS file in this directory to find a
|
||||
reviewer. If no OWNERS file exists, please consider signing up at
|
||||
go/reviewing-metrics (Googlers only), as all subdirectories are expected to
|
||||
have an OWNERS file. As a last resort you can send the CL to
|
||||
chromium-metrics-reviews@google.com.
|
||||
-->
|
||||
|
||||
<histogram-configuration>
|
||||
|
||||
<!-- Enum types -->
|
||||
|
||||
<enums>
|
||||
|
||||
<enum name="UserAnnotationsExecutionResult">
|
||||
<int value="0" label="Success"/>
|
||||
<int value="1" label="SQL update failed"/>
|
||||
<int value="2" label="OSCrypt is not initialized at startup"/>
|
||||
<int value="3" label="OSCrypt encrypt/decrypt error"/>
|
||||
<int value="4" label="Response error"/>
|
||||
<int value="5" label="Response malformed"/>
|
||||
<int value="6" label="Response timed out"/>
|
||||
</enum>
|
||||
|
||||
</enums>
|
||||
|
||||
</histogram-configuration>
|
@ -1,67 +0,0 @@
|
||||
<!--
|
||||
Copyright 2024 The Chromium Authors
|
||||
Use of this source code is governed by a BSD-style license that can be
|
||||
found in the LICENSE file.
|
||||
-->
|
||||
|
||||
<histogram-configuration>
|
||||
|
||||
<histograms>
|
||||
|
||||
<histogram name="UserAnnotations.AddFormSubmissionResult"
|
||||
enum="UserAnnotationsExecutionResult" expires_after="2025-05-25">
|
||||
<owner>rajendrant@chromium.org</owner>
|
||||
<owner>sophiechang@chromium.org</owner>
|
||||
<summary>
|
||||
Records the result of a form submission to user annotations service.
|
||||
Recorded for each form submission that is allowed to be stored in the user
|
||||
annotations database.
|
||||
</summary>
|
||||
</histogram>
|
||||
|
||||
<histogram name="UserAnnotations.CountEntries.Result"
|
||||
enum="UserAnnotationsExecutionResult" expires_after="M135">
|
||||
<owner>rajendrant@chromium.org</owner>
|
||||
<owner>sophiechang@chromium.org</owner>
|
||||
<summary>
|
||||
Records the result of counting entries within a certain time frame from user
|
||||
annotations service. Recorded for each call to count entries from the
|
||||
browsing data removal UI.
|
||||
</summary>
|
||||
</histogram>
|
||||
|
||||
<histogram name="UserAnnotations.EntryCount" units="Entries"
|
||||
expires_after="M135">
|
||||
<owner>dongyn@chromium.org</owner>
|
||||
<owner>sophiechang@chromium.org</owner>
|
||||
<summary>
|
||||
Records the number of user annotations entries currently on disk. Recorded
|
||||
once for each call to retrieve entries from disk.
|
||||
</summary>
|
||||
</histogram>
|
||||
|
||||
<histogram name="UserAnnotations.RemoveAllEntries.Result"
|
||||
enum="UserAnnotationsExecutionResult" expires_after="M135">
|
||||
<owner>rajendrant@chromium.org</owner>
|
||||
<owner>sophiechang@chromium.org</owner>
|
||||
<summary>
|
||||
Records the result of removing all entries from user annotations service.
|
||||
Recorded for each remove all entries call from the database via the
|
||||
management UI.
|
||||
</summary>
|
||||
</histogram>
|
||||
|
||||
<histogram name="UserAnnotations.RemoveEntry.Result"
|
||||
enum="UserAnnotationsExecutionResult" expires_after="M135">
|
||||
<owner>rajendrant@chromium.org</owner>
|
||||
<owner>sophiechang@chromium.org</owner>
|
||||
<summary>
|
||||
Records the result of removing a single entry from user annotations service.
|
||||
Recorded for each user annotation entry removal from the database via the
|
||||
management UI.
|
||||
</summary>
|
||||
</histogram>
|
||||
|
||||
</histograms>
|
||||
|
||||
</histogram-configuration>
|
Reference in New Issue
Block a user