Home | History | Annotate | Download | only in bookmarks
      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/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 
     25 namespace {
     26 
     27 const char kFieldTrialName[] = "EnhancedBookmarks";
     28 
     29 // Get extension id from Finch EnhancedBookmarks group parameters.
     30 std::string GetEnhancedBookmarksExtensionIdFromFinch() {
     31   return variations::GetVariationParamValue(kFieldTrialName, "id");
     32 }
     33 
     34 // Returns true if enhanced bookmarks experiment is enabled from Finch.
     35 bool IsEnhancedBookmarksExperimentEnabledFromFinch() {
     36   const std::string ext_id = GetEnhancedBookmarksExtensionIdFromFinch();
     37 #if defined(OS_ANDROID)
     38   return !ext_id.empty();
     39 #else
     40   const extensions::FeatureProvider* feature_provider =
     41       extensions::FeatureProvider::GetPermissionFeatures();
     42   extensions::Feature* feature = feature_provider->GetFeature("metricsPrivate");
     43   return feature && feature->IsIdInWhitelist(ext_id);
     44 #endif
     45 }
     46 
     47 };  // namespace
     48 
     49 bool GetBookmarksExperimentExtensionID(const PrefService* user_prefs,
     50                                        std::string* extension_id) {
     51   BookmarksExperimentState bookmarks_experiment_state =
     52       static_cast<BookmarksExperimentState>(user_prefs->GetInteger(
     53           sync_driver::prefs::kEnhancedBookmarksExperimentEnabled));
     54   if (bookmarks_experiment_state == BOOKMARKS_EXPERIMENT_ENABLED_FROM_FINCH) {
     55     *extension_id = GetEnhancedBookmarksExtensionIdFromFinch();
     56     return !extension_id->empty();
     57   }
     58   if (bookmarks_experiment_state == BOOKMARKS_EXPERIMENT_ENABLED) {
     59     *extension_id = user_prefs->GetString(
     60         sync_driver::prefs::kEnhancedBookmarksExtensionId);
     61     return !extension_id->empty();
     62   }
     63 
     64   return false;
     65 }
     66 
     67 void UpdateBookmarksExperimentState(
     68     PrefService* user_prefs,
     69     PrefService* local_state,
     70     bool user_signed_in,
     71     BookmarksExperimentState experiment_enabled_from_sync) {
     72  PrefService* flags_storage = local_state;
     73 #if defined(OS_CHROMEOS)
     74   // Chrome OS is using user prefs for flags storage.
     75   flags_storage = user_prefs;
     76 #endif
     77 
     78   BookmarksExperimentState bookmarks_experiment_state_before =
     79       static_cast<BookmarksExperimentState>(user_prefs->GetInteger(
     80           sync_driver::prefs::kEnhancedBookmarksExperimentEnabled));
     81   // If user signed out, clear possible previous state.
     82   if (!user_signed_in) {
     83     bookmarks_experiment_state_before = BOOKMARKS_EXPERIMENT_NONE;
     84     ForceFinchBookmarkExperimentIfNeeded(flags_storage,
     85         BOOKMARKS_EXPERIMENT_NONE);
     86   }
     87 
     88   // kEnhancedBookmarksExperiment flag could have values "", "1" and "0".
     89   // "0" - user opted out.
     90   bool opt_out = CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
     91                      switches::kEnhancedBookmarksExperiment) == "0";
     92 
     93   BookmarksExperimentState bookmarks_experiment_new_state =
     94       BOOKMARKS_EXPERIMENT_NONE;
     95 
     96   if (IsEnhancedBookmarksExperimentEnabledFromFinch() && !user_signed_in) {
     97     if (opt_out) {
     98       // Experiment enabled but user opted out.
     99       bookmarks_experiment_new_state = BOOKMARKS_EXPERIMENT_OPT_OUT_FROM_FINCH;
    100     } else {
    101       // Experiment enabled.
    102       bookmarks_experiment_new_state = BOOKMARKS_EXPERIMENT_ENABLED_FROM_FINCH;
    103     }
    104   } else if (experiment_enabled_from_sync == BOOKMARKS_EXPERIMENT_ENABLED) {
    105     // Experiment enabled from Chrome sync.
    106     if (opt_out) {
    107       // Experiment enabled but user opted out.
    108       bookmarks_experiment_new_state =
    109           BOOKMARKS_EXPERIMENT_ENABLED_USER_OPT_OUT;
    110     } else {
    111       // Experiment enabled.
    112       bookmarks_experiment_new_state = BOOKMARKS_EXPERIMENT_ENABLED;
    113     }
    114   } else if (experiment_enabled_from_sync == BOOKMARKS_EXPERIMENT_NONE) {
    115     // Experiment is not enabled from Chrome sync.
    116     bookmarks_experiment_new_state = BOOKMARKS_EXPERIMENT_NONE;
    117   } else if (bookmarks_experiment_state_before ==
    118              BOOKMARKS_EXPERIMENT_ENABLED) {
    119     if (opt_out) {
    120       // Experiment enabled but user opted out.
    121       bookmarks_experiment_new_state =
    122           BOOKMARKS_EXPERIMENT_ENABLED_USER_OPT_OUT;
    123     } else {
    124       bookmarks_experiment_new_state = BOOKMARKS_EXPERIMENT_ENABLED;
    125     }
    126   } else if (bookmarks_experiment_state_before ==
    127              BOOKMARKS_EXPERIMENT_ENABLED_USER_OPT_OUT) {
    128     if (opt_out) {
    129       bookmarks_experiment_new_state =
    130           BOOKMARKS_EXPERIMENT_ENABLED_USER_OPT_OUT;
    131     } else {
    132       // User opted in again.
    133       bookmarks_experiment_new_state = BOOKMARKS_EXPERIMENT_ENABLED;
    134     }
    135   }
    136 
    137 #if defined(OS_ANDROID)
    138   bool opt_in = !opt_out
    139       && CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
    140           switches::kEnhancedBookmarksExperiment) == "1";
    141   if (opt_in && bookmarks_experiment_new_state == BOOKMARKS_EXPERIMENT_NONE)
    142     bookmarks_experiment_new_state = BOOKMARKS_EXPERIMENT_ENABLED;
    143 #endif
    144 
    145   UMA_HISTOGRAM_ENUMERATION("EnhancedBookmarks.SyncExperimentState",
    146                             bookmarks_experiment_new_state,
    147                             BOOKMARKS_EXPERIMENT_ENUM_SIZE);
    148   user_prefs->SetInteger(
    149       sync_driver::prefs::kEnhancedBookmarksExperimentEnabled,
    150       bookmarks_experiment_new_state);
    151   ForceFinchBookmarkExperimentIfNeeded(flags_storage,
    152                                        bookmarks_experiment_new_state);
    153 }
    154 
    155 void InitBookmarksExperimentState(Profile* profile) {
    156   SigninManagerBase* signin = SigninManagerFactory::GetForProfile(profile);
    157   bool is_signed_in = signin && signin->IsAuthenticated();
    158   UpdateBookmarksExperimentState(
    159       profile->GetPrefs(),
    160       g_browser_process->local_state(),
    161       is_signed_in,
    162       BOOKMARKS_EXPERIMENT_ENABLED_FROM_SYNC_UNKNOWN);
    163 }
    164 
    165 void ForceFinchBookmarkExperimentIfNeeded(
    166     PrefService* flags_storage,
    167     BookmarksExperimentState bookmarks_experiment_state) {
    168   if (!flags_storage)
    169     return;
    170   ListPrefUpdate update(flags_storage, prefs::kEnabledLabsExperiments);
    171   base::ListValue* experiments_list = update.Get();
    172   if (!experiments_list)
    173     return;
    174   size_t index;
    175   if (bookmarks_experiment_state == BOOKMARKS_EXPERIMENT_NONE) {
    176     experiments_list->Remove(
    177         base::StringValue(switches::kManualEnhancedBookmarks), &index);
    178     experiments_list->Remove(
    179         base::StringValue(switches::kManualEnhancedBookmarksOptout), &index);
    180   } else if (bookmarks_experiment_state == BOOKMARKS_EXPERIMENT_ENABLED) {
    181     experiments_list->Remove(
    182         base::StringValue(switches::kManualEnhancedBookmarksOptout), &index);
    183     experiments_list->AppendIfNotPresent(
    184         new base::StringValue(switches::kManualEnhancedBookmarks));
    185   } else if (bookmarks_experiment_state ==
    186                  BOOKMARKS_EXPERIMENT_ENABLED_USER_OPT_OUT) {
    187     experiments_list->Remove(
    188         base::StringValue(switches::kManualEnhancedBookmarks), &index);
    189     experiments_list->AppendIfNotPresent(
    190         new base::StringValue(switches::kManualEnhancedBookmarksOptout));
    191   }
    192 }
    193 
    194 bool IsEnhancedBookmarksExperimentEnabled(
    195     about_flags::FlagsStorage* flags_storage) {
    196 #if defined(OS_CHROMEOS)
    197   // We are not setting command line flags on Chrome OS to avoid browser restart
    198   // but still have flags in flags_storage. So check flags_storage instead.
    199   const std::set<std::string> flags = flags_storage->GetFlags();
    200   if (flags.find(switches::kManualEnhancedBookmarks) != flags.end())
    201     return true;
    202   if (flags.find(switches::kManualEnhancedBookmarksOptout) != flags.end())
    203     return true;
    204 #else
    205   CommandLine* command_line = CommandLine::ForCurrentProcess();
    206   if (command_line->HasSwitch(switches::kManualEnhancedBookmarks) ||
    207       command_line->HasSwitch(switches::kManualEnhancedBookmarksOptout)) {
    208     return true;
    209   }
    210 #endif
    211 
    212   return IsEnhancedBookmarksExperimentEnabledFromFinch();
    213 }
    214 
    215 #if defined(OS_ANDROID)
    216 bool IsEnhancedBookmarkImageFetchingEnabled(const PrefService* user_prefs) {
    217   if (IsEnhancedBookmarksEnabled(user_prefs))
    218     return true;
    219 
    220   // Salient images are collected from visited bookmarked pages even if the
    221   // enhanced bookmark feature is turned off. This is to have some images
    222   // available so that in the future, when the feature is turned on, the user
    223   // experience is not a big list of flat colors. However as a precautionary
    224   // measure it is possible to disable this collection of images from finch.
    225   std::string disable_fetching = variations::GetVariationParamValue(
    226       kFieldTrialName, "DisableImagesFetching");
    227   return disable_fetching.empty();
    228 }
    229 
    230 bool IsEnhancedBookmarksEnabled(const PrefService* user_prefs) {
    231   BookmarksExperimentState bookmarks_experiment_state =
    232       static_cast<BookmarksExperimentState>(user_prefs->GetInteger(
    233           sync_driver::prefs::kEnhancedBookmarksExperimentEnabled));
    234   return bookmarks_experiment_state == BOOKMARKS_EXPERIMENT_ENABLED ||
    235       bookmarks_experiment_state == BOOKMARKS_EXPERIMENT_ENABLED_FROM_FINCH;
    236 }
    237 #endif
    238 
    239 bool IsEnableDomDistillerSet() {
    240   if (CommandLine::ForCurrentProcess()->
    241       HasSwitch(switches::kEnableDomDistiller)) {
    242     return true;
    243   }
    244   if (variations::GetVariationParamValue(
    245           kFieldTrialName, "enable-dom-distiller") == "1")
    246     return true;
    247 
    248   return false;
    249 }
    250 
    251 bool IsEnableSyncArticlesSet() {
    252   if (CommandLine::ForCurrentProcess()->
    253       HasSwitch(switches::kEnableSyncArticles)) {
    254     return true;
    255   }
    256   if (variations::GetVariationParamValue(
    257           kFieldTrialName, "enable-sync-articles") == "1")
    258     return true;
    259 
    260   return false;
    261 }
    262