| OLD | NEW |
| (Empty) |
| 1 // 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" | |
| 15 #include "chrome/browser/platform_util.h" | |
| 16 #include "chrome/browser/prefs/pref_service.h" | |
| 17 #include "chrome/browser/profile.h" | |
| 18 #include "chrome/common/chrome_switches.h" | |
| 19 #include "chrome/common/pref_names.h" | |
| 20 #include "grit/generated_resources.h" | |
| 21 | |
| 22 namespace about_labs { | |
| 23 | |
| 24 enum { kOsMac = 1 << 0, kOsWin = 1 << 1, kOsLinux = 1 << 2 }; | |
| 25 | |
| 26 struct 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 | |
| 48 const Experiment kExperiments[] = { | |
| 49 { | |
| 50 "expose-for-tabs", | |
| 51 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 { | |
| 62 "vertical-tabs", | |
| 63 IDS_LABS_LEFTTABS_NAME, | |
| 64 IDS_LABS_LEFTTABS_DESCRIPTION, | |
| 65 kOsWin, | |
| 66 switches::kEnableVerticalTabs | |
| 67 } | |
| 68 }; | |
| 69 | |
| 70 // Extracts the list of enabled lab experiments from a profile and stores them | |
| 71 // in a set. | |
| 72 void GetEnabledLabs(const PrefService* prefs, std::set<std::string>* result) { | |
| 73 const ListValue* enabled_experiments = prefs->GetList( | |
| 74 prefs::kEnabledLabsExperiments); | |
| 75 if (!enabled_experiments) | |
| 76 return; | |
| 77 | |
| 78 for (ListValue::const_iterator it = enabled_experiments->begin(); | |
| 79 it != enabled_experiments->end(); | |
| 80 ++it) { | |
| 81 std::string experiment_name; | |
| 82 if (!(*it)->GetAsString(&experiment_name)) { | |
| 83 LOG(WARNING) << "Invalid entry in " << prefs::kEnabledLabsExperiments; | |
| 84 continue; | |
| 85 } | |
| 86 result->insert(experiment_name); | |
| 87 } | |
| 88 } | |
| 89 | |
| 90 // Takes a set of enabled lab experiments | |
| 91 void SetEnabledLabs( | |
| 92 PrefService* prefs, const std::set<std::string>& enabled_experiments) { | |
| 93 ListValue* experiments_list = prefs->GetMutableList( | |
| 94 prefs::kEnabledLabsExperiments); | |
| 95 if (!experiments_list) | |
| 96 return; | |
| 97 | |
| 98 experiments_list->Clear(); | |
| 99 for (std::set<std::string>::const_iterator it = enabled_experiments.begin(); | |
| 100 it != enabled_experiments.end(); | |
| 101 ++it) { | |
| 102 experiments_list->Append(new StringValue(*it)); | |
| 103 } | |
| 104 } | |
| 105 | |
| 106 // Removes all experiments from prefs::kEnabledLabsExperiments that are | |
| 107 // unknown, to prevent this list to become very long as experiments are added | |
| 108 // and removed. | |
| 109 void SanitizeList(PrefService* prefs) { | |
| 110 std::set<std::string> known_experiments; | |
| 111 for (size_t i = 0; i < arraysize(kExperiments); ++i) | |
| 112 known_experiments.insert(kExperiments[i].internal_name); | |
| 113 | |
| 114 std::set<std::string> enabled_experiments; | |
| 115 GetEnabledLabs(prefs, &enabled_experiments); | |
| 116 | |
| 117 std::set<std::string> new_enabled_experiments; | |
| 118 std::set_intersection( | |
| 119 known_experiments.begin(), known_experiments.end(), | |
| 120 enabled_experiments.begin(), enabled_experiments.end(), | |
| 121 std::inserter(new_enabled_experiments, new_enabled_experiments.begin())); | |
| 122 | |
| 123 SetEnabledLabs(prefs, new_enabled_experiments); | |
| 124 } | |
| 125 | |
| 126 void GetSanitizedEnabledLabs( | |
| 127 PrefService* prefs, std::set<std::string>* result) { | |
| 128 SanitizeList(prefs); | |
| 129 GetEnabledLabs(prefs, result); | |
| 130 } | |
| 131 | |
| 132 int GetCurrentPlatform() { | |
| 133 #if defined(OS_MACOSX) | |
| 134 return kOsMac; | |
| 135 #elif defined(OS_WIN) | |
| 136 return kOsWin; | |
| 137 #elif defined(OS_LINUX) | |
| 138 return kOsLinux; | |
| 139 #else | |
| 140 #error Unknown platform | |
| 141 #endif | |
| 142 } | |
| 143 | |
| 144 bool IsEnabled() { | |
| 145 #if defined(OS_CHROMEOS) | |
| 146 // ChromeOS uses a different mechanism for about:labs; integrated with their | |
| 147 // dom ui options. | |
| 148 return false; | |
| 149 #elif defined(GOOGLE_CHROME_BUILD) | |
| 150 // Don't enable this on the stable channel. | |
| 151 return platform_util::GetVersionStringModifier() != string16(); | |
| 152 #else | |
| 153 return true; | |
| 154 #endif | |
| 155 } | |
| 156 | |
| 157 void ConvertLabsToSwitches(Profile* profile, CommandLine* command_line) { | |
| 158 // Do not activate labs features on the stable channel. | |
| 159 if (!IsEnabled()) | |
| 160 return; | |
| 161 | |
| 162 std::set<std::string> enabled_experiments; | |
| 163 GetSanitizedEnabledLabs(profile->GetPrefs(), &enabled_experiments); | |
| 164 | |
| 165 std::map<std::string, const Experiment*> experiments; | |
| 166 for (size_t i = 0; i < arraysize(kExperiments); ++i) | |
| 167 experiments[kExperiments[i].internal_name] = &kExperiments[i]; | |
| 168 | |
| 169 for (std::set<std::string>::iterator it = enabled_experiments.begin(); | |
| 170 it != enabled_experiments.end(); | |
| 171 ++it) { | |
| 172 const std::string& experiment_name = *it; | |
| 173 std::map<std::string, const Experiment*>::iterator experiment = | |
| 174 experiments.find(experiment_name); | |
| 175 DCHECK(experiment != experiments.end()); | |
| 176 if (experiment == experiments.end()) | |
| 177 continue; | |
| 178 | |
| 179 command_line->AppendSwitch(experiment->second->command_line); | |
| 180 } | |
| 181 } | |
| 182 | |
| 183 ListValue* GetLabsExperimentsData(Profile* profile) { | |
| 184 std::set<std::string> enabled_experiments; | |
| 185 GetSanitizedEnabledLabs(profile->GetPrefs(), &enabled_experiments); | |
| 186 | |
| 187 int current_platform = GetCurrentPlatform(); | |
| 188 | |
| 189 ListValue* experiments_data = new ListValue(); | |
| 190 for (size_t i = 0; i < arraysize(kExperiments); ++i) { | |
| 191 const Experiment& experiment = kExperiments[i]; | |
| 192 if (!(experiment.supported_platforms & current_platform)) | |
| 193 continue; | |
| 194 | |
| 195 DictionaryValue* data = new DictionaryValue(); | |
| 196 data->SetString("internal_name", experiment.internal_name); | |
| 197 data->SetString("name", | |
| 198 l10n_util::GetStringUTF16(experiment.visible_name_id)); | |
| 199 data->SetString("description", | |
| 200 l10n_util::GetStringUTF16( | |
| 201 experiment.visible_description_id)); | |
| 202 data->SetBoolean("enabled", | |
| 203 enabled_experiments.count(experiment.internal_name) > 0); | |
| 204 | |
| 205 experiments_data->Append(data); | |
| 206 } | |
| 207 return experiments_data; | |
| 208 } | |
| 209 | |
| 210 static bool needs_restart_ = false; | |
| 211 | |
| 212 bool IsRestartNeededToCommitChanges() { | |
| 213 return needs_restart_; | |
| 214 } | |
| 215 | |
| 216 void SetExperimentEnabled( | |
| 217 Profile* profile, const std::string& internal_name, bool enable) { | |
| 218 needs_restart_ = true; | |
| 219 | |
| 220 std::set<std::string> enabled_experiments; | |
| 221 GetSanitizedEnabledLabs(profile->GetPrefs(), &enabled_experiments); | |
| 222 | |
| 223 if (enable) | |
| 224 enabled_experiments.insert(internal_name); | |
| 225 else | |
| 226 enabled_experiments.erase(internal_name); | |
| 227 | |
| 228 SetEnabledLabs(profile->GetPrefs(), enabled_experiments); | |
| 229 } | |
| 230 | |
| 231 } // namespace Labs | |
| OLD | NEW |