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.
4
5 #include "chrome/browser/bookmarks/enhanced_bookmarks_features.h"
6
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/common/chrome_switches.h"
14 #include "chrome/common/pref_names.h"
15 #include "components/sync_driver/pref_names.h"
16 #include "components/variations/variations_associated_data.h"
17 #include "extensions/common/features/feature.h"
18 #include "extensions/common/features/feature_provider.h"
19
20 namespace {
21
22 const char kFieldTrialName[] = "EnhancedBookmarks";
23
24 // Get extension id from Finch EnhancedBookmarks group parameters.
GetEnhancedBookmarksExtensionIdFromFinch()25 std::string GetEnhancedBookmarksExtensionIdFromFinch() {
26 return chrome_variations::GetVariationParamValue(kFieldTrialName, "id");
27 }
28
29 // Returns true if enhanced bookmarks experiment is enabled from Finch.
IsEnhancedBookmarksExperimentEnabledFromFinch()30 bool IsEnhancedBookmarksExperimentEnabledFromFinch() {
31 std::string ext_id = GetEnhancedBookmarksExtensionIdFromFinch();
32 const extensions::FeatureProvider* feature_provider =
33 extensions::FeatureProvider::GetPermissionFeatures();
34 extensions::Feature* feature = feature_provider->GetFeature("metricsPrivate");
35 return feature && feature->IsIdInWhitelist(ext_id);
36 }
37
38 }; // namespace
39
GetBookmarksExperimentExtensionID(const PrefService * user_prefs,std::string * extension_id)40 bool GetBookmarksExperimentExtensionID(const PrefService* user_prefs,
41 std::string* extension_id) {
42 BookmarksExperimentState bookmarks_experiment_state =
43 static_cast<BookmarksExperimentState>(user_prefs->GetInteger(
44 sync_driver::prefs::kEnhancedBookmarksExperimentEnabled));
45 if (bookmarks_experiment_state == BOOKMARKS_EXPERIMENT_ENABLED_FROM_FINCH) {
46 *extension_id = GetEnhancedBookmarksExtensionIdFromFinch();
47 return !extension_id->empty();
48 }
49 if (bookmarks_experiment_state == BOOKMARKS_EXPERIMENT_ENABLED) {
50 *extension_id = user_prefs->GetString(
51 sync_driver::prefs::kEnhancedBookmarksExtensionId);
52 return !extension_id->empty();
53 }
54
55 return false;
56 }
57
UpdateBookmarksExperimentState(PrefService * user_prefs,PrefService * local_state,bool user_signed_in,BookmarksExperimentState experiment_enabled_from_sync)58 void UpdateBookmarksExperimentState(
59 PrefService* user_prefs,
60 PrefService* local_state,
61 bool user_signed_in,
62 BookmarksExperimentState experiment_enabled_from_sync) {
63 PrefService* flags_storage = local_state;
64 #if defined(OS_CHROMEOS)
65 // Chrome OS is using user prefs for flags storage.
66 flags_storage = user_prefs;
67 #endif
68
69 BookmarksExperimentState bookmarks_experiment_state_before =
70 static_cast<BookmarksExperimentState>(user_prefs->GetInteger(
71 sync_driver::prefs::kEnhancedBookmarksExperimentEnabled));
72 // If user signed out, clear possible previous state.
73 if (!user_signed_in) {
74 bookmarks_experiment_state_before = BOOKMARKS_EXPERIMENT_NONE;
75 ForceFinchBookmarkExperimentIfNeeded(flags_storage,
76 BOOKMARKS_EXPERIMENT_NONE);
77 }
78
79 // kEnhancedBookmarksExperiment flag could have values "", "1" and "0".
80 // "0" - user opted out.
81 bool opt_out = CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
82 switches::kEnhancedBookmarksExperiment) == "0";
83
84 BookmarksExperimentState bookmarks_experiment_new_state =
85 BOOKMARKS_EXPERIMENT_NONE;
86
87 if (IsEnhancedBookmarksExperimentEnabledFromFinch() && !user_signed_in) {
88 if (opt_out) {
89 // Experiment enabled but user opted out.
90 bookmarks_experiment_new_state = BOOKMARKS_EXPERIMENT_OPT_OUT_FROM_FINCH;
91 } else {
92 // Experiment enabled.
93 bookmarks_experiment_new_state = BOOKMARKS_EXPERIMENT_ENABLED_FROM_FINCH;
94 }
95 } else if (experiment_enabled_from_sync == BOOKMARKS_EXPERIMENT_ENABLED) {
96 // Experiment enabled from Chrome sync.
97 if (opt_out) {
98 // Experiment enabled but user opted out.
99 bookmarks_experiment_new_state =
100 BOOKMARKS_EXPERIMENT_ENABLED_USER_OPT_OUT;
101 } else {
102 // Experiment enabled.
103 bookmarks_experiment_new_state = BOOKMARKS_EXPERIMENT_ENABLED;
104 }
105 } else if (experiment_enabled_from_sync == BOOKMARKS_EXPERIMENT_NONE) {
106 // Experiment is not enabled from Chrome sync.
107 bookmarks_experiment_new_state = BOOKMARKS_EXPERIMENT_NONE;
108 } else if (bookmarks_experiment_state_before ==
109 BOOKMARKS_EXPERIMENT_ENABLED) {
110 if (opt_out) {
111 // Experiment enabled but user opted out.
112 bookmarks_experiment_new_state =
113 BOOKMARKS_EXPERIMENT_ENABLED_USER_OPT_OUT;
114 } else {
115 bookmarks_experiment_new_state = BOOKMARKS_EXPERIMENT_ENABLED;
116 }
117 } else if (bookmarks_experiment_state_before ==
118 BOOKMARKS_EXPERIMENT_ENABLED_USER_OPT_OUT) {
119 if (opt_out) {
120 bookmarks_experiment_new_state =
121 BOOKMARKS_EXPERIMENT_ENABLED_USER_OPT_OUT;
122 } else {
123 // User opted in again.
124 bookmarks_experiment_new_state = BOOKMARKS_EXPERIMENT_ENABLED;
125 }
126 }
127
128 UMA_HISTOGRAM_ENUMERATION("EnhancedBookmarks.SyncExperimentState",
129 bookmarks_experiment_new_state,
130 BOOKMARKS_EXPERIMENT_ENUM_SIZE);
131 user_prefs->SetInteger(
132 sync_driver::prefs::kEnhancedBookmarksExperimentEnabled,
133 bookmarks_experiment_new_state);
134 ForceFinchBookmarkExperimentIfNeeded(flags_storage,
135 bookmarks_experiment_new_state);
136 }
137
ForceFinchBookmarkExperimentIfNeeded(PrefService * flags_storage,BookmarksExperimentState bookmarks_experiment_state)138 void ForceFinchBookmarkExperimentIfNeeded(
139 PrefService* flags_storage,
140 BookmarksExperimentState bookmarks_experiment_state) {
141 if (!flags_storage)
142 return;
143 ListPrefUpdate update(flags_storage, prefs::kEnabledLabsExperiments);
144 base::ListValue* experiments_list = update.Get();
145 if (!experiments_list)
146 return;
147 size_t index;
148 if (bookmarks_experiment_state == BOOKMARKS_EXPERIMENT_NONE) {
149 experiments_list->Remove(
150 base::StringValue(switches::kManualEnhancedBookmarks), &index);
151 experiments_list->Remove(
152 base::StringValue(switches::kManualEnhancedBookmarksOptout), &index);
153 } else if (bookmarks_experiment_state == BOOKMARKS_EXPERIMENT_ENABLED) {
154 experiments_list->Remove(
155 base::StringValue(switches::kManualEnhancedBookmarksOptout), &index);
156 experiments_list->AppendIfNotPresent(
157 new base::StringValue(switches::kManualEnhancedBookmarks));
158 } else if (bookmarks_experiment_state ==
159 BOOKMARKS_EXPERIMENT_ENABLED_USER_OPT_OUT) {
160 experiments_list->Remove(
161 base::StringValue(switches::kManualEnhancedBookmarks), &index);
162 experiments_list->AppendIfNotPresent(
163 new base::StringValue(switches::kManualEnhancedBookmarksOptout));
164 }
165 }
166
IsEnhancedBookmarksExperimentEnabled()167 bool IsEnhancedBookmarksExperimentEnabled() {
168 CommandLine* command_line = CommandLine::ForCurrentProcess();
169 if (command_line->HasSwitch(switches::kManualEnhancedBookmarks) ||
170 command_line->HasSwitch(switches::kManualEnhancedBookmarksOptout)) {
171 return true;
172 }
173
174 return IsEnhancedBookmarksExperimentEnabledFromFinch();
175 }
176
177 #if defined(OS_ANDROID)
IsEnhancedBookmarkImageFetchingEnabled()178 bool IsEnhancedBookmarkImageFetchingEnabled() {
179 if (IsEnhancedBookmarksExperimentEnabled())
180 return true;
181
182 // Salient images are collected from visited bookmarked pages even if the
183 // enhanced bookmark feature is turned off. This is to have some images
184 // available so that in the future, when the feature is turned on, the user
185 // experience is not a big list of flat colors. However as a precautionary
186 // measure it is possible to disable this collection of images from finch.
187 std::string disable_fetching = chrome_variations::GetVariationParamValue(
188 kFieldTrialName, "DisableImagesFetching");
189 return disable_fetching.empty();
190 }
191 #endif
192
IsEnableDomDistillerSet()193 bool IsEnableDomDistillerSet() {
194 if (CommandLine::ForCurrentProcess()->
195 HasSwitch(switches::kEnableDomDistiller)) {
196 return true;
197 }
198 if (chrome_variations::GetVariationParamValue(
199 kFieldTrialName, "enable-dom-distiller") == "1")
200 return true;
201
202 return false;
203 }
204
IsEnableSyncArticlesSet()205 bool IsEnableSyncArticlesSet() {
206 if (CommandLine::ForCurrentProcess()->
207 HasSwitch(switches::kEnableSyncArticles)) {
208 return true;
209 }
210 if (chrome_variations::GetVariationParamValue(
211 kFieldTrialName, "enable-sync-articles") == "1")
212 return true;
213
214 return false;
215 }
216