summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authormirandac@chromium.org <mirandac@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-01-24 20:10:13 +0000
committermirandac@chromium.org <mirandac@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-01-24 20:10:13 +0000
commit47db9a95e12b8ab2ed14f33bcca1f8f2a40ea6d4 (patch)
tree8f4bc0ade113dbde98cf44caa0f7d7a9d147ffca
parent1503de36be46c5d273254bc7023b440f291e4be1 (diff)
downloadchromium_src-47db9a95e12b8ab2ed14f33bcca1f8f2a40ea6d4.zip
chromium_src-47db9a95e12b8ab2ed14f33bcca1f8f2a40ea6d4.tar.gz
chromium_src-47db9a95e12b8ab2ed14f33bcca1f8f2a40ea6d4.tar.bz2
Add possibility to divide chrome users into groups of equal size, and change promo code to reflect sync promo.
BUG=68671, 68672 TEST=none Review URL: http://codereview.chromium.org/6313009 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@72374 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/browser/dom_ui/ntp_resource_cache.cc2
-rw-r--r--chrome/browser/resources/new_new_tab.html5
-rw-r--r--chrome/browser/resources/new_new_tab.js36
-rw-r--r--chrome/browser/sessions/session_service.h2
-rw-r--r--chrome/browser/web_resource/web_resource_service.cc105
-rw-r--r--chrome/browser/web_resource/web_resource_service.h22
-rw-r--r--chrome/browser/web_resource/web_resource_service_unittest.cc68
-rw-r--r--chrome/common/pref_names.cc23
-rw-r--r--chrome/common/pref_names.h3
9 files changed, 206 insertions, 60 deletions
diff --git a/chrome/browser/dom_ui/ntp_resource_cache.cc b/chrome/browser/dom_ui/ntp_resource_cache.cc
index b82cf3c..b57fb98 100644
--- a/chrome/browser/dom_ui/ntp_resource_cache.cc
+++ b/chrome/browser/dom_ui/ntp_resource_cache.cc
@@ -337,6 +337,8 @@ void NTPResourceCache::CreateNewTabHTML() {
l10n_util::GetStringUTF16(IDS_APPS_PROMO_TEXT_1));
localized_strings.SetString("appspromotext2",
l10n_util::GetStringUTF16(IDS_APPS_PROMO_TEXT_2));
+ localized_strings.SetString("syncpromotext",
+ l10n_util::GetStringUTF16(IDS_SYNC_START_SYNC_BUTTON_LABEL));
#if defined(OS_CHROMEOS)
localized_strings.SetString("expandMenu",
l10n_util::GetStringUTF16(IDS_NEW_TAB_CLOSE_MENU_EXPAND));
diff --git a/chrome/browser/resources/new_new_tab.html b/chrome/browser/resources/new_new_tab.html
index b0f8ae9..ded221f 100644
--- a/chrome/browser/resources/new_new_tab.html
+++ b/chrome/browser/resources/new_new_tab.html
@@ -136,7 +136,10 @@ if ('mode' in hashParams) {
<div id="notification-container">
<div id="notification">
<span>&nbsp;</span>
- <span class="link"><span class="link-color"></span></span>
+ <span class="link"><span class="link-color" id="action-link"></span>
+ </span>
+ <span class="link"><span class="link-color" id="close-link"></span>
+ </span>
</div>
</div>
diff --git a/chrome/browser/resources/new_new_tab.js b/chrome/browser/resources/new_new_tab.js
index fdc1c61..c6520c0 100644
--- a/chrome/browser/resources/new_new_tab.js
+++ b/chrome/browser/resources/new_new_tab.js
@@ -807,7 +807,7 @@ function syncMessageChanged(newMessage) {
}
/**
- * Invoked when the link in the sync status section is clicked.
+ * Invoked when the link in the sync promo or sync status section is clicked.
*/
function syncSectionLinkClicked(e) {
chrome.send('SyncLinkClicked');
@@ -935,9 +935,11 @@ var notificationTimeout;
* @param {function=} opt_f Function to call when the user clicks the action
* link.
* @param {number=} opt_delay The time in milliseconds before hiding the
- * i notification.
+ * notification.
+ * @param {boolean=} close If true, show a close link next to the notification.
*/
-function showNotification(message, actionText, opt_f, opt_delay) {
+function showNotification(message, actionText, opt_f, opt_delay, opt_close) {
+// TODO(arv): Create a notification component.
var notificationElement = $('notification');
var f = opt_f || function() {};
var delay = opt_delay || 10000;
@@ -957,12 +959,26 @@ function showNotification(message, actionText, opt_f, opt_delay) {
hideNotification();
}
+ function closeNotification() {
+ chrome.send('closePromo');
+ hideNotification();
+ }
+
// Remove classList entries from previous notifications.
notification.classList.remove('first-run');
notification.classList.remove('promo');
var messageContainer = notificationElement.firstElementChild;
- var actionLink = notificationElement.querySelector('.link-color');
+ var actionLink = notificationElement.querySelector('#action-link');
+
+ if (opt_close) {
+ var closeLink = notificationElement.querySelector('#close-link');
+ closeLink.textContent =
+ localStrings.getString('closefirstrunnotification');
+ closeLink.onclick = closeNotification;
+ closeLink.onkeydown = handleIfEnterKey(closeNotification);
+ closeLink.tabIndex = 1;
+ }
if (typeof message == 'string') {
messageContainer.textContent = message;
@@ -993,14 +1009,17 @@ function hideNotification() {
var notificationElement = $('notification');
notificationElement.classList.remove('show');
document.body.classList.remove('notification-shown');
- var actionLink = notificationElement.querySelector('.link-color');
+ var actionLink = notificationElement.querySelector('#actionlink');
+ var closeLink = notificationElement.querySelector('#closelink');
// Prevent tabbing to the hidden link.
actionLink.tabIndex = -1;
+ closeLink.tabIndex = -1;
// Setting tabIndex to -1 only prevents future tabbing to it. If, however, the
// user switches window or a tab and then moves back to this tab the element
// may gain focus. We therefore make sure that we blur the element so that the
// element focus is not restored when coming back to this window.
actionLink.blur();
+ closeLink.blur();
}
function showFirstRunNotification() {
@@ -1013,9 +1032,10 @@ function showFirstRunNotification() {
function showPromoNotification() {
showNotification(parseHtmlSubset(localStrings.getString('serverpromo')),
- localStrings.getString('closefirstrunnotification'),
- function () { chrome.send('closePromo'); },
- 60000);
+ localStrings.getString('syncpromotext'),
+ function () { chrome.send('SyncLinkClicked'); },
+ 60000,
+ true);
var notificationElement = $('notification');
notification.classList.add('promo');
}
diff --git a/chrome/browser/sessions/session_service.h b/chrome/browser/sessions/session_service.h
index f17b77a..df97a78 100644
--- a/chrome/browser/sessions/session_service.h
+++ b/chrome/browser/sessions/session_service.h
@@ -444,7 +444,7 @@ class SessionService : public BaseSessionService,
// current/previous session.
bool move_on_new_browser_;
- // Used for reporting frequency of session alteriing operations.
+ // Used for reporting frequency of session altering operations.
base::TimeTicks last_updated_tab_closed_time_;
base::TimeTicks last_updated_nav_list_pruned_time_;
base::TimeTicks last_updated_nav_entry_commit_time_;
diff --git a/chrome/browser/web_resource/web_resource_service.cc b/chrome/browser/web_resource/web_resource_service.cc
index 35f4aea..f7984a7 100644
--- a/chrome/browser/web_resource/web_resource_service.cc
+++ b/chrome/browser/web_resource/web_resource_service.cc
@@ -4,6 +4,8 @@
#include "chrome/browser/web_resource/web_resource_service.h"
+#include <string>
+
#include "base/command_line.h"
#include "base/file_path.h"
#include "base/string_util.h"
@@ -14,6 +16,7 @@
#include "chrome/browser/browser_process.h"
#include "chrome/browser/browser_thread.h"
#include "chrome/browser/extensions/extension_service.h"
+#include "chrome/browser/platform_util.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/sync/sync_ui_util.h"
#include "chrome/common/chrome_switches.h"
@@ -34,6 +37,21 @@ static const int kStartResourceFetchDelay = 5000;
// Delay between calls to update the cache (48 hours).
static const int kCacheUpdateDelay = 48 * 60 * 60 * 1000;
+// Users are randomly assigned to one of kNTPPromoGroupSize buckets, in order
+// to be able to roll out promos slowly, or display different promos to
+// different groups.
+static const int kNTPPromoGroupSize = 16;
+
+// Maximum number of hours for each time slice (4 weeks).
+static const int kMaxTimeSliceHours = 24 * 7 * 4;
+
+// Used to determine which build type should be shown a given promo.
+enum BuildType {
+ DEV_BUILD = 1,
+ BETA_BUILD = 1 << 1,
+ STABLE_BUILD = 1 << 2,
+};
+
} // namespace
const char* WebResourceService::kCurrentTipPrefName = "current_tip";
@@ -203,7 +221,8 @@ class WebResourceService::UnpackerClient
// Server for dynamically loaded NTP HTML elements. TODO(mirandac): append
// locale for future usage, when we're serving localizable strings.
const char* WebResourceService::kDefaultWebResourceServer =
- "https://www.google.com/support/chrome/bin/topic/30248/inproduct";
+// "https://www.google.com/support/chrome/bin/topic/30248/inproduct";
+ "http://www.corp.google.com/~mirandac/testprefs.json";
WebResourceService::WebResourceService(Profile* profile)
: prefs_(profile->GetPrefs()),
@@ -227,6 +246,10 @@ void WebResourceService::Init() {
prefs_->RegisterRealPref(prefs::kNTPPromoEnd, 0);
prefs_->RegisterStringPref(prefs::kNTPPromoLine, std::string());
prefs_->RegisterBooleanPref(prefs::kNTPPromoClosed, false);
+ prefs_->RegisterIntegerPref(prefs::kNTPPromoGroup, -1);
+ prefs_->RegisterIntegerPref(prefs::kNTPPromoBuild,
+ DEV_BUILD | BETA_BUILD | STABLE_BUILD);
+ prefs_->RegisterIntegerPref(prefs::kNTPPromoGroupTimeSlice, 0);
// If the promo start is in the future, set a notification task to invalidate
// the NTP cache at the time of the promo start.
@@ -242,8 +265,7 @@ void WebResourceService::EndFetch() {
void WebResourceService::OnWebResourceUnpacked(
const DictionaryValue& parsed_json) {
UnpackLogoSignal(parsed_json);
- if (WebResourceServiceUtil::CanShowPromo(profile_))
- UnpackPromoSignal(parsed_json);
+ UnpackPromoSignal(parsed_json);
EndFetch();
}
@@ -377,6 +399,9 @@ void WebResourceService::UnpackPromoSignal(const DictionaryValue& parsed_json) {
std::string promo_start_string = "";
std::string promo_end_string = "";
std::string promo_string = "";
+ std::string promo_build = "";
+ int promo_build_type;
+ int time_slice_hrs;
for (ListValue::const_iterator tip_iter = answer_list->begin();
tip_iter != answer_list->end(); ++tip_iter) {
if (!(*tip_iter)->IsType(Value::TYPE_DICTIONARY))
@@ -386,9 +411,33 @@ void WebResourceService::UnpackPromoSignal(const DictionaryValue& parsed_json) {
std::string promo_signal;
if (a_dic->GetString("name", &promo_signal)) {
if (promo_signal == "promo_start") {
+ a_dic->GetString("question", &promo_build);
+ size_t split = promo_build.find(":");
+ if (split != std::string::npos &&
+ base::StringToInt(promo_build.substr(0, split),
+ &promo_build_type) &&
+ base::StringToInt(promo_build.substr(split+1),
+ &time_slice_hrs) &&
+ promo_build_type >= 0 &&
+ promo_build_type <= (DEV_BUILD | BETA_BUILD | STABLE_BUILD) &&
+ time_slice_hrs >= 0 &&
+ time_slice_hrs <= kMaxTimeSliceHours) {
+ prefs_->SetInteger(prefs::kNTPPromoBuild, promo_build_type);
+ prefs_->SetInteger(prefs::kNTPPromoGroupTimeSlice,
+ time_slice_hrs);
+ } else {
+ // If no time data or bad time data are set, show promo on all
+ // builds with no time slicing.
+ prefs_->SetInteger(prefs::kNTPPromoBuild,
+ DEV_BUILD | BETA_BUILD | STABLE_BUILD);
+ prefs_->SetInteger(prefs::kNTPPromoGroupTimeSlice, 0);
+ }
a_dic->GetString("inproduct", &promo_start_string);
a_dic->GetString("tooltip", &promo_string);
prefs_->SetString(prefs::kNTPPromoLine, promo_string);
+ srand(static_cast<uint32>(time(NULL)));
+ prefs_->SetInteger(prefs::kNTPPromoGroup,
+ rand() % kNTPPromoGroupSize);
} else if (promo_signal == "promo_end") {
a_dic->GetString("inproduct", &promo_end_string);
}
@@ -404,7 +453,11 @@ void WebResourceService::UnpackPromoSignal(const DictionaryValue& parsed_json) {
ASCIIToWide(promo_start_string).c_str(), &start_time) &&
base::Time::FromString(
ASCIIToWide(promo_end_string).c_str(), &end_time)) {
- promo_start = start_time.ToDoubleT();
+ // Add group time slice, adjusted from hours to seconds.
+ promo_start = start_time.ToDoubleT() +
+ (prefs_->FindPreference(prefs::kNTPPromoGroup) ?
+ prefs_->GetInteger(prefs::kNTPPromoGroup) *
+ time_slice_hrs * 60 * 60 : 0);
promo_end = end_time.ToDoubleT();
}
}
@@ -415,10 +468,12 @@ void WebResourceService::UnpackPromoSignal(const DictionaryValue& parsed_json) {
// notification, so that the logo on the NTP is updated. This check is
// outside the reading of the web resource data, because the absence of
// dates counts as a triggering change if there were dates before.
+ // Also reset the promo closed preference, to signal a new promo.
if (!(old_promo_start == promo_start) ||
!(old_promo_end == promo_end)) {
prefs_->SetReal(prefs::kNTPPromoStart, promo_start);
prefs_->SetReal(prefs::kNTPPromoEnd, promo_end);
+ prefs_->SetBoolean(prefs::kNTPPromoClosed, false);
ScheduleNotification(promo_start, promo_end);
}
}
@@ -498,32 +553,28 @@ bool CanShowPromo(Profile* profile) {
if (prefs->HasPrefPath(prefs::kNTPPromoClosed))
promo_closed = prefs->GetBoolean(prefs::kNTPPromoClosed);
- bool has_extensions = false;
- ExtensionService* extensions_service = profile->GetExtensionService();
- if (extensions_service) {
- const ExtensionList* extensions = extensions_service->extensions();
- for (ExtensionList::const_iterator iter = extensions->begin();
- iter != extensions->end();
- ++iter) {
- if ((*iter)->location() == Extension::INTERNAL) {
- has_extensions = true;
- break;
- }
- }
- }
-
- // Note that HasProfileSyncService() will be false for ChromeOS, so
- // promo_options will only be true if the user has an extension installed.
- // See http://crosbug/10209
- bool promo_options =
+ // Only show if not synced.
+ bool is_synced =
(profile->HasProfileSyncService() &&
sync_ui_util::GetStatus(
- profile->GetProfileSyncService()) == sync_ui_util::SYNCED) ||
- has_extensions;
+ profile->GetProfileSyncService()) == sync_ui_util::SYNCED);
+
+ const std::string channel = platform_util::GetVersionStringModifier();
+ bool is_promo_build = false;
+ if (prefs->HasPrefPath(prefs::kNTPPromoBuild)) {
+ int builds_allowed = prefs->GetInteger(prefs::kNTPPromoBuild);
+ if (channel == "dev") {
+ is_promo_build = (DEV_BUILD & builds_allowed) != 0;
+ } else if (channel == "beta") {
+ is_promo_build = (BETA_BUILD & builds_allowed) != 0;
+ } else if (channel == "stable") {
+ is_promo_build = (STABLE_BUILD & builds_allowed) != 0;
+ } else {
+ is_promo_build = true;
+ }
+ }
- return !promo_closed &&
- promo_options &&
- g_browser_process->GetApplicationLocale() == "en-US";
+ return !promo_closed && !is_synced && is_promo_build;
}
} // namespace WebResourceService
diff --git a/chrome/browser/web_resource/web_resource_service.h b/chrome/browser/web_resource/web_resource_service.h
index 70c8000..2373757 100644
--- a/chrome/browser/web_resource/web_resource_service.h
+++ b/chrome/browser/web_resource/web_resource_service.h
@@ -23,6 +23,14 @@ bool CanShowPromo(Profile* profile);
} // namespace WebResourceService
+// A WebResourceService fetches data from a web resource server to be used to
+// dynamically change the appearance of the New Tab Page. For example, it has
+// been used to fetch "tips" to be displayed on the NTP, or to display
+// promotional messages to certain groups of Chrome users.
+//
+// TODO(mirandac): Arrange for a server to be set up specifically for promo
+// messages, which have until now been piggybacked onto the old tips server
+// structure. (see http://crbug.com/70634 for details.)
class WebResourceService
: public UtilityProcessHost::Client {
public:
@@ -65,7 +73,7 @@ class WebResourceService
// {
// "answer_id": "1067976",
// "name": "promo_start",
- // "question": "",
+ // "question": "1:24",
// "tooltip":
// "Click \u003ca href=http://www.google.com\u003ehere\u003c/a\u003e!",
// "inproduct": "10/8/09 12:00",
@@ -84,6 +92,18 @@ class WebResourceService
// }
// }
//
+ // Because the promo signal data is piggybacked onto the tip server, the
+ // values don't exactly correspond with the field names:
+ //
+ // For "promo_start" or "promo_end", the date to start or stop showing the
+ // promotional line is given by the "inproduct" line.
+ // For "promo_start", the promotional line itself is given in the "tooltip"
+ // field. The "question" field gives the type of builds that should be shown
+ // this promo (see the BuildType enum in web_resource_service.cc) and the
+ // number of hours that each promo group should see it, separated by ":".
+ // For example, "7:24" would indicate that all builds should see the promo,
+ // and each group should see it for 24 hours.
+ //
// Public for unit testing.
void UnpackPromoSignal(const DictionaryValue& parsed_json);
diff --git a/chrome/browser/web_resource/web_resource_service_unittest.cc b/chrome/browser/web_resource/web_resource_service_unittest.cc
index 2211bb4..4127a6e 100644
--- a/chrome/browser/web_resource/web_resource_service_unittest.cc
+++ b/chrome/browser/web_resource/web_resource_service_unittest.cc
@@ -14,6 +14,17 @@
typedef testing::Test WebResourceServiceTest;
+namespace {
+
+// From web_resource_service.cc
+enum BuildType {
+ DEV_BUILD = 1,
+ BETA_BUILD = 1 << 1,
+ STABLE_BUILD = 1 << 2,
+};
+
+} // namespace
+
// Verifies that custom dates read from a web resource server are written to
// the preferences file.
TEST_F(WebResourceServiceTest, UnpackLogoSignal) {
@@ -42,12 +53,15 @@ TEST_F(WebResourceServiceTest, UnpackLogoSignal) {
// Check that prefs are set correctly.
web_resource_service->UnpackLogoSignal(*(test_json.get()));
+ PrefService* prefs = profile.GetPrefs();
+ ASSERT_TRUE(prefs != NULL);
+
double logo_start =
- profile.GetPrefs()->GetReal(prefs::kNTPCustomLogoStart);
- ASSERT_EQ(logo_start, 1264899600); // unix epoch for Jan 31 2010 0100 GMT.
+ prefs->GetReal(prefs::kNTPCustomLogoStart);
+ EXPECT_EQ(logo_start, 1264899600); // unix epoch for Jan 31 2010 0100 GMT.
double logo_end =
- profile.GetPrefs()->GetReal(prefs::kNTPCustomLogoEnd);
- ASSERT_EQ(logo_end, 1327971600); // unix epoch for Jan 31 2012 0100 GMT.
+ prefs->GetReal(prefs::kNTPCustomLogoEnd);
+ EXPECT_EQ(logo_end, 1327971600); // unix epoch for Jan 31 2012 0100 GMT.
// Change the start only and recheck.
json = "{ "
@@ -70,8 +84,9 @@ TEST_F(WebResourceServiceTest, UnpackLogoSignal) {
// Check that prefs are set correctly.
web_resource_service->UnpackLogoSignal(*(test_json.get()));
- logo_start = profile.GetPrefs()->GetReal(prefs::kNTPCustomLogoStart);
- ASSERT_EQ(logo_start, 1267365600); // date changes to Feb 28 2010 1400 GMT.
+
+ logo_start = prefs->GetReal(prefs::kNTPCustomLogoStart);
+ EXPECT_EQ(logo_start, 1267365600); // date changes to Feb 28 2010 1400 GMT.
// If no date is included in the prefs, reset custom logo dates to 0.
json = "{ "
@@ -88,10 +103,10 @@ TEST_F(WebResourceServiceTest, UnpackLogoSignal) {
// Check that prefs are set correctly.
web_resource_service->UnpackLogoSignal(*(test_json.get()));
- logo_start = profile.GetPrefs()->GetReal(prefs::kNTPCustomLogoStart);
- ASSERT_EQ(logo_start, 0); // date value reset to 0;
- logo_end = profile.GetPrefs()->GetReal(prefs::kNTPCustomLogoEnd);
- ASSERT_EQ(logo_end, 0); // date value reset to 0;
+ logo_start = prefs->GetReal(prefs::kNTPCustomLogoStart);
+ EXPECT_EQ(logo_start, 0); // date value reset to 0;
+ logo_end = prefs->GetReal(prefs::kNTPCustomLogoEnd);
+ EXPECT_EQ(logo_end, 0); // date value reset to 0;
}
TEST_F(WebResourceServiceTest, UnpackPromoSignal) {
@@ -107,6 +122,7 @@ TEST_F(WebResourceServiceTest, UnpackPromoSignal) {
" \"answers\": ["
" {"
" \"name\": \"promo_start\","
+ " \"question\": \"3:2\","
" \"tooltip\": \"Eat more pie!\","
" \"inproduct\": \"31/01/10 01:00 GMT\""
" },"
@@ -125,13 +141,33 @@ TEST_F(WebResourceServiceTest, UnpackPromoSignal) {
// Check that prefs are set correctly.
web_resource_service->UnpackPromoSignal(*(test_json.get()));
+ PrefService* prefs = profile.GetPrefs();
+ ASSERT_TRUE(prefs != NULL);
+
+ std::string promo_line = prefs->GetString(prefs::kNTPPromoLine);
+ EXPECT_EQ(promo_line, "Eat more pie!");
+
+ int promo_group = prefs->GetInteger(prefs::kNTPPromoGroup);
+ EXPECT_GE(promo_group, 0);
+ EXPECT_LT(promo_group, 16);
+
+ int promo_build_type = prefs->GetInteger(prefs::kNTPPromoBuild);
+ EXPECT_EQ(promo_build_type & DEV_BUILD, DEV_BUILD);
+ EXPECT_EQ(promo_build_type & BETA_BUILD, BETA_BUILD);
+ EXPECT_EQ(promo_build_type & STABLE_BUILD, 0);
+
+ int promo_time_slice = prefs->GetInteger(prefs::kNTPPromoGroupTimeSlice);
+ EXPECT_EQ(promo_time_slice, 2);
+
double promo_start =
- profile.GetPrefs()->GetReal(prefs::kNTPPromoStart);
- ASSERT_EQ(promo_start, 1264899600); // unix epoch for Jan 31 2010 0100 GMT.
+ prefs->GetReal(prefs::kNTPPromoStart);
+ int64 actual_start = 1264899600 + // unix epoch for Jan 31 2010 0100 GMT.
+ promo_group * 2 * 60 * 60;
+ EXPECT_EQ(promo_start, actual_start);
+
double promo_end =
- profile.GetPrefs()->GetReal(prefs::kNTPPromoEnd);
- ASSERT_EQ(promo_end, 1327971600); // unix epoch for Jan 31 2012 0100 GMT.
- std::string promo_line = profile.GetPrefs()->GetString(prefs::kNTPPromoLine);
- ASSERT_EQ(promo_line, "Eat more pie!");
+ prefs->GetReal(prefs::kNTPPromoEnd);
+ EXPECT_EQ(promo_end, 1327971600); // unix epoch for Jan 31 2012 0100 GMT.
}
+
diff --git a/chrome/common/pref_names.cc b/chrome/common/pref_names.cc
index d53f112..d52d503 100644
--- a/chrome/common/pref_names.cc
+++ b/chrome/common/pref_names.cc
@@ -1022,16 +1022,27 @@ const char kNTPPrefVersion[] = "ntp.pref_version";
const char kNTPCustomLogoStart[] = "ntp.alt_logo_start";
const char kNTPCustomLogoEnd[] = "ntp.alt_logo_end";
-// Dates between which the NTP should show a promotional line downloaded
-// from the promo server.
-const char kNTPPromoStart[] = "ntp.promo_start";
-const char kNTPPromoEnd[] = "ntp.promo_end";
+// Whether promo should be shown to Dev builds, Beta and Dev, or all builds.
+const char kNTPPromoBuild[] = "ntp.promo_build";
+
+// True if user has explicitly closed the promo line.
+const char kNTPPromoClosed[] = "ntp.promo_closed";
+
+// Users are randomly divided into 16 groups in order to slowly roll out
+// special promos.
+const char kNTPPromoGroup[] = "ntp.promo_group";
+
+// Amount of time each promo group should be shown a promo that is being slowly
+// rolled out, in hours.
+const char kNTPPromoGroupTimeSlice[] = "ntp.promo_group_timeslice";
// Promo line from server.
const char kNTPPromoLine[] = "ntp.promo_line";
-// True if user has explicitly closed the promo line.
-const char kNTPPromoClosed[] = "ntp.promo_closed";
+// Dates between which the NTP should show a promotional line downloaded
+// from the promo server.
+const char kNTPPromoStart[] = "ntp.promo_start";
+const char kNTPPromoEnd[] = "ntp.promo_end";
const char kDevToolsDisabled[] = "devtools.disabled";
diff --git a/chrome/common/pref_names.h b/chrome/common/pref_names.h
index e1fab64..327a49a 100644
--- a/chrome/common/pref_names.h
+++ b/chrome/common/pref_names.h
@@ -369,6 +369,9 @@ extern const char kNTPPromoStart[];
extern const char kNTPPromoEnd[];
extern const char kNTPPromoLine[];
extern const char kNTPPromoClosed[];
+extern const char kNTPPromoGroup[];
+extern const char kNTPPromoGroupTimeSlice[];
+extern const char kNTPPromoBuild[];
extern const char kDevToolsDisabled[];
extern const char kDevToolsOpenDocked[];