blob: dcbecda91932a02d68ef559e299548736695ad95 [file] [log] [blame]
[email protected]ad2a3ded2010-08-27 13:19:051// Copyright (c) 2010 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/labs.h"
6
7#include <algorithm>
8#include <iterator>
9#include <map>
10#include <set>
11
12#include "app/l10n_util.h"
13#include "base/command_line.h"
14#include "base/values.h"
[email protected]ad2a3ded2010-08-27 13:19:0515#include "chrome/browser/prefs/pref_service.h"
[email protected]ad2a3ded2010-08-27 13:19:0516#include "chrome/common/chrome_switches.h"
17#include "chrome/common/pref_names.h"
18#include "grit/generated_resources.h"
19
20namespace about_labs {
21
22enum { kOsMac = 1 << 0, kOsWin = 1 << 1, kOsLinux = 1 << 2 };
23
[email protected]654151872010-09-13 22:43:0524unsigned kOsAll = kOsMac | kOsWin | kOsLinux;
25
[email protected]ad2a3ded2010-08-27 13:19:0526struct Experiment {
27 // The internal name of the experiment. This is never shown to the user.
28 // It _is_ however stored in the prefs file, so you shouldn't change the
29 // name of existing labs.
30 const char* internal_name;
31
32 // String id of the message containing the experiment's name.
33 int visible_name_id;
34
35 // String id of the message containing the experiment's description.
36 int visible_description_id;
37
38 // The platforms the experiment is available on
39 // Needs to be more than a compile-time #ifdef because of profile sync.
40 unsigned supported_platforms; // bitmask
41
42 // The commandline parameter that's added when this lab is active. This is
43 // different from |internal_name| so that the commandline flag can be
44 // renamed without breaking the prefs file.
45 const char* command_line;
46};
47
48const Experiment kExperiments[] = {
49 {
[email protected]232448fb2010-08-27 18:48:2450 "expose-for-tabs", // Do not change; see above.
[email protected]ad2a3ded2010-08-27 13:19:0551 IDS_LABS_TABPOSE_NAME,
52 IDS_LABS_TABPOSE_DESCRIPTION,
53 kOsMac,
54#if defined(OS_MACOSX)
55 // The switch exists only on OS X.
56 switches::kEnableExposeForTabs
57#else
58 ""
59#endif
60 },
61 {
[email protected]232448fb2010-08-27 18:48:2462 "vertical-tabs", // Do not change; see above.
63 IDS_LABS_SIDE_TABS_NAME,
64 IDS_LABS_SIDE_TABS_DESCRIPTION,
[email protected]ad2a3ded2010-08-27 13:19:0565 kOsWin,
66 switches::kEnableVerticalTabs
[email protected]654151872010-09-13 22:43:0567 },
68 {
69 "tabbed-options", // Do not change; see above.
70 IDS_LABS_TABBED_OPTIONS_NAME,
71 IDS_LABS_TABBED_OPTIONS_DESCRIPTION,
72 kOsAll,
73 switches::kEnableTabbedOptions
74 },
[email protected]bcf91672010-09-16 15:40:2175 {
76 "match-preview", // Do not change; see above.
77 IDS_LABS_INSTANT_NAME,
78 IDS_LABS_INSTANT_DESCRIPTION,
79 kOsWin,
80 switches::kEnableMatchPreview
81 },
[email protected]52fa2d52010-09-25 14:08:5682 {
83 "remoting", // Do not change; see above.
84 IDS_LABS_REMOTING_NAME,
[email protected]4fb2f1192010-09-25 14:56:3185#if defined(OS_WIN)
[email protected]52fa2d52010-09-25 14:08:5686 // Windows only supports host functionality at the moment.
87 IDS_LABS_REMOTING_HOST_DESCRIPTION,
88#elif defined(OS_LINUX)
89 // Linux only supports client functionality at the moment.
90 IDS_LABS_REMOTING_CLIENT_DESCRIPTION,
91#else
[email protected]a6940852010-09-25 14:25:3292 // On other platforms, this lab isn't available at all.
93 0,
[email protected]52fa2d52010-09-25 14:08:5694#endif
95 kOsWin | kOsLinux,
96 switches::kEnableRemoting
97 },
[email protected]a6f03652010-09-28 15:59:0798 {
99 "page-info-bubble", // Do not change; see above.
100 IDS_LABS_PAGE_INFO_BUBBLE_NAME,
101 IDS_LABS_PAGE_INFO_BUBBLE_DESCRIPTION,
[email protected]440cb532010-09-30 17:32:28102 kOsAll,
[email protected]a6f03652010-09-28 15:59:07103 switches::kEnableNewPageInfoBubble
[email protected]2e0af762010-09-30 11:34:32104 },
[email protected]57b66d02010-09-30 11:24:51105 {
106 "disable-outdated-plugins", // Do not change; see above.
107 IDS_LABS_DISABLE_OUTDATED_PLUGINS_NAME,
108 IDS_LABS_DISABLE_OUTDATED_PLUGINS_DESCRIPTION,
109 kOsAll,
110 switches::kDisableOutdatedPlugins
111 },
[email protected]b3ce30ea2010-10-01 09:33:53112 {
113 "xss-auditor", // Do not change; see above.
114 IDS_LABS_XSS_AUDITOR_NAME,
115 IDS_LABS_XSS_AUDITOR_DESCRIPTION,
116 kOsAll,
117 switches::kEnableXSSAuditor
118 },
[email protected]aea2ff42010-10-04 18:04:19119 {
120 "background-webapps", // Do not change; see above
121 IDS_LABS_BACKGROUND_WEBAPPS_NAME,
122 IDS_LABS_BACKGROUND_WEBAPPS_DESCRIPTION,
123 kOsAll,
124 switches::kEnableBackgroundMode
[email protected]7bee0b22010-10-05 17:00:47125 },
126 {
127 "cloud-print-proxy", // Do not change; see above.
128 IDS_LABS_CLOUD_PRINT_PROXY_NAME,
129 IDS_LABS_CLOUD_PRINT_PROXY_DESCRIPTION,
130 kOsWin,
131 switches::kEnableCloudPrintProxy
[email protected]aea2ff42010-10-04 18:04:19132 }
[email protected]ad2a3ded2010-08-27 13:19:05133};
134
[email protected]c7b7800a2010-10-07 18:51:35135// Extracts the list of enabled lab experiments from preferences and stores them
[email protected]ad2a3ded2010-08-27 13:19:05136// in a set.
137void GetEnabledLabs(const PrefService* prefs, std::set<std::string>* result) {
138 const ListValue* enabled_experiments = prefs->GetList(
139 prefs::kEnabledLabsExperiments);
140 if (!enabled_experiments)
141 return;
142
143 for (ListValue::const_iterator it = enabled_experiments->begin();
144 it != enabled_experiments->end();
145 ++it) {
146 std::string experiment_name;
147 if (!(*it)->GetAsString(&experiment_name)) {
148 LOG(WARNING) << "Invalid entry in " << prefs::kEnabledLabsExperiments;
149 continue;
150 }
151 result->insert(experiment_name);
152 }
153}
154
155// Takes a set of enabled lab experiments
156void SetEnabledLabs(
157 PrefService* prefs, const std::set<std::string>& enabled_experiments) {
158 ListValue* experiments_list = prefs->GetMutableList(
159 prefs::kEnabledLabsExperiments);
160 if (!experiments_list)
161 return;
162
163 experiments_list->Clear();
164 for (std::set<std::string>::const_iterator it = enabled_experiments.begin();
165 it != enabled_experiments.end();
166 ++it) {
167 experiments_list->Append(new StringValue(*it));
168 }
169}
170
171// Removes all experiments from prefs::kEnabledLabsExperiments that are
172// unknown, to prevent this list to become very long as experiments are added
173// and removed.
174void SanitizeList(PrefService* prefs) {
175 std::set<std::string> known_experiments;
176 for (size_t i = 0; i < arraysize(kExperiments); ++i)
177 known_experiments.insert(kExperiments[i].internal_name);
178
179 std::set<std::string> enabled_experiments;
180 GetEnabledLabs(prefs, &enabled_experiments);
181
182 std::set<std::string> new_enabled_experiments;
183 std::set_intersection(
184 known_experiments.begin(), known_experiments.end(),
185 enabled_experiments.begin(), enabled_experiments.end(),
186 std::inserter(new_enabled_experiments, new_enabled_experiments.begin()));
187
188 SetEnabledLabs(prefs, new_enabled_experiments);
189}
190
191void GetSanitizedEnabledLabs(
192 PrefService* prefs, std::set<std::string>* result) {
193 SanitizeList(prefs);
194 GetEnabledLabs(prefs, result);
195}
196
197int GetCurrentPlatform() {
198#if defined(OS_MACOSX)
199 return kOsMac;
200#elif defined(OS_WIN)
201 return kOsWin;
202#elif defined(OS_LINUX)
203 return kOsLinux;
204#else
205#error Unknown platform
206#endif
207}
208
209bool IsEnabled() {
210#if defined(OS_CHROMEOS)
211 // ChromeOS uses a different mechanism for about:labs; integrated with their
212 // dom ui options.
[email protected]9bbf9702010-10-02 00:25:38213 // TODO(thakis): Port about:labs to chromeos -- http://crbug.com/57634
[email protected]ad2a3ded2010-08-27 13:19:05214 return false;
[email protected]ad2a3ded2010-08-27 13:19:05215#else
216 return true;
217#endif
218}
219
[email protected]c7b7800a2010-10-07 18:51:35220void ConvertLabsToSwitches(PrefService* prefs, CommandLine* command_line) {
[email protected]ad2a3ded2010-08-27 13:19:05221 if (!IsEnabled())
222 return;
223
224 std::set<std::string> enabled_experiments;
[email protected]c7b7800a2010-10-07 18:51:35225 GetSanitizedEnabledLabs(prefs, &enabled_experiments);
[email protected]ad2a3ded2010-08-27 13:19:05226
227 std::map<std::string, const Experiment*> experiments;
228 for (size_t i = 0; i < arraysize(kExperiments); ++i)
229 experiments[kExperiments[i].internal_name] = &kExperiments[i];
230
231 for (std::set<std::string>::iterator it = enabled_experiments.begin();
232 it != enabled_experiments.end();
233 ++it) {
234 const std::string& experiment_name = *it;
235 std::map<std::string, const Experiment*>::iterator experiment =
236 experiments.find(experiment_name);
237 DCHECK(experiment != experiments.end());
238 if (experiment == experiments.end())
239 continue;
240
241 command_line->AppendSwitch(experiment->second->command_line);
242 }
243}
244
[email protected]c7b7800a2010-10-07 18:51:35245ListValue* GetLabsExperimentsData(PrefService* prefs) {
[email protected]ad2a3ded2010-08-27 13:19:05246 std::set<std::string> enabled_experiments;
[email protected]c7b7800a2010-10-07 18:51:35247 GetSanitizedEnabledLabs(prefs, &enabled_experiments);
[email protected]ad2a3ded2010-08-27 13:19:05248
249 int current_platform = GetCurrentPlatform();
250
251 ListValue* experiments_data = new ListValue();
252 for (size_t i = 0; i < arraysize(kExperiments); ++i) {
253 const Experiment& experiment = kExperiments[i];
254 if (!(experiment.supported_platforms & current_platform))
255 continue;
256
257 DictionaryValue* data = new DictionaryValue();
258 data->SetString("internal_name", experiment.internal_name);
259 data->SetString("name",
260 l10n_util::GetStringUTF16(experiment.visible_name_id));
261 data->SetString("description",
262 l10n_util::GetStringUTF16(
263 experiment.visible_description_id));
264 data->SetBoolean("enabled",
265 enabled_experiments.count(experiment.internal_name) > 0);
266
267 experiments_data->Append(data);
268 }
269 return experiments_data;
270}
271
272static bool needs_restart_ = false;
273
274bool IsRestartNeededToCommitChanges() {
275 return needs_restart_;
276}
277
278void SetExperimentEnabled(
[email protected]c7b7800a2010-10-07 18:51:35279 PrefService* prefs, const std::string& internal_name, bool enable) {
[email protected]ad2a3ded2010-08-27 13:19:05280 needs_restart_ = true;
281
282 std::set<std::string> enabled_experiments;
[email protected]c7b7800a2010-10-07 18:51:35283 GetSanitizedEnabledLabs(prefs, &enabled_experiments);
[email protected]ad2a3ded2010-08-27 13:19:05284
285 if (enable)
286 enabled_experiments.insert(internal_name);
287 else
288 enabled_experiments.erase(internal_name);
289
[email protected]c7b7800a2010-10-07 18:51:35290 SetEnabledLabs(prefs, enabled_experiments);
[email protected]ad2a3ded2010-08-27 13:19:05291}
292
293} // namespace Labs