diff options
author | sky@chromium.org <sky@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-12-02 16:35:19 +0000 |
---|---|---|
committer | sky@chromium.org <sky@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-12-02 16:35:19 +0000 |
commit | 8a6ff28d37e1010ef77251f232ba5008b28ddc97 (patch) | |
tree | df509f80047be1cc3dc08971361c071e7ff47b47 | |
parent | c25108500d8b37f8e8fe194070e99eb8550cc9a5 (diff) | |
download | chromium_src-8a6ff28d37e1010ef77251f232ba5008b28ddc97.zip chromium_src-8a6ff28d37e1010ef77251f232ba5008b28ddc97.tar.gz chromium_src-8a6ff28d37e1010ef77251f232ba5008b28ddc97.tar.bz2 |
Adds ability for about:flags to use a select for choosing one of many
values, and wires this up for instant.
BUG=none
TEST=none
Review URL: http://codereview.chromium.org/5451003
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@68022 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | chrome/app/generated_resources.grd | 17 | ||||
-rw-r--r-- | chrome/browser/about_flags.cc | 235 | ||||
-rw-r--r-- | chrome/browser/about_flags.h | 40 | ||||
-rw-r--r-- | chrome/browser/about_flags_unittest.cc | 91 | ||||
-rw-r--r-- | chrome/browser/instant/instant_controller.cc | 6 | ||||
-rw-r--r-- | chrome/browser/resources/flags.html | 30 | ||||
-rw-r--r-- | chrome/common/chrome_switches.cc | 6 | ||||
-rw-r--r-- | chrome/common/chrome_switches.h | 1 |
8 files changed, 362 insertions, 64 deletions
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd index 3c237d1..31bb302 100644 --- a/chrome/app/generated_resources.grd +++ b/chrome/app/generated_resources.grd @@ -4065,11 +4065,20 @@ Keep your key file in a safe place. You will need it to create new versions of y <message name="IDS_FLAGS_PREDICTIVE_INSTANT_DESCRIPTION" desc="Description of the predictive 'Instant' lab."> Makes the address bar load urls as you type. Search results are shown for the best match. </message> - <message name="IDS_FLAGS_VERBATIM_INSTANT_NAME" desc="Description of the verbatim 'Instant' lab."> - Verbatim Instant + <message name="IDS_FLAGS_INSTANT_TYPE_NAME" desc="Description of the 'Instant Type' lab."> + Instant Type </message> - <message name="IDS_FLAGS_VERBATIM_INSTANT_DESCRIPTION" desc="Description of the verbatim 'Instant' lab."> - Makes the address bar load urls as you type. Search results are shown exactly as you typed them. + <message name="IDS_FLAGS_INSTANT_TYPE_DESCRIPTION" desc="Description of the 'Instant Type' lab."> + Configures the behavior of instant. + </message> + <message name="IDS_FLAGS_INSTANT_TYPE_PREDICTIVE" desc="Name for 'predictive' instant results"> + Predictive + </message> + <message name="IDS_FLAGS_INSTANT_TYPE_PREDICTIVE_NO_AUTO_COMPLETE" desc="Name for 'predictive no auto-complete' instant results"> + Predictive no auto-complete + </message> + <message name="IDS_FLAGS_INSTANT_TYPE_VERBATIM" desc="Name for 'verbatim' instant results"> + Verbatim </message> <message name="IDS_FLAGS_REMOTING_NAME" desc="Description of the 'Remoting' lab."> Remoting diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc index 38ea7f7..fec86c4 100644 --- a/chrome/browser/about_flags.cc +++ b/chrome/browser/about_flags.cc @@ -12,6 +12,7 @@ #include "app/l10n_util.h" #include "base/command_line.h" #include "base/singleton.h" +#include "base/string_number_conversions.h" #include "base/values.h" #include "chrome/browser/metrics/user_metrics.h" #include "chrome/browser/prefs/pref_service.h" @@ -21,6 +22,12 @@ namespace about_flags { +// Macros to simplify specifying the type. +#define SINGLE_VALUE_TYPE(command_line) Experiment::SINGLE_VALUE, \ + command_line, NULL, 0 +#define MULTI_VALUE_TYPE(choices) Experiment::MULTI_VALUE, "", choices, \ + arraysize(choices) + namespace { const unsigned kOsAll = kOsMac | kOsWin | kOsLinux | kOsCrOS; @@ -31,6 +38,15 @@ const char kMediaPlayerExperimentName[] = "media-player"; const char kAdvancedFileSystemExperimentName[] = "advanced-file-system"; const char kVerticalTabsExperimentName[] = "vertical-tabs"; +// If adding a new choice, add it to the end of the list. +const Experiment::Choice kInstantChoices[] = { + { IDS_FLAGS_INSTANT_TYPE_VERBATIM, switches::kEnableVerbatimInstant }, + { IDS_FLAGS_INSTANT_TYPE_PREDICTIVE, switches::kEnablePredictiveInstant }, + { IDS_FLAGS_INSTANT_TYPE_PREDICTIVE_NO_AUTO_COMPLETE, + switches::kEnablePredictiveNoAutoCompleteInstant + }, +}; + // RECORDING USER METRICS FOR FLAGS: // ----------------------------------------------------------------------------- // The first line of the experiment is the internal name. If you'd like to @@ -51,6 +67,16 @@ const char kVerticalTabsExperimentName[] = "vertical-tabs"; // TODO(rsesek): See if there's a way to count per-user, rather than // per-startup. +// To add a new experiment add to the end of kExperiments. There are two +// distinct types of experiments: +// . SINGLE_VALUE: experiment is either on or off. Use the SINGLE_VALUE_TYPE +// macro for this type supplying the command line to the macro. +// . MULTI_VALUE: if enabled the command line of the selected choice is enabled. +// To specify this type of experiment use the macro MULTI_VALUE_TYPE supplying +// it the array of choices. +// See the documentation of Experiment for details on the fields. +// +// When adding a new choice, add it to the end of the list. const Experiment kExperiments[] = { { "expose-for-tabs", // FLAGS:RECORD_UMA @@ -59,9 +85,9 @@ const Experiment kExperiments[] = { kOsMac, #if defined(OS_MACOSX) // The switch exists only on OS X. - switches::kEnableExposeForTabs + SINGLE_VALUE_TYPE(switches::kEnableExposeForTabs) #else - "" + SINGLE_VALUE_TYPE("") #endif }, { @@ -71,9 +97,9 @@ const Experiment kExperiments[] = { kOsCrOS, #if defined(OS_CHROMEOS) // The switch exists only on Chrome OS. - switches::kEnableMediaPlayer + SINGLE_VALUE_TYPE(switches::kEnableMediaPlayer) #else - "" + SINGLE_VALUE_TYPE("") #endif }, { @@ -83,9 +109,9 @@ const Experiment kExperiments[] = { kOsCrOS, #if defined(OS_CHROMEOS) // The switch exists only on Chrome OS. - switches::kEnableAdvancedFileSystem + SINGLE_VALUE_TYPE(switches::kEnableAdvancedFileSystem) #else - "" + SINGLE_VALUE_TYPE("") #endif }, { @@ -93,14 +119,14 @@ const Experiment kExperiments[] = { IDS_FLAGS_SIDE_TABS_NAME, IDS_FLAGS_SIDE_TABS_DESCRIPTION, kOsWin | kOsCrOS, - switches::kEnableVerticalTabs + SINGLE_VALUE_TYPE(switches::kEnableVerticalTabs) }, { "tabbed-options", // FLAGS:RECORD_UMA IDS_FLAGS_TABBED_OPTIONS_NAME, IDS_FLAGS_TABBED_OPTIONS_DESCRIPTION, kOsWin | kOsLinux | kOsMac, // Enabled by default on CrOS. - switches::kEnableTabbedOptions + SINGLE_VALUE_TYPE(switches::kEnableTabbedOptions) }, { "remoting", // FLAGS:RECORD_UMA @@ -116,35 +142,35 @@ const Experiment kExperiments[] = { 0, #endif kOsWin | kOsLinux | kOsCrOS, - switches::kEnableRemoting + SINGLE_VALUE_TYPE(switches::kEnableRemoting) }, { "disable-outdated-plugins", // FLAGS:RECORD_UMA IDS_FLAGS_DISABLE_OUTDATED_PLUGINS_NAME, IDS_FLAGS_DISABLE_OUTDATED_PLUGINS_DESCRIPTION, kOsAll, - switches::kDisableOutdatedPlugins + SINGLE_VALUE_TYPE(switches::kDisableOutdatedPlugins) }, { "xss-auditor", // FLAGS:RECORD_UMA IDS_FLAGS_XSS_AUDITOR_NAME, IDS_FLAGS_XSS_AUDITOR_DESCRIPTION, kOsAll, - switches::kEnableXSSAuditor + SINGLE_VALUE_TYPE(switches::kEnableXSSAuditor) }, { "background-webapps", // FLAGS:RECORD_UMA IDS_FLAGS_BACKGROUND_WEBAPPS_NAME, IDS_FLAGS_BACKGROUND_WEBAPPS_DESCRIPTION, kOsMac | kOsLinux | kOsCrOS, // Enabled by default on windows - switches::kEnableBackgroundMode + SINGLE_VALUE_TYPE(switches::kEnableBackgroundMode) }, { "conflicting-modules-check", // FLAGS:RECORD_UMA IDS_FLAGS_CONFLICTS_CHECK_NAME, IDS_FLAGS_CONFLICTS_CHECK_DESCRIPTION, kOsWin, - switches::kConflictingModulesCheck + SINGLE_VALUE_TYPE(switches::kConflictingModulesCheck) }, { "cloud-print-proxy", // FLAGS:RECORD_UMA @@ -159,21 +185,21 @@ const Experiment kExperiments[] = { // plug-in could be supplied, we'll keep the lab enabled. kOsWin, #endif - switches::kEnableCloudPrintProxy + SINGLE_VALUE_TYPE(switches::kEnableCloudPrintProxy) }, { "crxless-web-apps", IDS_FLAGS_CRXLESS_WEB_APPS_NAME, IDS_FLAGS_CRXLESS_WEB_APPS_DESCRIPTION, kOsAll, - switches::kEnableCrxlessWebApps + SINGLE_VALUE_TYPE(switches::kEnableCrxlessWebApps) }, { "match-preview", // FLAGS:RECORD_UMA IDS_FLAGS_PREDICTIVE_INSTANT_NAME, IDS_FLAGS_PREDICTIVE_INSTANT_DESCRIPTION, kOsMac, - switches::kEnablePredictiveInstant + SINGLE_VALUE_TYPE(switches::kEnablePredictiveInstant) }, // FIXME(scheib): Add Flags entry for accelerated Compositing, // or pull it and the strings in generated_resources.grd by Dec 2010 @@ -182,14 +208,14 @@ const Experiment kExperiments[] = { // IDS_FLAGS_ACCELERATED_COMPOSITING_NAME, // IDS_FLAGS_ACCELERATED_COMPOSITING_DESCRIPTION, // kOsAll, - // switches::kDisableAcceleratedCompositing + // SINGLE_VALUE_TYPE(switches::kDisableAcceleratedCompositing) // }, { "gpu-canvas-2d", // FLAGS:RECORD_UMA IDS_FLAGS_ACCELERATED_CANVAS_2D_NAME, IDS_FLAGS_ACCELERATED_CANVAS_2D_DESCRIPTION, kOsWin | kOsLinux | kOsCrOS, - switches::kEnableAccelerated2dCanvas + SINGLE_VALUE_TYPE(switches::kEnableAccelerated2dCanvas) }, // FIXME(scheib): Add Flags entry for WebGL, // or pull it and the strings in generated_resources.grd by Dec 2010 @@ -198,71 +224,78 @@ const Experiment kExperiments[] = { // IDS_FLAGS_WEBGL_NAME, // IDS_FLAGS_WEBGL_DESCRIPTION, // kOsAll, - // switches::kDisableExperimentalWebGL + // SINGLE_VALUE_TYPE(switches::kDisableExperimentalWebGL) // } { "print-preview", // FLAGS:RECORD_UMA IDS_FLAGS_PRINT_PREVIEW_NAME, IDS_FLAGS_PRINT_PREVIEW_DESCRIPTION, kOsAll, - switches::kEnablePrintPreview + SINGLE_VALUE_TYPE(switches::kEnablePrintPreview) }, { "enable-nacl", // FLAGS:RECORD_UMA IDS_FLAGS_ENABLE_NACL_NAME, IDS_FLAGS_ENABLE_NACL_DESCRIPTION, kOsAll, - switches::kEnableNaCl + SINGLE_VALUE_TYPE(switches::kEnableNaCl) }, { "dns-server", // FLAGS:RECORD_UMA IDS_FLAGS_DNS_SERVER_NAME, IDS_FLAGS_DNS_SERVER_DESCRIPTION, kOsLinux, - switches::kDnsServer + SINGLE_VALUE_TYPE(switches::kDnsServer) }, { "page-prerender", // FLAGS:RECORD_UMA IDS_FLAGS_PAGE_PRERENDER_NAME, IDS_FLAGS_PAGE_PRERENDER_DESCRIPTION, kOsAll, - switches::kEnablePagePrerender + SINGLE_VALUE_TYPE(switches::kEnablePagePrerender) }, { "confirm-to-quit", // FLAGS:RECORD_UMA IDS_FLAGS_CONFIRM_TO_QUIT_NAME, IDS_FLAGS_CONFIRM_TO_QUIT_DESCRIPTION, kOsMac, - switches::kEnableConfirmToQuit + SINGLE_VALUE_TYPE(switches::kEnableConfirmToQuit) }, { "extension-apis", // FLAGS:RECORD_UMA IDS_FLAGS_EXPERIMENTAL_EXTENSION_APIS_NAME, IDS_FLAGS_EXPERIMENTAL_EXTENSION_APIS_DESCRIPTION, kOsAll, - switches::kEnableExperimentalExtensionApis + SINGLE_VALUE_TYPE(switches::kEnableExperimentalExtensionApis) }, { "click-to-play", // FLAGS:RECORD_UMA IDS_FLAGS_CLICK_TO_PLAY_NAME, IDS_FLAGS_CLICK_TO_PLAY_DESCRIPTION, kOsAll, - switches::kEnableClickToPlay + SINGLE_VALUE_TYPE(switches::kEnableClickToPlay) }, { "disable-hyperlink-auditing", IDS_FLAGS_DISABLE_HYPERLINK_AUDITING_NAME, IDS_FLAGS_DISABLE_HYPERLINK_AUDITING_DESCRIPTION, kOsAll, - switches::kNoPings + SINGLE_VALUE_TYPE(switches::kNoPings) }, { "experimental-location-features", // FLAGS:RECORD_UMA IDS_FLAGS_EXPERIMENTAL_LOCATION_FEATURES_NAME, IDS_FLAGS_EXPERIMENTAL_LOCATION_FEATURES_DESCRIPTION, kOsMac | kOsWin | kOsLinux, // Currently does nothing on CrOS. - switches::kExperimentalLocationFeatures - } + SINGLE_VALUE_TYPE(switches::kExperimentalLocationFeatures) + }, + { + "instant-type", // FLAGS:RECORD_UMA + IDS_FLAGS_INSTANT_TYPE_NAME, + IDS_FLAGS_INSTANT_TYPE_DESCRIPTION, + kOsWin, + MULTI_VALUE_TYPE(kInstantChoices) + }, }; const Experiment* experiments = kExperiments; @@ -347,13 +380,32 @@ void SetEnabledFlags( } } +// Returns the name used in prefs for the choice at the specified index. +std::string NameForChoice(const Experiment& e, int index) { + DCHECK(e.type == Experiment::MULTI_VALUE); + DCHECK(index < e.num_choices); + return std::string(e.internal_name) + about_flags::testing::kMultiSeparator + + base::IntToString(index); +} + +// Adds the internal names for the specified experiment to |names|. +void AddInternalName(const Experiment& e, std::set<std::string>* names) { + if (e.type == Experiment::SINGLE_VALUE) { + names->insert(e.internal_name); + } else { + DCHECK(e.type == Experiment::MULTI_VALUE); + for (int i = 0; i < e.num_choices; ++i) + names->insert(NameForChoice(e, i)); + } +} + // Removes all experiments from prefs::kEnabledLabsExperiments that are // unknown, to prevent this list to become very long as experiments are added // and removed. void SanitizeList(PrefService* prefs) { std::set<std::string> known_experiments; for (size_t i = 0; i < num_experiments; ++i) - known_experiments.insert(experiments[i].internal_name); + AddInternalName(experiments[i], &known_experiments); std::set<std::string> enabled_experiments; GetEnabledFlags(prefs, &enabled_experiments); @@ -386,7 +438,7 @@ void GetSanitizedEnabledFlagsForCurrentPlatform( int current_platform = GetCurrentPlatform(); for (size_t i = 0; i < num_experiments; ++i) { if (experiments[i].supported_platforms & current_platform) - platform_experiments.insert(experiments[i].internal_name); + AddInternalName(experiments[i], &platform_experiments); } std::set<std::string> new_enabled_experiments; @@ -398,6 +450,29 @@ void GetSanitizedEnabledFlagsForCurrentPlatform( result->swap(new_enabled_experiments); } +// Returns the Value representing the choice data in the specified experiment. +// If one of the choices is enabled |is_one_selected| is set to true. +Value* CreateChoiceData(const Experiment& experiment, + const std::set<std::string>& enabled_experiments, + bool* is_one_selected) { + DCHECK(experiment.type == Experiment::MULTI_VALUE); + ListValue* result = new ListValue; + for (int i = 0; i < experiment.num_choices; ++i) { + const Experiment::Choice& choice = experiment.choices[i]; + DictionaryValue* value = new DictionaryValue; + std::string name = NameForChoice(experiment, i); + value->SetString("description", + l10n_util::GetStringUTF16(choice.description_id)); + value->SetString("internal_name", name); + bool is_selected = enabled_experiments.count(name) > 0; + if (is_selected) + *is_one_selected = true; + value->SetBoolean("selected", is_selected); + result->Append(value); + } + return result; +} + } // namespace void ConvertFlagsToSwitches(PrefService* prefs, CommandLine* command_line) { @@ -423,9 +498,15 @@ ListValue* GetFlagsExperimentsData(PrefService* prefs) { data->SetString("description", l10n_util::GetStringUTF16( experiment.visible_description_id)); - data->SetBoolean("enabled", - enabled_experiments.count(experiment.internal_name) > 0); + bool enabled = enabled_experiments.count(experiment.internal_name) > 0; + + if (experiment.type == Experiment::MULTI_VALUE) { + data->Set("choices", CreateChoiceData(experiment, enabled_experiments, + &enabled)); + } + + data->SetBoolean("enabled", enabled); experiments_data->Append(data); } return experiments_data; @@ -494,9 +575,17 @@ void FlagsState::ConvertFlagsToSwitches( GetSanitizedEnabledFlagsForCurrentPlatform(prefs, &enabled_experiments); - std::map<std::string, const Experiment*> experiment_map; - for (size_t i = 0; i < num_experiments; ++i) - experiment_map[experiments[i].internal_name] = &experiments[i]; + typedef std::map<std::string, std::string> NameToSwitchMap; + NameToSwitchMap name_to_switch_map; + for (size_t i = 0; i < num_experiments; ++i) { + const Experiment& e = experiments[i]; + if (e.type == Experiment::SINGLE_VALUE) { + name_to_switch_map[e.internal_name] = e.command_line; + } else { + for (int j = 0; j < e.num_choices; ++j) + name_to_switch_map[NameForChoice(e, j)] = e.choices[j].command_line; + } + } command_line->AppendSwitch(switches::kFlagSwitchesBegin); flags_switches_.insert(switches::kFlagSwitchesBegin); @@ -504,14 +593,15 @@ void FlagsState::ConvertFlagsToSwitches( it != enabled_experiments.end(); ++it) { const std::string& experiment_name = *it; - std::map<std::string, const Experiment*>::iterator experiment = - experiment_map.find(experiment_name); - DCHECK(experiment != experiment_map.end()); - if (experiment == experiment_map.end()) + NameToSwitchMap::const_iterator name_to_switch_it = + name_to_switch_map.find(experiment_name); + if (name_to_switch_it == name_to_switch_map.end()) { + NOTREACHED(); continue; + } - command_line->AppendSwitch(experiment->second->command_line); - flags_switches_.insert(experiment->second->command_line); + command_line->AppendSwitch(name_to_switch_it->second); + flags_switches_.insert(name_to_switch_it->second); } command_line->AppendSwitch(switches::kFlagSwitchesEnd); flags_switches_.insert(switches::kFlagSwitchesEnd); @@ -525,13 +615,56 @@ void FlagsState::SetExperimentEnabled( PrefService* prefs, const std::string& internal_name, bool enable) { needs_restart_ = true; + size_t at_index = internal_name.find(about_flags::testing::kMultiSeparator); + if (at_index != std::string::npos) { + DCHECK(enable); + // We're being asked to enable a multi-choice experiment. Disable the + // currently selected choice. + DCHECK_NE(at_index, 0u); + SetExperimentEnabled(prefs, internal_name.substr(0, at_index), false); + + // And enable the new choice. + std::set<std::string> enabled_experiments; + GetSanitizedEnabledFlags(prefs, &enabled_experiments); + enabled_experiments.insert(internal_name); + SetEnabledFlags(prefs, enabled_experiments); + return; + } + std::set<std::string> enabled_experiments; GetSanitizedEnabledFlags(prefs, &enabled_experiments); - if (enable) - enabled_experiments.insert(internal_name); - else - enabled_experiments.erase(internal_name); + const Experiment* e = NULL; + for (size_t i = 0; i < num_experiments; ++i) { + if (experiments[i].internal_name == internal_name) { + e = experiments + i; + break; + } + } + DCHECK(e); + + if (e->type == Experiment::SINGLE_VALUE) { + if (enable) + enabled_experiments.insert(internal_name); + else + enabled_experiments.erase(internal_name); + } else { + if (enable) { + // Enable the first choice. + enabled_experiments.insert(NameForChoice(*e, 0)); + } else { + // Find the currently enabled choice and disable it. + for (int i = 0; i < e->num_choices; ++i) { + std::string choice_name = NameForChoice(*e, i); + if (enabled_experiments.find(choice_name) != + enabled_experiments.end()) { + enabled_experiments.erase(choice_name); + // Continue on just in case there's a bug and more than one + // experiment for this choice was enabled. + } + } + } + } SetEnabledFlags(prefs, enabled_experiments); } @@ -553,6 +686,11 @@ void FlagsState::reset() { } // namespace namespace testing { + +// WARNING: '@' is also used in the html file. If you update this constant you +// also need to update the html file. +const char kMultiSeparator[] = "@"; + void ClearState() { FlagsState::instance()->reset(); } @@ -567,6 +705,11 @@ void SetExperiments(const Experiment* e, size_t count) { } } +const Experiment* GetExperiments(size_t* count) { + *count = num_experiments; + return experiments; +} + } // namespace testing } // namespace about_flags diff --git a/chrome/browser/about_flags.h b/chrome/browser/about_flags.h index fa8c868..daa76df 100644 --- a/chrome/browser/about_flags.h +++ b/chrome/browser/about_flags.h @@ -24,6 +24,27 @@ enum { kOsMac = 1 << 0, kOsWin = 1 << 1, kOsLinux = 1 << 2 , kOsCrOS = 1 << 3 }; // for testing). // This is exposed only for testing. struct Experiment { + enum Type { + // An experiment with a single value. This is typically what you want. + SINGLE_VALUE, + + // The experiment has multiple values only one of which is ever enabled. + // For MULTI_VALUE experiments the command_line of the Experiment is not + // used. If the experiment is enabled the command line of the selected + // Choice is enabled. + MULTI_VALUE, + }; + + // Used for MULTI_VALUE types to describe one of the possible values the user + // can select. + struct Choice { + // ID of the message containing the choice name. + int description_id; + + // Command line to enabled for this choice. + const char* command_line; + }; + // The internal name of the experiment. This is never shown to the user. // It _is_ however stored in the prefs file, so you shouldn't change the // name of existing flags. @@ -39,10 +60,21 @@ struct Experiment { // Needs to be more than a compile-time #ifdef because of profile sync. unsigned supported_platforms; // bitmask + // Type of experiment. + Type type; + // The commandline parameter that's added when this lab is active. This is // different from |internal_name| so that the commandline flag can be // renamed without breaking the prefs file. + // This is used if type is SINGLE_VALUE. const char* command_line; + + // This is used if type is MULTI_VALUE. + const Choice* choices; + + // Number of |choices|. + // This is used if type is MULTI_VALUE. + int num_choices; }; // Reads the Labs |prefs| (called "Labs" for historical reasons) and adds the @@ -80,6 +112,14 @@ void ClearState(); // Sets the list of experiments. Pass in NULL to use the default set. This does // NOT take ownership of the supplied Experiments. void SetExperiments(const Experiment* e, size_t count); + +// Returns the current set of experiments. +const Experiment* GetExperiments(size_t* count); + +// Separator used for multi values. Multi values are represented in prefs as +// name-of-experiment + kMultiSeparator + selected_index. +extern const char kMultiSeparator[]; + } // namespace testing } // namespace about_flags diff --git a/chrome/browser/about_flags_unittest.cc b/chrome/browser/about_flags_unittest.cc index f6b5193..c3bbe95 100644 --- a/chrome/browser/about_flags_unittest.cc +++ b/chrome/browser/about_flags_unittest.cc @@ -2,9 +2,9 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "chrome/browser/about_flags.h" - +#include "base/string_number_conversions.h" #include "base/values.h" +#include "chrome/browser/about_flags.h" #include "chrome/common/chrome_switches.h" #include "chrome/common/pref_names.h" #include "chrome/test/testing_pref_service.h" @@ -14,37 +14,64 @@ const char kFlags1[] = "flag1"; const char kFlags2[] = "flag2"; const char kFlags3[] = "flag3"; +const char kFlags4[] = "flag4"; const char kSwitch1[] = "switch"; const char kSwitch2[] = "switch2"; const char kSwitch3[] = "switch3"; +const char kMultiSwitch1[] = "multi_switch1"; +const char kMultiSwitch2[] = "multi_switch2"; + namespace about_flags { -// The experiments that are set for these tests. The first two experiments are -// supported on the current platform, but the last is only supported on a -// platform other than the current. +const Experiment::Choice kMultiChoices[] = { + { IDS_PRODUCT_NAME, kMultiSwitch1 }, + { IDS_PRODUCT_NAME, kMultiSwitch2 }, +}; + +// The experiments that are set for these tests. The 3rd experiment is not +// supported on the current platform, all others are. static Experiment kExperiments[] = { { kFlags1, IDS_PRODUCT_NAME, IDS_PRODUCT_NAME, 0, // Ends up being mapped to the current platform. - kSwitch1 + Experiment::SINGLE_VALUE, + kSwitch1, + NULL, + 0 }, { kFlags2, IDS_PRODUCT_NAME, IDS_PRODUCT_NAME, 0, // Ends up being mapped to the current platform. - kSwitch2 + Experiment::SINGLE_VALUE, + kSwitch2, + NULL, + 0 }, { kFlags3, IDS_PRODUCT_NAME, IDS_PRODUCT_NAME, 0, // This ends up enabling for an OS other than the current. - kSwitch3 + Experiment::SINGLE_VALUE, + kSwitch3, + NULL, + 0 + }, + { + kFlags4, + IDS_PRODUCT_NAME, + IDS_PRODUCT_NAME, + 0, // Ends up being mapped to the current platform. + Experiment::MULTI_VALUE, + "", + kMultiChoices, + arraysize(kMultiChoices) }, }; @@ -176,7 +203,7 @@ TEST_F(AboutFlagsTest, RemoveFlagSwitches) { // Tests enabling experiments that aren't supported on the current platform. TEST_F(AboutFlagsTest, PersistAndPrune) { - // Enable exerpiement 1 and experiment 3. + // Enable experiments 1 and 3. SetExperimentEnabled(&prefs_, kFlags1, true); SetExperimentEnabled(&prefs_, kFlags3, true); CommandLine command_line(CommandLine::NO_PROGRAM); @@ -192,7 +219,51 @@ TEST_F(AboutFlagsTest, PersistAndPrune) { // Experiment 3 should show still be persisted in preferences though. scoped_ptr<ListValue> switch_prefs(GetFlagsExperimentsData(&prefs_)); ASSERT_TRUE(switch_prefs.get()); - EXPECT_EQ(2u, switch_prefs->GetSize()); + EXPECT_EQ(arraysize(kExperiments) - 1, switch_prefs->GetSize()); +} + +// Tests enabling multi-value type experiments. +TEST_F(AboutFlagsTest, MultiValues) { + // Enable the multi value experiment, which should enable the first choice. + SetExperimentEnabled(&prefs_, kFlags4, true); + { + CommandLine command_line(CommandLine::NO_PROGRAM); + ConvertFlagsToSwitches(&prefs_, &command_line); + EXPECT_TRUE(command_line.HasSwitch(kMultiSwitch1)); + EXPECT_FALSE(command_line.HasSwitch(kMultiSwitch2)); + } + + // Enable the 2nd choice of the multi-value, which should disable the first + // choice. + SetExperimentEnabled(&prefs_, std::string(kFlags4) + + std::string(testing::kMultiSeparator) + + base::IntToString(1), true); + { + CommandLine command_line(CommandLine::NO_PROGRAM); + ConvertFlagsToSwitches(&prefs_, &command_line); + EXPECT_FALSE(command_line.HasSwitch(kMultiSwitch1)); + EXPECT_TRUE(command_line.HasSwitch(kMultiSwitch2)); + } + + // Disable the multi-value experiment. + SetExperimentEnabled(&prefs_, kFlags4, false); + { + CommandLine command_line(CommandLine::NO_PROGRAM); + ConvertFlagsToSwitches(&prefs_, &command_line); + EXPECT_FALSE(command_line.HasSwitch(kMultiSwitch1)); + EXPECT_FALSE(command_line.HasSwitch(kMultiSwitch2)); + } +} + +// Makes sure there are no separators in any of the experiment names. +TEST_F(AboutFlagsTest, NoSeparators) { + testing::SetExperiments(NULL, 0); + size_t count; + const Experiment* experiments = testing::GetExperiments(&count); + for (size_t i = 0; i < count; ++i) { + std::string name = experiments->internal_name; + EXPECT_EQ(std::string::npos, name.find(testing::kMultiSeparator)) << i; + } } } // namespace about_flags diff --git a/chrome/browser/instant/instant_controller.cc b/chrome/browser/instant/instant_controller.cc index fcc55f9..8a71266 100644 --- a/chrome/browser/instant/instant_controller.cc +++ b/chrome/browser/instant/instant_controller.cc @@ -514,8 +514,10 @@ bool InstantController::GetType(Profile* profile, Type* type) { *type = VERBATIM_TYPE; return true; } - - // There is no switch for PREDICTIVE_NO_AUTO_COMPLETE_TYPE. + if (cl->HasSwitch(switches::kEnablePredictiveNoAutoCompleteInstant)) { + *type = PREDICTIVE_NO_AUTO_COMPLETE_TYPE; + return true; + } // Then prefs. PrefService* prefs = profile->GetPrefs(); diff --git a/chrome/browser/resources/flags.html b/chrome/browser/resources/flags.html index 9798c82..106d4a5 100644 --- a/chrome/browser/resources/flags.html +++ b/chrome/browser/resources/flags.html @@ -176,7 +176,15 @@ var flagsExperimentsDataFormat = { 'internal_name': 'Experiment ID string', 'name': 'Experiment Name', 'description': 'description', - 'enabled': true + 'enabled': true, + /* choices is only set if the experiment has multiple values */ + 'choices': [ + { + 'internal_name': 'Experiment ID string', + 'description': 'description', + 'selected': true + } + ] } ], 'needsRestart': false @@ -231,6 +239,17 @@ function handleEnableExperiment(node, enable) { requestFlagsExperimentsData(); } +/** + * Invoked when the selection of a multi-value choice is changed to the + * specified index. + */ +function handleSelectChoiceExperiment(node, index) { + // Tell the C++ FlagsDOMHandler to enable the selected choice. + chrome.send('enableFlagsExperiment', + [String(node.internal_name) + "@" + index, "true"]); + requestFlagsExperimentsData(); +} + // Get data and have it displayed upon loading. document.addEventListener('DOMContentLoaded', requestFlagsExperimentsData); @@ -282,6 +301,15 @@ document.addEventListener('DOMContentLoaded', requestFlagsExperimentsData); <div> <span dir="ltr" jsvalues=".innerHTML:description"> </div> + <div jsdisplay="choices && choices.length > 0"> + <select jsvalues=".internal_name:internal_name;.disabled:!enabled" + onchange="handleSelectChoiceExperiment(this, this.selectedIndex)"> + <option jsvalues=".selected:selected" + jsselect="choices" + jscontent="description">NAME + </option> + </select> + </div> </div> </div> <div class="experiment-actions"> diff --git a/chrome/common/chrome_switches.cc b/chrome/common/chrome_switches.cc index 7c7fb23..33cfe75 100644 --- a/chrome/common/chrome_switches.cc +++ b/chrome/common/chrome_switches.cc @@ -505,9 +505,13 @@ const char kEnableNaClDebug[] = "enable-nacl-debug"; // Enable Native Web Worker support. const char kEnableNativeWebWorkers[] = "enable-native-web-workers"; -// Is the predictive varition of instant enabled? +// Is InstantController::PREDICTIVE_TYPE enabled? const char kEnablePredictiveInstant[] = "enable-predictive-instant"; +// Is InstantController::PREDICTIVE_NO_AUTO_COMPLETE_TYPE enabled? +const char kEnablePredictiveNoAutoCompleteInstant[] = + "enable-predictive-no-auto-complete-instant"; + // This applies only when the process type is "service". Enables the // Chromoting Host Process within the service process. const char kEnableRemoting[] = "enable-remoting"; diff --git a/chrome/common/chrome_switches.h b/chrome/common/chrome_switches.h index 22b930b..26c79bf 100644 --- a/chrome/common/chrome_switches.h +++ b/chrome/common/chrome_switches.h @@ -154,6 +154,7 @@ extern const char kEnablePagePrerender[]; extern const char kEnableSyncNewAutofill[]; extern const char kEnablePreconnect[]; extern const char kEnablePredictiveInstant[]; +extern const char kEnablePredictiveNoAutoCompleteInstant[]; extern const char kEnablePreparsedJsCaching[]; extern const char kEnablePrintPreview[]; extern const char kEnableRemoting[]; |