• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
IsInstantExtendedAPIEnabled()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.
EmbeddedSearchPageVersion()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 
GetFieldTrialInfo(FieldTrialFlags * flags)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.
GetStringValueForFlagWithDefault(const std::string & flag,const std::string & default_value,const FieldTrialFlags & flags)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.
GetUInt64ValueForFlagWithDefault(const std::string & flag,uint64 default_value,const FieldTrialFlags & flags)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.
GetBoolValueForFlagWithDefault(const std::string & flag,bool default_value,const FieldTrialFlags & flags)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 
ShouldHideTopVerbatimMatch()148 bool ShouldHideTopVerbatimMatch() {
149   FieldTrialFlags flags;
150   return GetFieldTrialInfo(&flags) && GetBoolValueForFlagWithDefault(
151       kHideVerbatimFlagName, false, flags);
152 }
153 
154 }  // namespace chrome
155