1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338
|
// Copyright 2023 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_SEARCH_ENGINES_SEARCH_ENGINE_CHOICE_SEARCH_ENGINE_CHOICE_UTILS_H_
#define COMPONENTS_SEARCH_ENGINES_SEARCH_ENGINE_CHOICE_SEARCH_ENGINE_CHOICE_UTILS_H_
#include <optional>
#include <string>
#include <vector>
#include "base/memory/raw_ptr.h"
#include "base/types/expected.h"
#include "base/version.h"
#include "build/build_config.h"
#include "components/country_codes/country_codes.h"
#include "components/search_engines/choice_made_location.h"
#include "components/search_engines/search_engine_type.h"
#include "components/search_engines/template_url.h"
class PrefService;
class SearchTermsData;
struct TemplateURLData;
namespace base {
class Time;
} // namespace base
namespace search_engines {
inline constexpr char
kSearchEngineChoiceScreenProfileInitConditionsHistogram[] =
"Search.ChoiceScreenProfileInitConditions";
inline constexpr char kSearchEngineChoiceScreenNavigationConditionsHistogram[] =
"Search.ChoiceScreenNavigationConditions";
inline constexpr char kSearchEngineChoiceScreenEventsHistogram[] =
"Search.ChoiceScreenEvents";
inline constexpr char
kSearchEngineChoiceScreenDefaultSearchEngineTypeHistogram[] =
"Search.ChoiceScreenDefaultSearchEngineType";
inline constexpr char
kSearchEngineChoiceScreenDefaultSearchEngineType2Histogram[] =
"Search.ChoiceScreenDefaultSearchEngineType2";
inline constexpr char kSearchEngineChoiceScreenSelectedEngineIndexHistogram[] =
"Search.ChoiceScreenSelectedEngineIndex";
inline constexpr char
kSearchEngineChoiceScreenShowedEngineAtHistogramPattern[] =
"Search.ChoiceScreenShowedEngineAt.Index%d";
inline constexpr char
kSearchEngineChoiceScreenShowedEngineAtCountryMismatchHistogram[] =
"Search.ChoiceScreenShowedEngineAt.CountryMismatch";
inline constexpr char kSearchEngineChoiceWipeReasonHistogram[] =
"Search.ChoiceWipeReason";
inline constexpr char kSearchEngineChoiceRepromptHistogram[] =
"Search.ChoiceReprompt";
inline constexpr char kSearchEngineChoiceRepromptWildcardHistogram[] =
"Search.ChoiceReprompt.Wildcard";
inline constexpr char kSearchEngineChoiceRepromptSpecificCountryHistogram[] =
"Search.ChoiceReprompt.SpecificCountry";
inline constexpr char kSearchEngineChoiceCompletedOnMonthHistogram[] =
"Search.ChoiceCompletedOnMonth.OnProfileLoad2";
// These values are persisted to logs. Entries should not be renumbered and
// numeric values should never be reused.
// LINT.IfChange(SearchEngineChoiceScreenConditions)
enum class SearchEngineChoiceScreenConditions {
// The user has a custom search engine set.
kHasCustomSearchEngine = 0,
// The user has a search provider list override.
kSearchProviderOverride = 1,
// The user is not in the regional scope.
kNotInRegionalScope = 2,
// A policy sets the default search engine or disables search altogether.
kControlledByPolicy = 3,
// The profile is out of scope.
kProfileOutOfScope = 4,
// An extension controls the default search engine.
kExtensionControlled = 5,
// The user is eligible to see the screen at the next opportunity.
kEligible = 6,
// The choice has already been completed.
kAlreadyCompleted = 7,
// The browser type is unsupported.
kUnsupportedBrowserType = 8,
// The feature can't run, it is disabled by local or remote configuration.
kFeatureSuppressed = 9,
// Some other dialog is showing and interfering with the choice one.
kSuppressedByOtherDialog = 10,
// The browser window can't fit the dialog's smallest variant.
kBrowserWindowTooSmall = 11,
// The user has a distribution custom search engine set as default.
kHasDistributionCustomSearchEngine = 12,
// The user has an unknown (which we assume is because it has been removed)
// prepopulated search engine set as default.
kHasRemovedPrepopulatedSearchEngine = 13,
// The user does not have Google as the default search engine.
kHasNonGoogleSearchEngine = 14,
// The user is eligible, the app could have presented a dialog but the
// application was started via an external intent and the dialog skipped.
kAppStartedByExternalIntent = 15,
// The browser attempting to show the choice screen in a dialog is already
// showing a choice screen.
kAlreadyBeingShown = 16,
// The user made the choice in the guest session and opted to save it across
// guest sessions.
kUsingPersistedGuestSessionChoice = 17,
kMaxValue = kUsingPersistedGuestSessionChoice,
};
// LINT.ThenChange(/tools/metrics/histograms/metadata/search/enums.xml:SearchEngineChoiceScreenConditions)
// These values are persisted to logs. Entries should not be renumbered and
// numeric values should never be reused.
// LINT.IfChange(SearchEngineChoiceScreenEvents)
enum class SearchEngineChoiceScreenEvents {
kUnknown = 0,
// The non-FRE version of the choice screen was displayed.
kChoiceScreenWasDisplayed = 1,
// The FRE-specific flavor of the screen was displayed.
kFreChoiceScreenWasDisplayed = 2,
// The user clicked/tapped `Set as default` on the non-FRE screen.
kDefaultWasSet = 3,
// The user clicked/tapped `Set as default` on the
// FRE-specific screen.
kFreDefaultWasSet = 4,
// The "Learn more" screen was displayed on the non-FRE screen.
kLearnMoreWasDisplayed = 5,
// The "Learn more" screen was displayed on the FRE-specific screen.
kFreLearnMoreWasDisplayed = 6,
// The profile creation specific flavor of the screen was displayed.
kProfileCreationChoiceScreenWasDisplayed = 7,
// The user clicked `Set as default` on the profile creation specific screen.
kProfileCreationDefaultWasSet = 8,
// The "Learn more" screen was displayed on the profile creation specific
// screen.
kProfileCreationLearnMoreDisplayed = 9,
// The "More" button was clicked on the modal dialog.
kMoreButtonClicked = 10,
// The "More" button was clicked on the FRE-specific screen.
kFreMoreButtonClicked = 11,
// The "More" button was clicked on the profile creation specific screen.
kProfileCreationMoreButtonClicked = 12,
kMaxValue = kProfileCreationMoreButtonClicked,
};
// LINT.ThenChange(/tools/metrics/histograms/metadata/search/enums.xml:SearchEngineChoiceScreenEvents)
// The cause for wiping the search engine choice preferences. Only used for
// metrics.
// These values are persisted to logs. Entries should not be renumbered and
// numeric values should never be reused.
enum class SearchEngineChoiceWipeReason {
kProfileWipe = 0,
kMissingMetadataVersion = 1,
kInvalidMetadataVersion = 2,
kFinchBasedReprompt = 3,
kCommandLineFlag = 4,
kDeviceRestored = 5,
kInvalidMetadata = 6,
kMissingDefaultSearchEngine = 7,
kMaxValue = kMissingDefaultSearchEngine,
};
// Exposed for testing.
// These values are persisted to logs. Entries should not be renumbered and
// numeric values should never be reused.
enum class RepromptResult {
// Reprompt.
kReprompt = 0,
// Cases below do not reprompt.
//
// Wrong JSON syntax.
kInvalidDictionary = 1,
// There was no applicable key (specific country or wildcard).
kNoDictionaryKey = 2,
// The reprompt version could not be parsed.
kInvalidVersion = 3,
// Chrome older than the requested version, reprompting would not make the
// version recent enough.
kChromeTooOld = 4,
// The choice was made recently enough.
kRecentChoice = 5,
// Do not reprompt the users.
kNoReprompt = 6,
kMaxValue = kNoReprompt,
};
struct ChoiceScreenDisplayState {
public:
ChoiceScreenDisplayState(
std::vector<SearchEngineType> search_engines,
country_codes::CountryId country_id,
std::optional<int> selected_engine_index = std::nullopt);
ChoiceScreenDisplayState(const ChoiceScreenDisplayState& other);
~ChoiceScreenDisplayState();
base::Value::Dict ToDict() const;
static std::optional<ChoiceScreenDisplayState> FromDict(
const base::Value::Dict& dict);
// `SearchEngineType`s of the search engines displayed on the choice screen,
// listed in an order matching their display order.
// Note that the screen shows items from a list specific for each EEA
// country, and these items are randomized before they are presented.
const std::vector<SearchEngineType> search_engines;
// Index of the selected search engine. Obviously can't be populated until
// the choice has been made, so instances describing purely the state at the
// time of the display won't have a value, while the ones describing it at
// the moment of the choice will have it populated.
std::optional<int> selected_engine_index;
// The country used when generating the list. It should be the country
// used to determine the set of search engines to show for the current
// profile.
const country_codes::CountryId country_id;
};
// Contains basic information about the search engine choice screen, notably
// the list of actual search engines to show, and other metadata associated
// with how it was determined.
class ChoiceScreenData {
public:
ChoiceScreenData(TemplateURL::OwnedTemplateURLVector owned_template_urls,
country_codes::CountryId country_id,
const SearchTermsData& search_terms_data);
ChoiceScreenData(const ChoiceScreenData&) = delete;
ChoiceScreenData& operator=(const ChoiceScreenData&) = delete;
~ChoiceScreenData();
const TemplateURL::OwnedTemplateURLVector& search_engines() const {
return search_engines_;
}
const ChoiceScreenDisplayState& display_state() const {
return display_state_;
}
private:
const TemplateURL::OwnedTemplateURLVector search_engines_;
const ChoiceScreenDisplayState display_state_;
};
// Records the specified choice screen condition at profile initialization.
void RecordChoiceScreenProfileInitCondition(
SearchEngineChoiceScreenConditions event);
// Records the specified choice screen condition for relevant navigations.
void RecordChoiceScreenNavigationCondition(
SearchEngineChoiceScreenConditions condition);
// Records the specified choice screen event.
void RecordChoiceScreenEvent(SearchEngineChoiceScreenEvents event);
// Records the type of the default search engine that was chosen by the user
// in the search engine choice screen or in the settings page.
void RecordChoiceScreenDefaultSearchProviderType(
SearchEngineType engine_type,
ChoiceMadeLocation choice_location);
// Records the index of the search engine that was chosen by the user as it was
// displayed on the choice screen.
void RecordChoiceScreenSelectedIndex(int selected_engine_index);
// Records the positions of search engines in a choice screen. Intended to be
// recorded when a choice happens, so that we emit it at most once per choice
// "scope". For more info, please see
// http://go/chrome-choice-screen-positions-histogram-design (Google-internal).
// Don't call this directly. Instead, go through
// `SearchEngineChoiceService::MaybeRecordChoiceScreenDisplayState()`.
void RecordChoiceScreenPositions(
const std::vector<SearchEngineType>& displayed_search_engines);
// Records whether `RecordChoiceScreenPositions()` had to be skipped due to
// a mismatch between the Variations/UMA country and the profile/choice
// country. If `has_mismatch` is `true`, we record that it was "skipped", or
// that it was "not skipped" otherwise.
void RecordChoiceScreenPositionsCountryMismatch(bool has_mismatch);
// For debugging purposes, record the ID of the current default search engine
// that does not exist in the prepopulated search providers data.
void RecordUnexpectedSearchProvider(const TemplateURLData& data);
// Clears the search engine choice prefs, such as the timestamp and the Chrome
// version, to ensure the choice screen is shown again.
void WipeSearchEngineChoicePrefs(PrefService& profile_prefs,
SearchEngineChoiceWipeReason reason);
struct ChoiceCompletionMetadata {
enum class ParseError {
kAbsent,
kMissingVersion,
kInvalidVersion,
kMissingTimestamp,
kNullTimestamp,
};
base::Time timestamp;
base::Version version;
};
base::expected<ChoiceCompletionMetadata, ChoiceCompletionMetadata::ParseError>
GetChoiceCompletionMetadata(const PrefService& prefs);
void SetChoiceCompletionMetadata(PrefService& prefs,
ChoiceCompletionMetadata metadata);
// Returns the timestamp of search engine choice screen. No value if no choice
// has been made.
std::optional<base::Time> GetChoiceScreenCompletionTimestamp(
PrefService& prefs);
void ClearSearchEngineChoiceInvalidation(PrefService& prefs);
bool IsSearchEngineChoiceInvalid(PrefService& prefs);
#if !BUILDFLAG(IS_ANDROID)
// Returns the engine marketing snippet string resource id or -1 if the snippet
// was not found.
// The function definition is generated in `generated_marketing_snippets.cc`.
// `engine_keyword` is the search engine keyword.
int GetMarketingSnippetResourceId(const std::u16string& engine_keyword);
// Returns the marketing snippet string or the fallback string if the search
// engine didn't provide its own.
std::u16string GetMarketingSnippetString(
const TemplateURLData& template_url_data);
#endif // !BUILDFLAG(IS_ANDROID)
} // namespace search_engines
#endif // COMPONENTS_SEARCH_ENGINES_SEARCH_ENGINE_CHOICE_SEARCH_ENGINE_CHOICE_UTILS_H_
|