enhanced_bookmarks_features.cc revision 5f1c94371a64b3196d4be9466099bb892df9b88e
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
20namespace {
21
22const char kFieldTrialName[] = "EnhancedBookmarks";
23
24// Get extension id from Finch EnhancedBookmarks group parameters.
25std::string GetEnhancedBookmarksExtensionIdFromFinch() {
26  return variations::GetVariationParamValue(kFieldTrialName, "id");
27}
28
29// Returns true if enhanced bookmarks experiment is enabled from Finch.
30bool 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
40bool 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
58void 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
138void 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
167bool 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)
178bool 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 = variations::GetVariationParamValue(
188      kFieldTrialName, "DisableImagesFetching");
189  return disable_fetching.empty();
190}
191#endif
192
193bool IsEnableDomDistillerSet() {
194  if (CommandLine::ForCurrentProcess()->
195      HasSwitch(switches::kEnableDomDistiller)) {
196    return true;
197  }
198  if (variations::GetVariationParamValue(
199          kFieldTrialName, "enable-dom-distiller") == "1")
200    return true;
201
202  return false;
203}
204
205bool IsEnableSyncArticlesSet() {
206  if (CommandLine::ForCurrentProcess()->
207      HasSwitch(switches::kEnableSyncArticles)) {
208    return true;
209  }
210  if (variations::GetVariationParamValue(
211          kFieldTrialName, "enable-sync-articles") == "1")
212    return true;
213
214  return false;
215}
216