1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/browser/bookmarks/enhanced_bookmarks_features.h"
7 #include "base/command_line.h"
8 #include "base/metrics/histogram.h"
9 #include "base/prefs/pref_service.h"
10 #include "base/prefs/scoped_user_pref_update.h"
11 #include "base/sha1.h"
12 #include "base/strings/string_number_conversions.h"
13 #include "chrome/browser/browser_process.h"
14 #include "chrome/browser/flags_storage.h"
15 #include "chrome/browser/profiles/profile.h"
16 #include "chrome/browser/signin/signin_manager_factory.h"
17 #include "chrome/common/chrome_switches.h"
18 #include "chrome/common/pref_names.h"
19 #include "components/signin/core/browser/signin_manager.h"
20 #include "components/sync_driver/pref_names.h"
21 #include "components/variations/variations_associated_data.h"
22 #include "extensions/common/features/feature.h"
23 #include "extensions/common/features/feature_provider.h"
24 #include "ui/base/device_form_factor.h"
28 const char kFieldTrialName[] = "EnhancedBookmarks";
30 // Get extension id from Finch EnhancedBookmarks group parameters.
31 std::string GetEnhancedBookmarksExtensionIdFromFinch() {
32 return variations::GetVariationParamValue(kFieldTrialName, "id");
35 // Returns true if enhanced bookmarks experiment is enabled from Finch.
36 bool IsEnhancedBookmarksExperimentEnabledFromFinch() {
37 const std::string ext_id = GetEnhancedBookmarksExtensionIdFromFinch();
38 #if defined(OS_ANDROID)
39 return !ext_id.empty();
41 const extensions::FeatureProvider* feature_provider =
42 extensions::FeatureProvider::GetPermissionFeatures();
43 extensions::Feature* feature = feature_provider->GetFeature("metricsPrivate");
44 return feature && feature->IsIdInWhitelist(ext_id);
50 bool GetBookmarksExperimentExtensionID(const PrefService* user_prefs,
51 std::string* extension_id) {
52 BookmarksExperimentState bookmarks_experiment_state =
53 static_cast<BookmarksExperimentState>(user_prefs->GetInteger(
54 sync_driver::prefs::kEnhancedBookmarksExperimentEnabled));
55 if (bookmarks_experiment_state == BOOKMARKS_EXPERIMENT_ENABLED_FROM_FINCH) {
56 *extension_id = GetEnhancedBookmarksExtensionIdFromFinch();
57 return !extension_id->empty();
59 if (bookmarks_experiment_state == BOOKMARKS_EXPERIMENT_ENABLED) {
60 *extension_id = user_prefs->GetString(
61 sync_driver::prefs::kEnhancedBookmarksExtensionId);
62 return !extension_id->empty();
68 void UpdateBookmarksExperimentState(
69 PrefService* user_prefs,
70 PrefService* local_state,
72 BookmarksExperimentState experiment_enabled_from_sync) {
73 PrefService* flags_storage = local_state;
74 #if defined(OS_CHROMEOS)
75 // Chrome OS is using user prefs for flags storage.
76 flags_storage = user_prefs;
79 BookmarksExperimentState bookmarks_experiment_state_before =
80 static_cast<BookmarksExperimentState>(user_prefs->GetInteger(
81 sync_driver::prefs::kEnhancedBookmarksExperimentEnabled));
82 // If user signed out, clear possible previous state.
83 if (!user_signed_in) {
84 bookmarks_experiment_state_before = BOOKMARKS_EXPERIMENT_NONE;
85 ForceFinchBookmarkExperimentIfNeeded(flags_storage,
86 BOOKMARKS_EXPERIMENT_NONE);
89 // kEnhancedBookmarksExperiment flag could have values "", "1" and "0".
90 // "0" - user opted out.
91 bool opt_out = CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
92 switches::kEnhancedBookmarksExperiment) == "0";
93 #if defined(OS_ANDROID)
94 // Tablets automagically do opt out.
96 opt_out || ui::GetDeviceFormFactor() == ui::DEVICE_FORM_FACTOR_TABLET;
97 #endif // defined(OS_ANDROID)
99 BookmarksExperimentState bookmarks_experiment_new_state =
100 BOOKMARKS_EXPERIMENT_NONE;
102 if (IsEnhancedBookmarksExperimentEnabledFromFinch() && !user_signed_in) {
104 // Experiment enabled but user opted out.
105 bookmarks_experiment_new_state = BOOKMARKS_EXPERIMENT_OPT_OUT_FROM_FINCH;
107 // Experiment enabled.
108 bookmarks_experiment_new_state = BOOKMARKS_EXPERIMENT_ENABLED_FROM_FINCH;
110 } else if (experiment_enabled_from_sync == BOOKMARKS_EXPERIMENT_ENABLED) {
111 // Experiment enabled from Chrome sync.
113 // Experiment enabled but user opted out.
114 bookmarks_experiment_new_state =
115 BOOKMARKS_EXPERIMENT_ENABLED_USER_OPT_OUT;
117 // Experiment enabled.
118 bookmarks_experiment_new_state = BOOKMARKS_EXPERIMENT_ENABLED;
120 } else if (experiment_enabled_from_sync == BOOKMARKS_EXPERIMENT_NONE) {
121 // Experiment is not enabled from Chrome sync.
122 bookmarks_experiment_new_state = BOOKMARKS_EXPERIMENT_NONE;
123 } else if (bookmarks_experiment_state_before ==
124 BOOKMARKS_EXPERIMENT_ENABLED) {
126 // Experiment enabled but user opted out.
127 bookmarks_experiment_new_state =
128 BOOKMARKS_EXPERIMENT_ENABLED_USER_OPT_OUT;
130 bookmarks_experiment_new_state = BOOKMARKS_EXPERIMENT_ENABLED;
132 } else if (bookmarks_experiment_state_before ==
133 BOOKMARKS_EXPERIMENT_ENABLED_USER_OPT_OUT) {
135 bookmarks_experiment_new_state =
136 BOOKMARKS_EXPERIMENT_ENABLED_USER_OPT_OUT;
138 // User opted in again.
139 bookmarks_experiment_new_state = BOOKMARKS_EXPERIMENT_ENABLED;
143 #if defined(OS_ANDROID)
144 bool opt_in = !opt_out
145 && CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
146 switches::kEnhancedBookmarksExperiment) == "1";
147 if (opt_in && bookmarks_experiment_new_state == BOOKMARKS_EXPERIMENT_NONE)
148 bookmarks_experiment_new_state = BOOKMARKS_EXPERIMENT_ENABLED;
151 UMA_HISTOGRAM_ENUMERATION("EnhancedBookmarks.SyncExperimentState",
152 bookmarks_experiment_new_state,
153 BOOKMARKS_EXPERIMENT_ENUM_SIZE);
154 user_prefs->SetInteger(
155 sync_driver::prefs::kEnhancedBookmarksExperimentEnabled,
156 bookmarks_experiment_new_state);
157 ForceFinchBookmarkExperimentIfNeeded(flags_storage,
158 bookmarks_experiment_new_state);
161 void InitBookmarksExperimentState(Profile* profile) {
162 SigninManagerBase* signin = SigninManagerFactory::GetForProfile(profile);
163 bool is_signed_in = signin && signin->IsAuthenticated();
164 UpdateBookmarksExperimentState(
166 g_browser_process->local_state(),
168 BOOKMARKS_EXPERIMENT_ENABLED_FROM_SYNC_UNKNOWN);
171 void ForceFinchBookmarkExperimentIfNeeded(
172 PrefService* flags_storage,
173 BookmarksExperimentState bookmarks_experiment_state) {
176 ListPrefUpdate update(flags_storage, prefs::kEnabledLabsExperiments);
177 base::ListValue* experiments_list = update.Get();
178 if (!experiments_list)
181 if (bookmarks_experiment_state == BOOKMARKS_EXPERIMENT_NONE) {
182 experiments_list->Remove(
183 base::StringValue(switches::kManualEnhancedBookmarks), &index);
184 experiments_list->Remove(
185 base::StringValue(switches::kManualEnhancedBookmarksOptout), &index);
186 } else if (bookmarks_experiment_state == BOOKMARKS_EXPERIMENT_ENABLED) {
187 experiments_list->Remove(
188 base::StringValue(switches::kManualEnhancedBookmarksOptout), &index);
189 experiments_list->AppendIfNotPresent(
190 new base::StringValue(switches::kManualEnhancedBookmarks));
191 } else if (bookmarks_experiment_state ==
192 BOOKMARKS_EXPERIMENT_ENABLED_USER_OPT_OUT) {
193 experiments_list->Remove(
194 base::StringValue(switches::kManualEnhancedBookmarks), &index);
195 experiments_list->AppendIfNotPresent(
196 new base::StringValue(switches::kManualEnhancedBookmarksOptout));
200 bool IsEnhancedBookmarksExperimentEnabled(
201 about_flags::FlagsStorage* flags_storage) {
202 #if defined(OS_CHROMEOS)
203 // We are not setting command line flags on Chrome OS to avoid browser restart
204 // but still have flags in flags_storage. So check flags_storage instead.
205 const std::set<std::string> flags = flags_storage->GetFlags();
206 if (flags.find(switches::kManualEnhancedBookmarks) != flags.end())
208 if (flags.find(switches::kManualEnhancedBookmarksOptout) != flags.end())
211 CommandLine* command_line = CommandLine::ForCurrentProcess();
212 if (command_line->HasSwitch(switches::kManualEnhancedBookmarks) ||
213 command_line->HasSwitch(switches::kManualEnhancedBookmarksOptout)) {
218 return IsEnhancedBookmarksExperimentEnabledFromFinch();
221 #if defined(OS_ANDROID)
222 bool IsEnhancedBookmarkImageFetchingEnabled(const PrefService* user_prefs) {
223 if (IsEnhancedBookmarksEnabled(user_prefs))
226 // Salient images are collected from visited bookmarked pages even if the
227 // enhanced bookmark feature is turned off. This is to have some images
228 // available so that in the future, when the feature is turned on, the user
229 // experience is not a big list of flat colors. However as a precautionary
230 // measure it is possible to disable this collection of images from finch.
231 std::string disable_fetching = variations::GetVariationParamValue(
232 kFieldTrialName, "DisableImagesFetching");
233 return disable_fetching.empty();
236 bool IsEnhancedBookmarksEnabled(const PrefService* user_prefs) {
237 BookmarksExperimentState bookmarks_experiment_state =
238 static_cast<BookmarksExperimentState>(user_prefs->GetInteger(
239 sync_driver::prefs::kEnhancedBookmarksExperimentEnabled));
240 return bookmarks_experiment_state == BOOKMARKS_EXPERIMENT_ENABLED ||
241 bookmarks_experiment_state == BOOKMARKS_EXPERIMENT_ENABLED_FROM_FINCH;
245 bool IsEnableDomDistillerSet() {
246 if (CommandLine::ForCurrentProcess()->
247 HasSwitch(switches::kEnableDomDistiller)) {
250 if (variations::GetVariationParamValue(
251 kFieldTrialName, "enable-dom-distiller") == "1")
257 bool IsEnableSyncArticlesSet() {
258 if (CommandLine::ForCurrentProcess()->
259 HasSwitch(switches::kEnableSyncArticles)) {
262 if (variations::GetVariationParamValue(
263 kFieldTrialName, "enable-sync-articles") == "1")