Home | History | Annotate | Download | only in search
      1 // Copyright 2014 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 "components/search/search.h"
      6 
      7 #include "base/command_line.h"
      8 #include "base/metrics/field_trial.h"
      9 #include "base/strings/string_number_conversions.h"
     10 #include "base/strings/string_split.h"
     11 #include "base/strings/string_util.h"
     12 #include "base/strings/utf_string_conversions.h"
     13 #include "components/search/search_switches.h"
     14 
     15 namespace chrome {
     16 
     17 namespace {
     18 
     19 // Configuration options for Embedded Search.
     20 // EmbeddedSearch field trials are named in such a way that we can parse out
     21 // the experiment configuration from the trial's group name in order to give
     22 // us maximum flexability in running experiments.
     23 // Field trial groups should be named things like "Group7 espv:2 instant:1".
     24 // The first token is always GroupN for some integer N, followed by a
     25 // space-delimited list of key:value pairs which correspond to these flags:
     26 const char kEmbeddedPageVersionFlagName[] = "espv";
     27 
     28 #if defined(OS_IOS)
     29 const uint64 kEmbeddedPageVersionDefault = 1;
     30 #elif defined(OS_ANDROID)
     31 const uint64 kEmbeddedPageVersionDefault = 1;
     32 // Use this variant to enable EmbeddedSearch SearchBox API in the results page.
     33 const uint64 kEmbeddedSearchEnabledVersion = 2;
     34 #else
     35 const uint64 kEmbeddedPageVersionDefault = 2;
     36 #endif
     37 
     38 const char kHideVerbatimFlagName[] = "hide_verbatim";
     39 
     40 // Constants for the field trial name and group prefix.
     41 // Note in M30 and below this field trial was named "InstantExtended" and in
     42 // M31 was renamed to EmbeddedSearch for clarity and cleanliness.  Since we
     43 // can't easilly sync up Finch configs with the pushing of this change to
     44 // Dev & Canary, for now the code accepts both names.
     45 // TODO(dcblack): Remove the InstantExtended name once M31 hits the Beta
     46 // channel.
     47 const char kInstantExtendedFieldTrialName[] = "InstantExtended";
     48 const char kEmbeddedSearchFieldTrialName[] = "EmbeddedSearch";
     49 
     50 // If the field trial's group name ends with this string its configuration will
     51 // be ignored and Instant Extended will not be enabled by default.
     52 const char kDisablingSuffix[] = "DISABLED";
     53 
     54 }  // namespace
     55 
     56 bool IsInstantExtendedAPIEnabled() {
     57 #if defined(OS_IOS)
     58   return false;
     59 #elif defined(OS_ANDROID)
     60   return EmbeddedSearchPageVersion() == kEmbeddedSearchEnabledVersion;
     61 #else
     62   return true;
     63 #endif  // defined(OS_IOS)
     64 }
     65 
     66 // Determine what embedded search page version to request from the user's
     67 // default search provider. If 0, the embedded search UI should not be enabled.
     68 uint64 EmbeddedSearchPageVersion() {
     69 #if defined(OS_ANDROID)
     70   if (CommandLine::ForCurrentProcess()->HasSwitch(
     71       switches::kEnableEmbeddedSearchAPI)) {
     72     return kEmbeddedSearchEnabledVersion;
     73   }
     74 #endif
     75 
     76   FieldTrialFlags flags;
     77   if (GetFieldTrialInfo(&flags)) {
     78     return GetUInt64ValueForFlagWithDefault(kEmbeddedPageVersionFlagName,
     79                                             kEmbeddedPageVersionDefault,
     80                                             flags);
     81   }
     82   return kEmbeddedPageVersionDefault;
     83 }
     84 
     85 bool GetFieldTrialInfo(FieldTrialFlags* flags) {
     86   // Get the group name.  If the EmbeddedSearch trial doesn't exist, look for
     87   // the older InstantExtended name.
     88   std::string group_name = base::FieldTrialList::FindFullName(
     89       kEmbeddedSearchFieldTrialName);
     90   if (group_name.empty()) {
     91     group_name = base::FieldTrialList::FindFullName(
     92         kInstantExtendedFieldTrialName);
     93   }
     94 
     95   if (EndsWith(group_name, kDisablingSuffix, true))
     96     return false;
     97 
     98   // We have a valid trial that isn't disabled. Extract the flags.
     99   std::string group_prefix(group_name);
    100   size_t first_space = group_name.find(" ");
    101   if (first_space != std::string::npos) {
    102     // There is a flags section of the group name. Split that out and parse it.
    103     group_prefix = group_name.substr(0, first_space);
    104     if (!base::SplitStringIntoKeyValuePairs(group_name.substr(first_space),
    105                                             ':', ' ', flags)) {
    106       // Failed to parse the flags section. Assume the whole group name is
    107       // invalid.
    108       return false;
    109     }
    110   }
    111   return true;
    112 }
    113 
    114 // Given a FieldTrialFlags object, returns the string value of the provided
    115 // flag.
    116 std::string GetStringValueForFlagWithDefault(const std::string& flag,
    117                                              const std::string& default_value,
    118                                              const FieldTrialFlags& flags) {
    119   FieldTrialFlags::const_iterator i;
    120   for (i = flags.begin(); i != flags.end(); i++) {
    121     if (i->first == flag)
    122       return i->second;
    123   }
    124   return default_value;
    125 }
    126 
    127 // Given a FieldTrialFlags object, returns the uint64 value of the provided
    128 // flag.
    129 uint64 GetUInt64ValueForFlagWithDefault(const std::string& flag,
    130                                         uint64 default_value,
    131                                         const FieldTrialFlags& flags) {
    132   uint64 value;
    133   std::string str_value =
    134       GetStringValueForFlagWithDefault(flag, std::string(), flags);
    135   if (base::StringToUint64(str_value, &value))
    136     return value;
    137   return default_value;
    138 }
    139 
    140 // Given a FieldTrialFlags object, returns the boolean value of the provided
    141 // flag.
    142 bool GetBoolValueForFlagWithDefault(const std::string& flag,
    143                                     bool default_value,
    144                                     const FieldTrialFlags& flags) {
    145   return !!GetUInt64ValueForFlagWithDefault(flag, default_value ? 1 : 0, flags);
    146 }
    147 
    148 bool ShouldHideTopVerbatimMatch() {
    149   FieldTrialFlags flags;
    150   return GetFieldTrialInfo(&flags) && GetBoolValueForFlagWithDefault(
    151       kHideVerbatimFlagName, false, flags);
    152 }
    153 
    154 }  // namespace chrome
    155