blob: 06327601e948f6ae1abadffa89f86d42f8d6e6b2 [file]
// 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/page_content_annotations/core/page_content_annotations_features.h"
#include "base/containers/contains.h"
#include "base/metrics/field_trial.h"
#include "base/metrics/field_trial_params.h"
#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
#include "build/build_config.h"
#include "components/page_content_annotations/core/page_content_annotations_switches.h"
#include "ui/base/l10n/l10n_util.h"
namespace page_content_annotations::features {
namespace {
constexpr auto enabled_by_default_desktop_only =
#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)
base::FEATURE_DISABLED_BY_DEFAULT;
#else
base::FEATURE_ENABLED_BY_DEFAULT;
#endif
constexpr auto enabled_by_default_non_ios =
#if BUILDFLAG(IS_IOS)
base::FEATURE_DISABLED_BY_DEFAULT;
#else
base::FEATURE_ENABLED_BY_DEFAULT;
#endif
constexpr char enabled_all_mobile_locales_en_us_desktop_only[] =
#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)
"*";
#else
"en-US";
#endif
constexpr char enabled_all_mobile_countries_us_desktop_only[] =
#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)
"*";
#else
"us";
#endif
const base::FeatureParam<base::TimeDelta> kAnnotatedPageContentCaptureDelay{
&kAnnotatedPageContentExtraction, "capture_delay", base::Seconds(5)};
const base::FeatureParam<bool> kAnnotatedPageContentStudyIncludeInnerText{
&kAnnotatedPageContentExtraction, "include_inner_text", false};
const base::FeatureParam<bool> kAnnotatedPageContentOnCriticalPath{
&kAnnotatedPageContentExtraction, "on_critical_path", false};
const base::FeatureParam<std::string> kAnnotatedPageContentMode{
&kAnnotatedPageContentExtraction, "mode", "default"};
const base::FeatureParam<std::string> kPageContentExtractionTriggeringMode{
&kAnnotatedPageContentExtraction, "triggering_mode", "on_load"};
bool IsSupportedLocale(const std::string& locale,
const std::string& supported_locales) {
if (supported_locales == "*") {
return true;
}
std::vector<std::string> supported = base::SplitString(
supported_locales, ",", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
// An empty admits any locale.
if (supported.empty()) {
return true;
}
// Otherwise, the locale or the primary language subtag must match an element
// of the allowlist.
return base::Contains(supported, locale) ||
base::Contains(supported, l10n_util::GetLanguage(locale));
}
bool IsSupportedCountry(const std::string& country_code,
const std::string& supported_countries) {
if (supported_countries == "*") {
return true;
}
std::vector<std::string> supported =
base::SplitString(supported_countries, ",", base::TRIM_WHITESPACE,
base::SPLIT_WANT_NONEMPTY);
// An empty allowlist admits any country.
if (supported.empty()) {
return true;
}
return std::ranges::any_of(
supported, [&country_code](const auto& supported_country_code) {
return base::EqualsCaseInsensitiveASCII(supported_country_code,
country_code);
});
}
} // namespace
// Enables page content to be annotated.
BASE_FEATURE(kPageContentAnnotations, base::FEATURE_ENABLED_BY_DEFAULT);
BASE_FEATURE(kPageContentAnnotationsValidation,
base::FEATURE_DISABLED_BY_DEFAULT);
// Enables fetching page metadata from the remote Optimization Guide service.
BASE_FEATURE(kRemotePageMetadata, base::FEATURE_ENABLED_BY_DEFAULT);
BASE_FEATURE(kOptimizationGuideUseContinueOnShutdownForPageContentAnnotations,
enabled_by_default_non_ios);
BASE_FEATURE(kExtractRelatedSearchesFromPrefetchedZPSResponse,
enabled_by_default_desktop_only);
BASE_FEATURE(kAnnotatedPageContentExtraction,
base::FEATURE_DISABLED_BY_DEFAULT);
BASE_FEATURE(kOnDeviceCategoryClassifier, base::FEATURE_DISABLED_BY_DEFAULT);
BASE_FEATURE(kPageContentCache, base::FEATURE_DISABLED_BY_DEFAULT);
const base::FeatureParam<int> kPageContentCacheMaxCacheAgeInDays{
&kPageContentCache, "max_cache_age_in_days", 7};
const base::FeatureParam<int> kPageContentCacheMaxTabs{
&kPageContentCache, "max_cache_tabs_count", 50};
const base::FeatureParam<bool> kPageContentCacheEnableScreenshot{
&kPageContentCache, "enable_screenshot", false};
base::TimeDelta PCAServiceWaitForTitleDelayDuration() {
return base::Milliseconds(GetFieldTrialParamByFeatureAsInt(
kPageContentAnnotations,
"pca_service_wait_for_title_delay_in_milliseconds", 5000));
}
bool ShouldEnablePageContentAnnotations() {
// Allow for the validation experiment or remote page metadata to enable the
// PCAService without need to enable both features.
return base::FeatureList::IsEnabled(kPageContentAnnotations) ||
base::FeatureList::IsEnabled(page_content_annotations::features::
kPageContentAnnotationsValidation) ||
base::FeatureList::IsEnabled(
page_content_annotations::features::kRemotePageMetadata) ||
base::FeatureList::IsEnabled(kOnDeviceCategoryClassifier);
}
bool ShouldWriteContentAnnotationsToHistoryService() {
return base::GetFieldTrialParamByFeatureAsBool(
kPageContentAnnotations, "write_to_history_service", true);
}
size_t MaxContentAnnotationRequestsCached() {
return GetFieldTrialParamByFeatureAsInt(
kPageContentAnnotations, "max_content_annotation_requests_cached", 50);
}
const base::FeatureParam<bool> kContentAnnotationsExtractRelatedSearchesParam{
&kPageContentAnnotations, "extract_related_searches", true};
bool ShouldExtractRelatedSearches() {
return kContentAnnotationsExtractRelatedSearchesParam.Get();
}
bool ShouldExecutePageVisibilityModelOnPageContent(const std::string& locale) {
#if defined(ARCH_CPU_ARMEL)
return false;
#else
return IsSupportedLocale(
locale,
/*default_value=*/"ar,en,es,fa,fr,hi,id,pl,pt,tr,vi");
#endif
}
bool RemotePageMetadataEnabled(const std::string& locale,
const std::string& country_code) {
return base::FeatureList::IsEnabled(kRemotePageMetadata) &&
IsSupportedLocaleForFeature(
locale, kRemotePageMetadata,
enabled_all_mobile_locales_en_us_desktop_only) &&
IsSupportedCountryForFeature(
country_code, kRemotePageMetadata,
enabled_all_mobile_countries_us_desktop_only);
}
int GetMinimumPageCategoryScoreToPersist() {
return GetFieldTrialParamByFeatureAsInt(kRemotePageMetadata,
"min_page_category_score", 85);
}
int NumBitsForRAPPORMetrics() {
// The number of bits must be at least 1.
return std::max(
1, GetFieldTrialParamByFeatureAsInt(kPageContentAnnotations,
"num_bits_for_rappor_metrics", 4));
}
double NoiseProbabilityForRAPPORMetrics() {
// The noise probability must be between 0 and 1.
return std::max(0.0, std::min(1.0, GetFieldTrialParamByFeatureAsDouble(
kPageContentAnnotations,
"noise_prob_for_rappor_metrics", .5)));
}
size_t AnnotateVisitBatchSize() {
// When new visits are synced, the service gets visit notifications in a loop.
// The service drops new visits during processing a batch. Often only the
// `kDefaultBatchSize` entries are annotated when new visits are synced. Set
// the limit to 5 since up to 5 URLs are shown on tab resume module.
constexpr int kDefaultBatchSize = 5;
return std::max(1, GetFieldTrialParamByFeatureAsInt(
kPageContentAnnotations, "annotate_visit_batch_size",
kDefaultBatchSize));
}
base::TimeDelta PageContentAnnotationValidationStartupDelay() {
return switches::PageContentAnnotationsValidationStartupDelay().value_or(
base::Seconds(std::max(
1, GetFieldTrialParamByFeatureAsInt(kPageContentAnnotationsValidation,
"startup_delay", 30))));
}
size_t PageContentAnnotationsValidationBatchSize() {
return switches::PageContentAnnotationsValidationBatchSize().value_or(
std::max(1, GetFieldTrialParamByFeatureAsInt(
kPageContentAnnotationsValidation, "batch_size", 25)));
}
base::TimeDelta PageContentAnnotationBatchSizeTimeoutDuration() {
return base::Seconds(GetFieldTrialParamByFeatureAsInt(
kPageContentAnnotations, "batch_annotations_timeout_seconds", 30));
}
size_t MaxVisitAnnotationCacheSize() {
int batch_size = GetFieldTrialParamByFeatureAsInt(
kPageContentAnnotations, "max_visit_annotation_cache_size", 50);
return std::max(1, batch_size);
}
bool ShouldPersistSalientImageMetadata(const std::string& locale,
const std::string& country_code) {
return IsSupportedLocale(locale,
enabled_all_mobile_locales_en_us_desktop_only) &&
IsSupportedCountry(country_code,
enabled_all_mobile_countries_us_desktop_only);
}
size_t MaxRelatedSearchesCacheSize() {
return GetFieldTrialParamByFeatureAsInt(
kExtractRelatedSearchesFromPrefetchedZPSResponse,
"max_related_searches_cache_size", 10);
}
bool IsAnnotatedPageContentOnCriticalPath() {
return kAnnotatedPageContentOnCriticalPath.Get();
}
base::TimeDelta GetAnnotatedPageContentCaptureDelay() {
return kAnnotatedPageContentCaptureDelay.Get();
}
bool ShouldAnnotatedPageContentStudyIncludeInnerText() {
return kAnnotatedPageContentStudyIncludeInnerText.Get();
}
std::string AnnotatedPageContentMode() {
return kAnnotatedPageContentMode.Get();
}
PageContentExtractionTriggeringMode GetPageContentExtractionTriggeringMode() {
std::string mode_str = kPageContentExtractionTriggeringMode.Get();
if (mode_str == "on_hidden") {
return PageContentExtractionTriggeringMode::kOnHidden;
}
if (mode_str == "on_load_and_hidden") {
return PageContentExtractionTriggeringMode::kOnLoadAndHidden;
}
return PageContentExtractionTriggeringMode::kOnLoad;
}
bool IsSupportedLocaleForFeature(
const std::string& locale,
const base::Feature& feature,
const std::string& default_value = "de,en,es,fr,it,nl,pt,tr") {
if (!base::FeatureList::IsEnabled(feature)) {
return false;
}
std::string value =
base::GetFieldTrialParamValueByFeature(feature, "supported_locales");
if (value.empty()) {
// The default list of supported locales for optimization guide features.
value = default_value;
}
return IsSupportedLocale(locale, value);
}
bool IsSupportedCountryForFeature(const std::string& country_code,
const base::Feature& feature,
const std::string& default_value) {
if (!base::FeatureList::IsEnabled(feature)) {
return false;
}
std::string value =
base::GetFieldTrialParamValueByFeature(feature, "supported_countries");
if (value.empty()) {
// The default list of supported countries for optimization guide features.
value = default_value;
}
return IsSupportedCountry(country_code, value);
}
} // namespace page_content_annotations::features