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