OLD | NEW |
---|---|
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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/notification_promo.h" | 5 #include "chrome/browser/web_resource/notification_promo.h" |
6 | 6 |
7 #include <cmath> | 7 #include <cmath> |
8 #include <vector> | 8 #include <vector> |
9 | 9 |
10 #include "base/bind.h" | 10 #include "base/bind.h" |
11 #include "base/rand_util.h" | 11 #include "base/rand_util.h" |
12 #include "base/string_number_conversions.h" | 12 #include "base/string_number_conversions.h" |
13 #include "base/string_util.h" | 13 #include "base/string_util.h" |
14 #include "base/sys_info.h" | 14 #include "base/sys_info.h" |
15 #include "base/threading/thread_restrictions.h" | |
15 #include "base/time.h" | 16 #include "base/time.h" |
16 #include "base/values.h" | 17 #include "base/values.h" |
17 #include "chrome/browser/prefs/pref_service.h" | 18 #include "chrome/browser/prefs/pref_service.h" |
18 #include "chrome/browser/profiles/profile_impl.h" | 19 #include "chrome/browser/prefs/pref_service_simple.h" |
20 #include "chrome/browser/prefs/pref_service_syncable.h" | |
19 #include "chrome/browser/web_resource/promo_resource_service.h" | 21 #include "chrome/browser/web_resource/promo_resource_service.h" |
20 #include "chrome/common/chrome_version_info.h" | 22 #include "chrome/common/chrome_version_info.h" |
21 #include "chrome/common/net/url_util.h" | 23 #include "chrome/common/net/url_util.h" |
22 #include "chrome/common/pref_names.h" | 24 #include "chrome/common/pref_names.h" |
23 #include "content/public/browser/user_metrics.h" | 25 #include "content/public/browser/user_metrics.h" |
24 #include "googleurl/src/gurl.h" | 26 #include "googleurl/src/gurl.h" |
25 | 27 |
26 #if defined(OS_ANDROID) | 28 #if defined(OS_ANDROID) |
27 #include "base/command_line.h" | 29 #include "base/command_line.h" |
28 #include "chrome/common/chrome_switches.h" | 30 #include "chrome/common/chrome_switches.h" |
(...skipping 17 matching lines...) Expand all Loading... | |
46 const char kPrefPromoEnd[] = "end"; | 48 const char kPrefPromoEnd[] = "end"; |
47 const char kPrefPromoNumGroups[] = "num_groups"; | 49 const char kPrefPromoNumGroups[] = "num_groups"; |
48 const char kPrefPromoSegment[] = "segment"; | 50 const char kPrefPromoSegment[] = "segment"; |
49 const char kPrefPromoIncrement[] = "increment"; | 51 const char kPrefPromoIncrement[] = "increment"; |
50 const char kPrefPromoIncrementFrequency[] = "increment_frequency"; | 52 const char kPrefPromoIncrementFrequency[] = "increment_frequency"; |
51 const char kPrefPromoIncrementMax[] = "increment_max"; | 53 const char kPrefPromoIncrementMax[] = "increment_max"; |
52 const char kPrefPromoMaxViews[] = "max_views"; | 54 const char kPrefPromoMaxViews[] = "max_views"; |
53 const char kPrefPromoGroup[] = "group"; | 55 const char kPrefPromoGroup[] = "group"; |
54 const char kPrefPromoViews[] = "views"; | 56 const char kPrefPromoViews[] = "views"; |
55 const char kPrefPromoClosed[] = "closed"; | 57 const char kPrefPromoClosed[] = "closed"; |
56 const char kPrefPromoGPlusRequired[] = "gplus_required"; | |
57 | 58 |
58 // Returns a string suitable for the Promo Server URL 'osname' value. | 59 // Returns a string suitable for the Promo Server URL 'osname' value. |
59 std::string PlatformString() { | 60 std::string PlatformString() { |
60 #if defined(OS_WIN) | 61 #if defined(OS_WIN) |
61 return "win"; | 62 return "win"; |
62 #elif defined(OS_IOS) | 63 #elif defined(OS_IOS) |
63 // TODO(noyau): add iOS-specific implementation | 64 // TODO(noyau): add iOS-specific implementation |
64 const bool isTablet = false; | 65 const bool isTablet = false; |
65 return std::string("ios-") + (isTablet ? "tablet" : "phone"); | 66 return std::string("ios-") + (isTablet ? "tablet" : "phone"); |
66 #elif defined(OS_MACOSX) | 67 #elif defined(OS_MACOSX) |
(...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
182 } | 183 } |
183 | 184 |
184 void AppendQueryParameter(GURL* url, | 185 void AppendQueryParameter(GURL* url, |
185 const std::string& param, | 186 const std::string& param, |
186 const std::string& value) { | 187 const std::string& value) { |
187 *url = chrome_common_net::AppendQueryParameter(*url, param, value); | 188 *url = chrome_common_net::AppendQueryParameter(*url, param, value); |
188 } | 189 } |
189 | 190 |
190 } // namespace | 191 } // namespace |
191 | 192 |
192 NotificationPromo::NotificationPromo(Profile* profile) | 193 NotificationPromo::NotificationPromo(PrefServiceSimple* prefs) |
193 : profile_(profile), | 194 : prefs_(prefs), |
194 prefs_(profile_->GetPrefs()), | |
195 promo_type_(NO_PROMO), | 195 promo_type_(NO_PROMO), |
196 promo_payload_(new base::DictionaryValue()), | 196 promo_payload_(new base::DictionaryValue()), |
197 start_(0.0), | 197 start_(0.0), |
198 end_(0.0), | 198 end_(0.0), |
199 num_groups_(kDefaultGroupSize), | 199 num_groups_(kDefaultGroupSize), |
200 initial_segment_(0), | 200 initial_segment_(0), |
201 increment_(1), | 201 increment_(1), |
202 time_slice_(0), | 202 time_slice_(0), |
203 max_group_(0), | 203 max_group_(0), |
204 max_views_(0), | 204 max_views_(0), |
205 group_(0), | 205 group_(0), |
206 views_(0), | 206 views_(0), |
207 closed_(false), | 207 closed_(false), |
208 gplus_required_(false), | |
209 new_notification_(false) { | 208 new_notification_(false) { |
210 DCHECK(profile); | |
211 DCHECK(prefs_); | 209 DCHECK(prefs_); |
212 } | 210 } |
213 | 211 |
214 NotificationPromo::~NotificationPromo() {} | 212 NotificationPromo::~NotificationPromo() {} |
215 | 213 |
216 void NotificationPromo::InitFromJson(const DictionaryValue& json, | 214 void NotificationPromo::InitFromJson(const DictionaryValue& json, |
217 PromoType promo_type) { | 215 PromoType promo_type) { |
218 promo_type_ = promo_type; | 216 promo_type_ = promo_type; |
219 const ListValue* promo_list = NULL; | 217 const ListValue* promo_list = NULL; |
220 DVLOG(1) << "InitFromJson " << PromoTypeToString(promo_type_); | 218 DVLOG(1) << "InitFromJson " << PromoTypeToString(promo_type_); |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
264 << ", max_group_ = " << max_group_; | 262 << ", max_group_ = " << max_group_; |
265 } | 263 } |
266 | 264 |
267 // Strings. | 265 // Strings. |
268 const DictionaryValue* strings = NULL; | 266 const DictionaryValue* strings = NULL; |
269 promo->GetDictionary("strings", &strings); | 267 promo->GetDictionary("strings", &strings); |
270 | 268 |
271 // Payload. | 269 // Payload. |
272 const DictionaryValue* payload = NULL; | 270 const DictionaryValue* payload = NULL; |
273 if (promo->GetDictionary("payload", &payload)) { | 271 if (promo->GetDictionary("payload", &payload)) { |
274 payload->GetBoolean("gplus_required", &gplus_required_); | |
275 DVLOG(1) << "gplus_required_ = " << gplus_required_; | |
276 | |
277 base::Value* ppcopy = DeepCopyAndResolveStrings(payload, strings); | 272 base::Value* ppcopy = DeepCopyAndResolveStrings(payload, strings); |
278 DCHECK(ppcopy && ppcopy->IsType(base::Value::TYPE_DICTIONARY)); | 273 DCHECK(ppcopy && ppcopy->IsType(base::Value::TYPE_DICTIONARY)); |
279 promo_payload_.reset(static_cast<base::DictionaryValue*>(ppcopy)); | 274 promo_payload_.reset(static_cast<base::DictionaryValue*>(ppcopy)); |
280 } | 275 } |
281 | 276 |
282 if (!promo_payload_->GetString("promo_message_short", &promo_text_) && | 277 if (!promo_payload_->GetString("promo_message_short", &promo_text_) && |
283 strings) { | 278 strings) { |
284 // For compatibility with the legacy desktop version, | 279 // For compatibility with the legacy desktop version, |
285 // if no |payload.promo_message_short| is specified, | 280 // if no |payload.promo_message_short| is specified, |
286 // the first string in |strings| is used. | 281 // the first string in |strings| is used. |
287 DictionaryValue::Iterator iter(*strings); | 282 DictionaryValue::Iterator iter(*strings); |
288 iter.value().GetAsString(&promo_text_); | 283 iter.value().GetAsString(&promo_text_); |
289 } | 284 } |
290 DVLOG(1) << "promo_text_=" << promo_text_; | 285 DVLOG(1) << "promo_text_=" << promo_text_; |
291 | 286 |
292 promo->GetInteger("max_views", &max_views_); | 287 promo->GetInteger("max_views", &max_views_); |
293 DVLOG(1) << "max_views_ " << max_views_; | 288 DVLOG(1) << "max_views_ " << max_views_; |
294 | 289 |
295 CheckForNewNotification(); | 290 CheckForNewNotification(); |
296 } | 291 } |
297 | 292 |
298 void NotificationPromo::CheckForNewNotification() { | 293 void NotificationPromo::CheckForNewNotification() { |
299 NotificationPromo old_promo(profile_); | 294 NotificationPromo old_promo(prefs_); |
300 old_promo.InitFromPrefs(promo_type_); | 295 old_promo.InitFromPrefs(promo_type_); |
301 const double old_start = old_promo.start_; | 296 const double old_start = old_promo.start_; |
302 const double old_end = old_promo.end_; | 297 const double old_end = old_promo.end_; |
303 const std::string old_promo_text = old_promo.promo_text_; | 298 const std::string old_promo_text = old_promo.promo_text_; |
304 | 299 |
305 new_notification_ = | 300 new_notification_ = |
306 old_start != start_ || old_end != end_ || old_promo_text != promo_text_; | 301 old_start != start_ || old_end != end_ || old_promo_text != promo_text_; |
307 if (new_notification_) | 302 if (new_notification_) |
308 OnNewNotification(); | 303 OnNewNotification(); |
309 } | 304 } |
310 | 305 |
311 void NotificationPromo::OnNewNotification() { | 306 void NotificationPromo::OnNewNotification() { |
312 DVLOG(1) << "OnNewNotification"; | 307 DVLOG(1) << "OnNewNotification"; |
313 // Create a new promo group. | 308 // Create a new promo group. |
314 group_ = base::RandInt(0, num_groups_ - 1); | 309 group_ = base::RandInt(0, num_groups_ - 1); |
315 WritePrefs(); | 310 WritePrefs(); |
316 } | 311 } |
317 | 312 |
318 // static | 313 // static |
314 void NotificationPromo::RegisterPrefs(PrefServiceSimple* local_state) { | |
315 local_state->RegisterDictionaryPref(kPrefPromoObject, | |
316 new base::DictionaryValue); | |
Bernhard Bauer
2012/12/31 11:51:52
Nit: an empty dictionary is the default value for
Dan Beam
2013/01/02 04:36:35
OK, should I remove it from the below user pref re
Bernhard Bauer
2013/01/02 10:57:44
Please and thank you! :)
Dan Beam
2013/01/02 22:27:51
Done.
| |
317 } | |
318 | |
319 // static | |
319 void NotificationPromo::RegisterUserPrefs(PrefServiceSyncable* prefs) { | 320 void NotificationPromo::RegisterUserPrefs(PrefServiceSyncable* prefs) { |
321 // TODO(dbeam): Remove in M28 when we're reasonably sure all prefs are gone. | |
320 prefs->RegisterDictionaryPref(kPrefPromoObject, | 322 prefs->RegisterDictionaryPref(kPrefPromoObject, |
321 new base::DictionaryValue, | 323 new base::DictionaryValue, |
322 PrefServiceSyncable::UNSYNCABLE_PREF); | 324 PrefServiceSyncable::UNSYNCABLE_PREF); |
325 prefs->ClearPref(kPrefPromoObject); | |
323 } | 326 } |
324 | 327 |
325 void NotificationPromo::WritePrefs() { | 328 void NotificationPromo::WritePrefs() { |
326 base::DictionaryValue* ntp_promo = new base::DictionaryValue; | 329 base::DictionaryValue* ntp_promo = new base::DictionaryValue; |
327 ntp_promo->SetString(kPrefPromoText, promo_text_); | 330 ntp_promo->SetString(kPrefPromoText, promo_text_); |
328 ntp_promo->Set(kPrefPromoPayload, promo_payload_->DeepCopy()); | 331 ntp_promo->Set(kPrefPromoPayload, promo_payload_->DeepCopy()); |
329 ntp_promo->SetDouble(kPrefPromoStart, start_); | 332 ntp_promo->SetDouble(kPrefPromoStart, start_); |
330 ntp_promo->SetDouble(kPrefPromoEnd, end_); | 333 ntp_promo->SetDouble(kPrefPromoEnd, end_); |
331 | 334 |
332 ntp_promo->SetInteger(kPrefPromoNumGroups, num_groups_); | 335 ntp_promo->SetInteger(kPrefPromoNumGroups, num_groups_); |
333 ntp_promo->SetInteger(kPrefPromoSegment, initial_segment_); | 336 ntp_promo->SetInteger(kPrefPromoSegment, initial_segment_); |
334 ntp_promo->SetInteger(kPrefPromoIncrement, increment_); | 337 ntp_promo->SetInteger(kPrefPromoIncrement, increment_); |
335 ntp_promo->SetInteger(kPrefPromoIncrementFrequency, time_slice_); | 338 ntp_promo->SetInteger(kPrefPromoIncrementFrequency, time_slice_); |
336 ntp_promo->SetInteger(kPrefPromoIncrementMax, max_group_); | 339 ntp_promo->SetInteger(kPrefPromoIncrementMax, max_group_); |
337 | 340 |
338 ntp_promo->SetInteger(kPrefPromoMaxViews, max_views_); | 341 ntp_promo->SetInteger(kPrefPromoMaxViews, max_views_); |
339 | 342 |
340 ntp_promo->SetInteger(kPrefPromoGroup, group_); | 343 ntp_promo->SetInteger(kPrefPromoGroup, group_); |
341 ntp_promo->SetInteger(kPrefPromoViews, views_); | 344 ntp_promo->SetInteger(kPrefPromoViews, views_); |
342 ntp_promo->SetBoolean(kPrefPromoClosed, closed_); | 345 ntp_promo->SetBoolean(kPrefPromoClosed, closed_); |
343 | 346 |
344 ntp_promo->SetBoolean(kPrefPromoGPlusRequired, gplus_required_); | |
345 | |
346 base::ListValue* promo_list = new base::ListValue; | 347 base::ListValue* promo_list = new base::ListValue; |
347 promo_list->Set(0, ntp_promo); // Only support 1 promo for now. | 348 promo_list->Set(0, ntp_promo); // Only support 1 promo for now. |
348 | 349 |
349 base::DictionaryValue promo_dict; | 350 base::DictionaryValue promo_dict; |
350 promo_dict.MergeDictionary(prefs_->GetDictionary(kPrefPromoObject)); | 351 promo_dict.MergeDictionary(prefs_->GetDictionary(kPrefPromoObject)); |
351 promo_dict.Set(PromoTypeToString(promo_type_), promo_list); | 352 promo_dict.Set(PromoTypeToString(promo_type_), promo_list); |
352 prefs_->Set(kPrefPromoObject, promo_dict); | 353 prefs_->Set(kPrefPromoObject, promo_dict); |
353 DVLOG(1) << "WritePrefs " << promo_dict; | 354 DVLOG(1) << "WritePrefs " << promo_dict; |
354 } | 355 } |
355 | 356 |
(...skipping 26 matching lines...) Expand all Loading... | |
382 ntp_promo->GetInteger(kPrefPromoSegment, &initial_segment_); | 383 ntp_promo->GetInteger(kPrefPromoSegment, &initial_segment_); |
383 ntp_promo->GetInteger(kPrefPromoIncrement, &increment_); | 384 ntp_promo->GetInteger(kPrefPromoIncrement, &increment_); |
384 ntp_promo->GetInteger(kPrefPromoIncrementFrequency, &time_slice_); | 385 ntp_promo->GetInteger(kPrefPromoIncrementFrequency, &time_slice_); |
385 ntp_promo->GetInteger(kPrefPromoIncrementMax, &max_group_); | 386 ntp_promo->GetInteger(kPrefPromoIncrementMax, &max_group_); |
386 | 387 |
387 ntp_promo->GetInteger(kPrefPromoMaxViews, &max_views_); | 388 ntp_promo->GetInteger(kPrefPromoMaxViews, &max_views_); |
388 | 389 |
389 ntp_promo->GetInteger(kPrefPromoGroup, &group_); | 390 ntp_promo->GetInteger(kPrefPromoGroup, &group_); |
390 ntp_promo->GetInteger(kPrefPromoViews, &views_); | 391 ntp_promo->GetInteger(kPrefPromoViews, &views_); |
391 ntp_promo->GetBoolean(kPrefPromoClosed, &closed_); | 392 ntp_promo->GetBoolean(kPrefPromoClosed, &closed_); |
392 | |
393 ntp_promo->GetBoolean(kPrefPromoGPlusRequired, &gplus_required_); | |
394 } | 393 } |
395 | 394 |
396 bool NotificationPromo::CanShow() const { | 395 bool NotificationPromo::CanShow() const { |
397 return !closed_ && | 396 return !closed_ && |
398 !promo_text_.empty() && | 397 !promo_text_.empty() && |
399 !ExceedsMaxGroup() && | 398 !ExceedsMaxGroup() && |
400 !ExceedsMaxViews() && | 399 !ExceedsMaxViews() && |
401 base::Time::FromDoubleT(StartTimeForGroup()) < base::Time::Now() && | 400 base::Time::FromDoubleT(StartTimeForGroup()) < base::Time::Now() && |
402 base::Time::FromDoubleT(EndTime()) > base::Time::Now() && | 401 base::Time::FromDoubleT(EndTime()) > base::Time::Now(); |
403 IsGPlusRequired(); | |
404 } | 402 } |
405 | 403 |
406 // static | 404 // static |
407 void NotificationPromo::HandleClosed(Profile* profile, PromoType promo_type) { | 405 void NotificationPromo::HandleClosed(PrefServiceSimple* prefs, |
406 PromoType promo_type) { | |
408 content::RecordAction(UserMetricsAction("NTPPromoClosed")); | 407 content::RecordAction(UserMetricsAction("NTPPromoClosed")); |
409 NotificationPromo promo(profile); | 408 NotificationPromo promo(prefs); |
410 promo.InitFromPrefs(promo_type); | 409 promo.InitFromPrefs(promo_type); |
411 if (!promo.closed_) { | 410 if (!promo.closed_) { |
412 promo.closed_ = true; | 411 promo.closed_ = true; |
413 promo.WritePrefs(); | 412 promo.WritePrefs(); |
414 } | 413 } |
415 } | 414 } |
416 | 415 |
417 // static | 416 // static |
418 bool NotificationPromo::HandleViewed(Profile* profile, PromoType promo_type) { | 417 bool NotificationPromo::HandleViewed(PrefServiceSimple* prefs, |
418 PromoType promo_type) { | |
419 content::RecordAction(UserMetricsAction("NTPPromoShown")); | 419 content::RecordAction(UserMetricsAction("NTPPromoShown")); |
420 NotificationPromo promo(profile); | 420 NotificationPromo promo(prefs); |
421 promo.InitFromPrefs(promo_type); | 421 promo.InitFromPrefs(promo_type); |
422 ++promo.views_; | 422 ++promo.views_; |
423 promo.WritePrefs(); | 423 promo.WritePrefs(); |
424 return promo.ExceedsMaxViews(); | 424 return promo.ExceedsMaxViews(); |
425 } | 425 } |
426 | 426 |
427 bool NotificationPromo::ExceedsMaxGroup() const { | 427 bool NotificationPromo::ExceedsMaxGroup() const { |
428 return (max_group_ == 0) ? false : group_ >= max_group_; | 428 return (max_group_ == 0) ? false : group_ >= max_group_; |
429 } | 429 } |
430 | 430 |
431 bool NotificationPromo::ExceedsMaxViews() const { | 431 bool NotificationPromo::ExceedsMaxViews() const { |
432 return (max_views_ == 0) ? false : views_ >= max_views_; | 432 return (max_views_ == 0) ? false : views_ >= max_views_; |
433 } | 433 } |
434 | 434 |
435 bool NotificationPromo::IsGPlusRequired() const { | |
436 return !gplus_required_ || prefs_->GetBoolean(prefs::kIsGooglePlusUser); | |
437 } | |
438 | |
439 // static | 435 // static |
440 GURL NotificationPromo::PromoServerURL() { | 436 GURL NotificationPromo::PromoServerURL() { |
441 GURL url(promo_server_url); | 437 GURL url(promo_server_url); |
442 AppendQueryParameter(&url, "dist", ChannelString()); | 438 AppendQueryParameter(&url, "dist", ChannelString()); |
443 AppendQueryParameter(&url, "osname", PlatformString()); | 439 AppendQueryParameter(&url, "osname", PlatformString()); |
444 AppendQueryParameter(&url, "branding", chrome::VersionInfo().Version()); | 440 AppendQueryParameter(&url, "branding", chrome::VersionInfo().Version()); |
445 AppendQueryParameter(&url, "osver", base::SysInfo::OperatingSystemVersion()); | 441 AppendQueryParameter(&url, "osver", base::SysInfo::OperatingSystemVersion()); |
446 DVLOG(1) << "PromoServerURL=" << url.spec(); | 442 DVLOG(1) << "PromoServerURL=" << url.spec(); |
447 // Note that locale param is added by WebResourceService. | 443 // Note that locale param is added by WebResourceService. |
448 return url; | 444 return url; |
449 } | 445 } |
450 | 446 |
451 double NotificationPromo::StartTimeForGroup() const { | 447 double NotificationPromo::StartTimeForGroup() const { |
452 if (group_ < initial_segment_) | 448 if (group_ < initial_segment_) |
453 return start_; | 449 return start_; |
454 return start_ + | 450 return start_ + |
455 std::ceil(static_cast<float>(group_ - initial_segment_ + 1) / increment_) | 451 std::ceil(static_cast<float>(group_ - initial_segment_ + 1) / increment_) |
456 * time_slice_; | 452 * time_slice_; |
457 } | 453 } |
458 | 454 |
459 double NotificationPromo::EndTime() const { | 455 double NotificationPromo::EndTime() const { |
460 return end_; | 456 return end_; |
461 } | 457 } |
OLD | NEW |