Chromium Code Reviews| Index: chrome/browser/web_resource/promo_notification.cc |
| =================================================================== |
| --- chrome/browser/web_resource/promo_notification.cc (revision 0) |
| +++ chrome/browser/web_resource/promo_notification.cc (revision 0) |
| @@ -0,0 +1,280 @@ |
| +// Copyright (c) 2011 The Chromium Authors. All rights reserved. |
| +// Use of this source code is governed by a BSD-style license that can be |
| +// found in the LICENSE file. |
| + |
| +#include "chrome/browser/web_resource/promo_notification.h" |
| + |
| +#include "base/rand_util.h" |
| +#include "base/string_number_conversions.h" |
| +#include "base/time.h" |
| +#include "base/values.h" |
| +#include "chrome/browser/prefs/pref_service.h" |
| +#include "chrome/browser/web_resource/promo_resource_service.h" |
| +#include "chrome/common/pref_names.h" |
| + |
| +// Maximum number of hours for each time slice (4 weeks). |
| +static const int kMaxTimeSliceHours = 24 * 7 * 4; |
| + |
| +PromoNotification::PromoNotification(PrefService* prefs, Delegate* delegate) |
| + : prefs_(prefs), |
| + delegate_(delegate), |
| + start_(0.0), |
| + end_(0.0), |
| + build_(0), |
| + time_slice_(0), |
| + max_group_(0), |
| + max_views_(0), |
| + group_(0), |
| + views_(0), |
| + text_(), |
| + closed_(false) { |
| + DCHECK(prefs); |
| +} |
| + |
| +void PromoNotification::InitFromJson(const DictionaryValue& json) { |
| + DictionaryValue* dict; |
| + if (json.GetDictionary("topic", &dict)) { |
| + ListValue* answers; |
| + if (dict->GetList("answers", &answers)) { |
| + for (ListValue::const_iterator it = answers->begin(); |
| + it != answers->end(); |
| + ++it) { |
| + if ((*it)->IsType(Value::TYPE_DICTIONARY)) |
| + Parse(static_cast<DictionaryValue*>(*it)); |
| + } |
| + } |
| + } |
| + |
| + CheckForNewNotification(); |
| +} |
| + |
| +void PromoNotification::Parse(const DictionaryValue* dict) { |
| + std::string name; |
| + if (dict->GetString("name", &name)) { |
| + if (name == "promo_start") { |
| + GetParams(dict); |
| + dict->GetString("tooltip", &text_); |
| + start_ = GetTimeFromDict(dict); |
| + } else if (name == "promo_end") { |
| + end_ = GetTimeFromDict(dict); |
| + } |
| + } |
| +} |
| + |
| +bool PromoNotification::OutOfBounds(int var, int min, int max) { |
|
Miranda Callahan
2011/09/27 09:18:40
This should probably just be a helper function in
achuithb
2011/09/28 01:40:14
Done.
|
| + return var < min || var > max; |
| +} |
| + |
| +void PromoNotification::GetParams(const DictionaryValue* dict) { |
|
Miranda Callahan
2011/09/27 09:18:40
Perhaps this should be called "ParseParams", since
achuithb
2011/09/28 01:40:14
Done.
|
| + std::string question; |
| + dict->GetString("question", &question); |
| + |
| + size_t index = 0; |
| + bool err = false; |
| + |
| + build_ = GetNextQuestionValue(question, &index, &err); |
| + time_slice_ = GetNextQuestionValue(question, &index, &err); |
| + max_group_ = GetNextQuestionValue(question, &index, &err); |
| + max_views_ = GetNextQuestionValue(question, &index, &err); |
| + |
| + if (err || |
| + OutOfBounds(build_, PromoResourceService::NO_BUILD, |
| + PromoResourceService::ALL_BUILDS) || |
| + OutOfBounds(time_slice_, 0, kMaxTimeSliceHours) || |
| + OutOfBounds(max_group_, 0, kMaxGroupSize) || |
| + OutOfBounds(max_views_, 0, kMaxViews)) { |
| + // If values are not valid, do not show promo notification. |
| + NOTREACHED() << "Invalid server data, question=" << question << |
| + ", build=" << build_ << |
| + ", time_slice=" << time_slice_ << |
| + ", max_group=" << max_group_ << |
| + ", max_views=" << max_views_; |
| + build_ = PromoResourceService::NO_BUILD; |
| + time_slice_ = 0; |
| + max_group_ = 0; |
| + max_views_ = 0; |
| + } |
| +} |
| + |
| +void PromoNotification::CheckForNewNotification() { |
| + const double old_start = GetTimeFromPrefs(prefs::kNTPPromoStart); |
| + const double old_end = GetTimeFromPrefs(prefs::kNTPPromoEnd); |
| + const bool has_views = prefs_->HasPrefPath(prefs::kNTPPromoViewsMax); |
| + |
| + // Trigger a new notification if the times have changed, or if |
| + // we previously never wrote out a max_views preference. |
| + if (old_start != start_ || old_end != end_ || !has_views) |
| + OnNewNotification(); |
| +} |
| + |
| +void PromoNotification::OnNewNotification() { |
| + group_ = NewGroup(); |
| + WritePrefs(); |
| + if (delegate_) |
| + delegate_->OnNewNotification(StartTimeWithOffset(), end_); |
| +} |
| + |
| +// static |
| +int PromoNotification::NewGroup() { |
| + return base::RandInt(0, kMaxGroupSize); |
| +} |
| + |
| +// static |
| +void PromoNotification::RegisterUserPrefs(PrefService* prefs) { |
| + prefs->RegisterDoublePref(prefs::kNTPPromoStart, |
| + 0, |
| + PrefService::UNSYNCABLE_PREF); |
| + prefs->RegisterDoublePref(prefs::kNTPPromoEnd, |
| + 0, |
| + PrefService::UNSYNCABLE_PREF); |
| + |
| + prefs->RegisterIntegerPref(prefs::kNTPPromoBuild, |
| + PromoResourceService::ALL_BUILDS, |
| + PrefService::UNSYNCABLE_PREF); |
| + prefs->RegisterIntegerPref(prefs::kNTPPromoGroupTimeSlice, |
| + 0, |
| + PrefService::UNSYNCABLE_PREF); |
| + prefs->RegisterIntegerPref(prefs::kNTPPromoGroupMax, |
| + 0, |
| + PrefService::UNSYNCABLE_PREF); |
| + prefs->RegisterIntegerPref(prefs::kNTPPromoViewsMax, |
| + 0, |
| + PrefService::UNSYNCABLE_PREF); |
| + |
| + prefs->RegisterStringPref(prefs::kNTPPromoLine, |
| + std::string(), |
| + PrefService::UNSYNCABLE_PREF); |
| + prefs->RegisterIntegerPref(prefs::kNTPPromoGroup, |
| + 0, |
| + PrefService::UNSYNCABLE_PREF); |
| + prefs->RegisterIntegerPref(prefs::kNTPPromoViews, |
| + 0, |
| + PrefService::UNSYNCABLE_PREF); |
| + prefs->RegisterBooleanPref(prefs::kNTPPromoClosed, |
| + false, |
| + PrefService::UNSYNCABLE_PREF); |
| +} |
| + |
| + |
| +void PromoNotification::WritePrefs() { |
| + prefs_->SetDouble(prefs::kNTPPromoStart, start_); |
| + prefs_->SetDouble(prefs::kNTPPromoEnd, end_); |
| + |
| + prefs_->SetInteger(prefs::kNTPPromoBuild, build_); |
| + prefs_->SetInteger(prefs::kNTPPromoGroupTimeSlice, time_slice_); |
| + prefs_->SetInteger(prefs::kNTPPromoGroupMax, max_group_); |
| + prefs_->SetInteger(prefs::kNTPPromoViewsMax, max_views_); |
| + |
| + prefs_->SetString(prefs::kNTPPromoLine, text_); |
| + prefs_->SetInteger(prefs::kNTPPromoGroup, group_); |
| + prefs_->SetInteger(prefs::kNTPPromoViews, views_); |
| + prefs_->SetBoolean(prefs::kNTPPromoClosed, closed_); |
| +} |
| + |
| +void PromoNotification::InitFromPrefs() { |
| + if (prefs_->HasPrefPath(prefs::kNTPPromoStart)) |
| + start_ = prefs_->GetDouble(prefs::kNTPPromoStart); |
| + |
| + if (prefs_->HasPrefPath(prefs::kNTPPromoEnd)) |
| + end_ = prefs_->GetDouble(prefs::kNTPPromoEnd); |
| + |
| + if (prefs_->HasPrefPath(prefs::kNTPPromoBuild)) |
| + build_ = prefs_->GetInteger(prefs::kNTPPromoBuild); |
| + |
| + if (prefs_->HasPrefPath(prefs::kNTPPromoGroupTimeSlice)) |
| + time_slice_ = prefs_->GetInteger(prefs::kNTPPromoGroupTimeSlice); |
| + |
| + if (prefs_->HasPrefPath(prefs::kNTPPromoGroupMax)) |
| + max_group_ = prefs_->GetInteger(prefs::kNTPPromoGroupMax); |
| + |
| + if (prefs_->HasPrefPath(prefs::kNTPPromoViewsMax)) |
| + max_views_ = prefs_->GetInteger(prefs::kNTPPromoViewsMax); |
| + |
| + if (prefs_->HasPrefPath(prefs::kNTPPromoLine)) |
| + text_ = prefs_->GetString(prefs::kNTPPromoLine); |
| + |
| + if (prefs_->HasPrefPath(prefs::kNTPPromoGroup)) |
| + group_ = prefs_->GetInteger(prefs::kNTPPromoGroup); |
| + |
| + if (prefs_->HasPrefPath(prefs::kNTPPromoViews)) |
| + views_ = prefs_->GetInteger(prefs::kNTPPromoViews); |
| + |
| + if (prefs_->HasPrefPath(prefs::kNTPPromoClosed)) |
| + closed_ = prefs_->GetBoolean(prefs::kNTPPromoClosed); |
| +} |
| + |
| +bool PromoNotification::CanShow() const { |
| + return !closed_ && |
| + !text_.empty() && |
| + group_ < max_group_ && |
| + views_ < max_views_ && |
| + IsBuildAllowed(build_) && |
| + base::Time::FromDoubleT(StartTimeWithOffset()) < base::Time::Now() && |
| + base::Time::FromDoubleT(end_) > base::Time::Now(); |
| +} |
| + |
| +bool PromoNotification::IsBuildAllowed(int builds_allowed) const { |
| + if (delegate_) // For testing. |
| + return delegate_->IsBuildAllowed(builds_allowed); |
| + else |
| + return PromoResourceService::IsBuildTargeted( |
| + PromoResourceService::GetChannel(), builds_allowed); |
| +} |
| + |
| +double PromoNotification::StartTimeWithOffset() const { |
| + // Adjust start using group and time slice, adjusted from hours to seconds. |
| + static const double kSecondsInHour = 60.0 * 60.0; |
| + return start_ + group_ * time_slice_ * kSecondsInHour; |
| +} |
| + |
| +// static |
| +int PromoNotification::GetNextQuestionValue(const std::string& question, |
| + size_t* index, |
| + bool* err) { |
| + if (*err) |
| + return 0; |
| + |
| + size_t new_index = question.find(':', *index); |
| + // Note that substr correctly handles npos. |
| + std::string fragment(question.substr(*index, new_index - *index)); |
| + *index = new_index + 1; |
| + |
| + int value; |
| + *err = !base::StringToInt(fragment, &value); |
| + return *err ? 0 : value; |
| +} |
| + |
| +// static |
| +double PromoNotification::GetTimeFromDict(const DictionaryValue* dict) { |
| + std::string str; |
| + dict->GetString("inproduct", &str); |
|
Miranda Callahan
2011/09/27 09:18:40
It's unfortunate that we still have to use strings
achuithb
2011/09/28 01:40:14
Done.
|
| + return GetTimeFromString(str); |
| +} |
| + |
| +// static |
| +double PromoNotification::GetTimeFromString(const std::string& time_str) { |
|
Miranda Callahan
2011/09/27 09:18:40
I would not have this as a separate method, but ju
achuithb
2011/09/28 01:40:14
Done.
|
| + base::Time time; |
| + if (time_str.empty() || !base::Time::FromString(time_str.c_str(), &time)) |
| + return 0.0; |
| + |
| + return time.ToDoubleT(); |
| +} |
| + |
| +double PromoNotification::GetTimeFromPrefs(const char* pref) const { |
| + return prefs_->HasPrefPath(pref) ? prefs_->GetDouble(pref) : 0.0; |
| +} |
| + |
| +bool PromoNotification::operator==(const PromoNotification& other) const { |
| + return prefs_ == other.prefs_ && |
| + delegate_ == other.delegate_ && |
| + start_ == other.start_ && |
| + end_ == other.end_ && |
| + build_ == other.build_ && |
| + time_slice_ == other.time_slice_ && |
| + max_group_ == other.max_group_ && |
| + max_views_ == other.max_views_ && |
| + group_ == other.group_ && |
| + views_ == other.views_ && |
| + text_ == other.text_ && |
| + closed_ == other.closed_; |
| +} |
| Property changes on: chrome/browser/web_resource/promo_notification.cc |
| ___________________________________________________________________ |
| Added: svn:eol-style |
| + LF |