Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(270)

Side by Side Diff: chrome/browser/web_resource/promo_resource_service.cc

Issue 6825052: Update the web store promo to be clearer and configurable at run-time. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Fix URL. Created 9 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/web_resource/promo_resource_service.h" 5 #include "chrome/browser/web_resource/promo_resource_service.h"
6 6
7 #include "base/string_number_conversions.h" 7 #include "base/string_number_conversions.h"
8 #include "base/threading/thread_restrictions.h" 8 #include "base/threading/thread_restrictions.h"
9 #include "base/time.h" 9 #include "base/time.h"
10 #include "base/values.h" 10 #include "base/values.h"
11 #include "chrome/browser/browser_process.h" 11 #include "chrome/browser/browser_process.h"
12 #include "chrome/browser/extensions/apps_promo.h"
12 #include "chrome/browser/platform_util.h" 13 #include "chrome/browser/platform_util.h"
13 #include "chrome/browser/prefs/pref_service.h" 14 #include "chrome/browser/prefs/pref_service.h"
14 #include "chrome/browser/profiles/profile.h" 15 #include "chrome/browser/profiles/profile.h"
15 #include "chrome/browser/sync/sync_ui_util.h" 16 #include "chrome/browser/sync/sync_ui_util.h"
16 #include "chrome/common/pref_names.h" 17 #include "chrome/common/pref_names.h"
17 #include "content/browser/browser_thread.h" 18 #include "content/browser/browser_thread.h"
18 #include "content/common/notification_service.h" 19 #include "content/common/notification_service.h"
19 #include "content/common/notification_type.h" 20 #include "content/common/notification_type.h"
21 #include "googleurl/src/gurl.h"
20 22
21 namespace { 23 namespace {
22 24
23 // Delay on first fetch so we don't interfere with startup. 25 // Delay on first fetch so we don't interfere with startup.
24 static const int kStartResourceFetchDelay = 5000; 26 static const int kStartResourceFetchDelay = 5000;
25 27
26 // Delay between calls to update the cache (48 hours). 28 // Delay between calls to update the cache (48 hours).
27 static const int kCacheUpdateDelay = 48 * 60 * 60 * 1000; 29 static const int kCacheUpdateDelay = 48 * 60 * 60 * 1000;
28 30
29 // Users are randomly assigned to one of kNTPPromoGroupSize buckets, in order 31 // Users are randomly assigned to one of kNTPPromoGroupSize buckets, in order
30 // to be able to roll out promos slowly, or display different promos to 32 // to be able to roll out promos slowly, or display different promos to
31 // different groups. 33 // different groups.
32 static const int kNTPPromoGroupSize = 16; 34 static const int kNTPPromoGroupSize = 16;
33 35
34 // Maximum number of hours for each time slice (4 weeks). 36 // Maximum number of hours for each time slice (4 weeks).
35 static const int kMaxTimeSliceHours = 24 * 7 * 4; 37 static const int kMaxTimeSliceHours = 24 * 7 * 4;
36 38
37 // Used to determine which build type should be shown a given promo. 39 // The version of the service (used to expire the cache when upgrading Chrome
38 enum BuildType { 40 // to versions with different types of promos).
39 NO_BUILD = 0, 41 static const int kPromoServiceVersion = 1;
40 DEV_BUILD = 1, 42
41 BETA_BUILD = 1 << 1, 43 // Properties used by the server.
42 STABLE_BUILD = 1 << 2, 44 static const char kAnswerIdProperty[] = "answer_id";
43 }; 45 static const char kWebStoreHeaderProperty[] = "answer1";
46 static const char kWebStoreButtonProperty[] = "answer2";
47 static const char kWebStoreLinkProperty[] = "answer3";
48 static const char kWebStoreExpireProperty[] = "answer4";
49 static const char kWebStoreBuildsProperty[] = "inproduct";
44 50
45 } // namespace 51 } // namespace
46 52
47 // Server for dynamically loaded NTP HTML elements. TODO(mirandac): append 53 // Server for dynamically loaded NTP HTML elements. TODO(mirandac): append
48 // locale for future usage, when we're serving localizable strings. 54 // locale for future usage, when we're serving localizable strings.
49 const char* PromoResourceService::kDefaultPromoResourceServer = 55 const char* PromoResourceService::kDefaultPromoResourceServer =
50 "https://www.google.com/support/chrome/bin/topic/1142433/inproduct?hl="; 56 "https://www.google.com/support/chrome/bin/topic/1142433/inproduct?hl=";
51 57
58 // static
59 void PromoResourceService::RegisterPrefs(PrefService* local_state) {
60 local_state->RegisterIntegerPref(prefs::kNTPPromoVersion, 0);
61 local_state->RegisterStringPref(prefs::kNTPPromoLocale, std::string());
62 }
63
64 // static
65 void PromoResourceService::RegisterUserPrefs(PrefService* prefs) {
66 prefs->RegisterDoublePref(prefs::kNTPCustomLogoStart, 0);
67 prefs->RegisterDoublePref(prefs::kNTPCustomLogoEnd, 0);
68 prefs->RegisterDoublePref(prefs::kNTPPromoStart, 0);
69 prefs->RegisterDoublePref(prefs::kNTPPromoEnd, 0);
70 prefs->RegisterStringPref(prefs::kNTPPromoLine, std::string());
71 prefs->RegisterBooleanPref(prefs::kNTPPromoClosed, false);
72 prefs->RegisterIntegerPref(prefs::kNTPPromoGroup, -1);
73 prefs->RegisterIntegerPref(prefs::kNTPPromoBuild,
74 CANARY_BUILD | DEV_BUILD | BETA_BUILD | STABLE_BUILD);
75 prefs->RegisterIntegerPref(prefs::kNTPPromoGroupTimeSlice, 0);
76 }
77
78 // static
79 bool PromoResourceService::IsBuildTargeted(const std::string& channel,
80 int builds_allowed) {
81 if (builds_allowed == NO_BUILD)
82 return false;
83 if (channel == "canary" || channel == "canary-m") {
84 return (CANARY_BUILD & builds_allowed) != 0;
85 } else if (channel == "dev" || channel == "dev-m") {
86 return (DEV_BUILD & builds_allowed) != 0;
87 } else if (channel == "beta" || channel == "beta-m") {
88 return (BETA_BUILD & builds_allowed) != 0;
89 } else if (channel == "" || channel == "m") {
90 return (STABLE_BUILD & builds_allowed) != 0;
91 } else {
92 return false;
93 }
94 }
95
52 PromoResourceService::PromoResourceService(Profile* profile) 96 PromoResourceService::PromoResourceService(Profile* profile)
53 : WebResourceService(profile, 97 : WebResourceService(profile,
54 profile->GetPrefs(), 98 profile->GetPrefs(),
55 PromoResourceService::kDefaultPromoResourceServer, 99 PromoResourceService::kDefaultPromoResourceServer,
56 true, // append locale to URL 100 true, // append locale to URL
57 NotificationType::PROMO_RESOURCE_STATE_CHANGED, 101 NotificationType::PROMO_RESOURCE_STATE_CHANGED,
58 prefs::kNTPPromoResourceCacheUpdate, 102 prefs::kNTPPromoResourceCacheUpdate,
59 kStartResourceFetchDelay, 103 kStartResourceFetchDelay,
60 kCacheUpdateDelay), 104 kCacheUpdateDelay),
61 web_resource_cache_(NULL) { 105 web_resource_cache_(NULL),
106 channel_(NULL) {
62 Init(); 107 Init();
63 } 108 }
64 109
65 PromoResourceService::~PromoResourceService() { } 110 PromoResourceService::~PromoResourceService() { }
66 111
67 void PromoResourceService::Init() { 112 void PromoResourceService::Init() {
68 prefs_->RegisterDoublePref(prefs::kNTPCustomLogoStart, 0); 113 ScheduleNotificationOnInit();
69 prefs_->RegisterDoublePref(prefs::kNTPCustomLogoEnd, 0); 114 }
70 prefs_->RegisterDoublePref(prefs::kNTPPromoStart, 0);
71 prefs_->RegisterDoublePref(prefs::kNTPPromoEnd, 0);
72 prefs_->RegisterStringPref(prefs::kNTPPromoLine, std::string());
73 prefs_->RegisterBooleanPref(prefs::kNTPPromoClosed, false);
74 prefs_->RegisterIntegerPref(prefs::kNTPPromoGroup, -1);
75 prefs_->RegisterIntegerPref(prefs::kNTPPromoBuild,
76 DEV_BUILD | BETA_BUILD | STABLE_BUILD);
77 prefs_->RegisterIntegerPref(prefs::kNTPPromoGroupTimeSlice, 0);
78 115
79 // If the promo start is in the future, set a notification task to invalidate 116 bool PromoResourceService::IsThisBuildTargeted(int builds_targeted) {
80 // the NTP cache at the time of the promo start. 117 std::string channel;
81 double promo_start = prefs_->GetDouble(prefs::kNTPPromoStart); 118 if (channel_ != NULL) {
82 double promo_end = prefs_->GetDouble(prefs::kNTPPromoEnd); 119 channel = channel_;
83 ScheduleNotification(promo_start, promo_end); 120 } else {
121 base::ThreadRestrictions::ScopedAllowIO allow_io;
122 channel = platform_util::GetVersionStringModifier();
Miranda Callahan 2011/04/13 14:29:29 did you want to cache the channel in channel_ here
jstritar 2011/04/13 19:52:27 Oh, yeah! Done.
123 }
124
125 return IsBuildTargeted(channel, builds_targeted);
84 } 126 }
85 127
86 void PromoResourceService::Unpack(const DictionaryValue& parsed_json) { 128 void PromoResourceService::Unpack(const DictionaryValue& parsed_json) {
87 UnpackLogoSignal(parsed_json); 129 UnpackLogoSignal(parsed_json);
88 UnpackPromoSignal(parsed_json); 130 UnpackPromoSignal(parsed_json);
131 UnpackWebStoreSignal(parsed_json);
89 } 132 }
90 133
91 void PromoResourceService::ScheduleNotification(double promo_start, 134 void PromoResourceService::ScheduleNotification(double promo_start,
92 double promo_end) { 135 double promo_end) {
93 if (promo_start > 0 && promo_end > 0) { 136 if (promo_start > 0 && promo_end > 0) {
94 int64 ms_until_start = 137 int64 ms_until_start =
95 static_cast<int64>((base::Time::FromDoubleT( 138 static_cast<int64>((base::Time::FromDoubleT(
96 promo_start) - base::Time::Now()).InMilliseconds()); 139 promo_start) - base::Time::Now()).InMilliseconds());
97 int64 ms_until_end = 140 int64 ms_until_end =
98 static_cast<int64>((base::Time::FromDoubleT( 141 static_cast<int64>((base::Time::FromDoubleT(
99 promo_end) - base::Time::Now()).InMilliseconds()); 142 promo_end) - base::Time::Now()).InMilliseconds());
100 if (ms_until_start > 0) 143 if (ms_until_start > 0)
101 PostNotification(ms_until_start); 144 PostNotification(ms_until_start);
102 if (ms_until_end > 0) { 145 if (ms_until_end > 0) {
103 PostNotification(ms_until_end); 146 PostNotification(ms_until_end);
104 if (ms_until_start <= 0) { 147 if (ms_until_start <= 0) {
105 // Notify immediately if time is between start and end. 148 // Notify immediately if time is between start and end.
106 PostNotification(0); 149 PostNotification(0);
107 } 150 }
108 } 151 }
109 } 152 }
110 } 153 }
111 154
155 void PromoResourceService::ScheduleNotificationOnInit() {
156 std::string locale = g_browser_process->GetApplicationLocale();
157 if ((GetPromoServiceVersion() != kPromoServiceVersion) ||
158 (GetPromoLocale() != locale)) {
159 // If the promo service has been upgraded or Chrome switched locales,
160 // refresh the promos.
161 PrefService* local_state = g_browser_process->local_state();
162 local_state->SetInteger(prefs::kNTPPromoVersion, kPromoServiceVersion);
163 local_state->SetString(prefs::kNTPPromoLocale, locale);
164 prefs_->ClearPref(prefs::kNTPPromoResourceCacheUpdate);
165 AppsPromo::ClearPromo();
166 PostNotification(0);
167 } else {
168 // If the promo start is in the future, set a notification task to
169 // invalidate the NTP cache at the time of the promo start.
170 double promo_start = prefs_->GetDouble(prefs::kNTPPromoStart);
171 double promo_end = prefs_->GetDouble(prefs::kNTPPromoEnd);
172 ScheduleNotification(promo_start, promo_end);
173 }
174 }
175
176 int PromoResourceService::GetPromoServiceVersion() {
177 PrefService* local_state = g_browser_process->local_state();
178 return local_state->GetInteger(prefs::kNTPPromoVersion);
179 }
180
181 std::string PromoResourceService::GetPromoLocale() {
182 PrefService* local_state = g_browser_process->local_state();
183 return local_state->GetString(prefs::kNTPPromoLocale);
184 }
185
112 void PromoResourceService::UnpackPromoSignal( 186 void PromoResourceService::UnpackPromoSignal(
113 const DictionaryValue& parsed_json) { 187 const DictionaryValue& parsed_json) {
114 DictionaryValue* topic_dict; 188 DictionaryValue* topic_dict;
115 ListValue* answer_list; 189 ListValue* answer_list;
116 double old_promo_start = 0; 190 double old_promo_start = 0;
117 double old_promo_end = 0; 191 double old_promo_end = 0;
118 double promo_start = 0; 192 double promo_start = 0;
119 double promo_end = 0; 193 double promo_end = 0;
120 194
121 // Check for preexisting start and end values. 195 // Check for preexisting start and end values.
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after
201 // Also reset the promo closed preference, to signal a new promo. 275 // Also reset the promo closed preference, to signal a new promo.
202 if (!(old_promo_start == promo_start) || 276 if (!(old_promo_start == promo_start) ||
203 !(old_promo_end == promo_end)) { 277 !(old_promo_end == promo_end)) {
204 prefs_->SetDouble(prefs::kNTPPromoStart, promo_start); 278 prefs_->SetDouble(prefs::kNTPPromoStart, promo_start);
205 prefs_->SetDouble(prefs::kNTPPromoEnd, promo_end); 279 prefs_->SetDouble(prefs::kNTPPromoEnd, promo_end);
206 prefs_->SetBoolean(prefs::kNTPPromoClosed, false); 280 prefs_->SetBoolean(prefs::kNTPPromoClosed, false);
207 ScheduleNotification(promo_start, promo_end); 281 ScheduleNotification(promo_start, promo_end);
208 } 282 }
209 } 283 }
210 284
285 void PromoResourceService::UnpackWebStoreSignal(
286 const DictionaryValue& parsed_json) {
287 DictionaryValue* topic_dict;
288 ListValue* answer_list;
289
290 bool signal_found = false;
291 std::string promo_id = "";
292 std::string promo_header = "";
293 std::string promo_button = "";
294 std::string promo_link = "";
295 std::string promo_expire = "";
296 std::string promo_builds = "";
297 int target_builds;
298
299 if (!parsed_json.GetDictionary("topic", &topic_dict) ||
300 !topic_dict->GetList("answers", &answer_list))
301 return;
302
303 for (ListValue::const_iterator tip_iter = answer_list->begin();
Miranda Callahan 2011/04/13 14:29:29 can you change the name from the atavistic "tip_it
jstritar 2011/04/13 19:52:27 Done. I changed them to "answer_iter". Another opt
304 tip_iter != answer_list->end(); ++tip_iter) {
305 if (!(*tip_iter)->IsType(Value::TYPE_DICTIONARY))
306 continue;
307 DictionaryValue* a_dic =
308 static_cast<DictionaryValue*>(*tip_iter);
309 std::string promo_signal;
310 if (!a_dic->GetString("name", &promo_signal) ||
311 promo_signal != "webstore_promo")
312 continue;
313
314 if (!a_dic->GetString(kAnswerIdProperty, &promo_id) ||
315 !a_dic->GetString(kWebStoreHeaderProperty, &promo_header) ||
316 !a_dic->GetString(kWebStoreButtonProperty, &promo_button) ||
317 !a_dic->GetString(kWebStoreLinkProperty, &promo_link) ||
318 !a_dic->GetString(kWebStoreExpireProperty, &promo_expire) ||
319 !a_dic->GetString(kWebStoreBuildsProperty, &promo_builds))
320 continue;
321
322 if (!base::StringToInt(promo_builds, &target_builds))
323 continue;
324
325 if (IsThisBuildTargeted(target_builds)) {
326 // Store the first web store promo that targets the current build.
327 AppsPromo::SetPromo(
328 promo_id, promo_header, promo_button, GURL(promo_link), promo_expire);
329 signal_found = true;
330 break;
331 }
332 }
333
334 if (!signal_found) {
335 // If no web store promos target this build, then clear all the prefs.
336 AppsPromo::ClearPromo();
337 }
338
339 NotificationService::current()->Notify(
340 NotificationType::WEB_STORE_PROMO_LOADED,
341 Source<PromoResourceService>(this),
342 NotificationService::NoDetails());
343
344 return;
345 }
346
211 void PromoResourceService::UnpackLogoSignal( 347 void PromoResourceService::UnpackLogoSignal(
212 const DictionaryValue& parsed_json) { 348 const DictionaryValue& parsed_json) {
213 DictionaryValue* topic_dict; 349 DictionaryValue* topic_dict;
214 ListValue* answer_list; 350 ListValue* answer_list;
215 double old_logo_start = 0; 351 double old_logo_start = 0;
216 double old_logo_end = 0; 352 double old_logo_end = 0;
217 double logo_start = 0; 353 double logo_start = 0;
218 double logo_end = 0; 354 double logo_end = 0;
219 355
220 // Check for preexisting start and end values. 356 // Check for preexisting start and end values.
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after
283 PrefService* prefs = profile->GetPrefs(); 419 PrefService* prefs = profile->GetPrefs();
284 if (prefs->HasPrefPath(prefs::kNTPPromoClosed)) 420 if (prefs->HasPrefPath(prefs::kNTPPromoClosed))
285 promo_closed = prefs->GetBoolean(prefs::kNTPPromoClosed); 421 promo_closed = prefs->GetBoolean(prefs::kNTPPromoClosed);
286 422
287 // Only show if not synced. 423 // Only show if not synced.
288 bool is_synced = 424 bool is_synced =
289 (profile->HasProfileSyncService() && 425 (profile->HasProfileSyncService() &&
290 sync_ui_util::GetStatus( 426 sync_ui_util::GetStatus(
291 profile->GetProfileSyncService()) == sync_ui_util::SYNCED); 427 profile->GetProfileSyncService()) == sync_ui_util::SYNCED);
292 428
293 // GetVersionStringModifier hits the registry. See http://crbug.com/70898.
294 base::ThreadRestrictions::ScopedAllowIO allow_io;
295 const std::string channel = platform_util::GetVersionStringModifier();
296 bool is_promo_build = false; 429 bool is_promo_build = false;
297 if (prefs->HasPrefPath(prefs::kNTPPromoBuild)) { 430 if (prefs->HasPrefPath(prefs::kNTPPromoBuild)) {
298 int builds_allowed = prefs->GetInteger(prefs::kNTPPromoBuild); 431 // GetVersionStringModifier hits the registry. See http://crbug.com/70898.
299 if (builds_allowed == NO_BUILD) 432 base::ThreadRestrictions::ScopedAllowIO allow_io;
300 return false; 433 const std::string channel = platform_util::GetVersionStringModifier();
301 if (channel == "dev" || channel == "dev-m") { 434 is_promo_build = PromoResourceService::IsBuildTargeted(
302 is_promo_build = (DEV_BUILD & builds_allowed) != 0; 435 channel, prefs->GetInteger(prefs::kNTPPromoBuild));
303 } else if (channel == "beta" || channel == "beta-m") {
304 is_promo_build = (BETA_BUILD & builds_allowed) != 0;
305 } else if (channel == "" || channel == "m") {
306 is_promo_build = (STABLE_BUILD & builds_allowed) != 0;
307 } else {
308 is_promo_build = false;
309 }
310 } 436 }
311 437
312 return !promo_closed && !is_synced && is_promo_build; 438 return !promo_closed && !is_synced && is_promo_build;
313 } 439 }
314 440
315 } // namespace PromoResourceServiceUtil 441 } // namespace PromoResourceServiceUtil
316
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698