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

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

Issue 8045012: NotificationPromo (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: minor Created 9 years, 2 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
Property Changes:
Added: svn:eol-style
+ LF
OLDNEW
(Empty)
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
3 // found in the LICENSE file.
4
5 #include "chrome/browser/web_resource/promo_notification.h"
6
7 #include "base/rand_util.h"
8 #include "base/string_number_conversions.h"
9 #include "base/time.h"
10 #include "base/values.h"
11 #include "chrome/browser/prefs/pref_service.h"
12 #include "chrome/browser/web_resource/promo_resource_service.h"
13 #include "chrome/common/pref_names.h"
14
15 namespace {
16
17 bool OutOfBounds(int var, int min, int max) {
18 return var < min || var > max;
19 }
20
21 static const char kHeaderProperty[] = "topic";
22 static const char kArrayProperty[] = "answers";
23 static const char kIdentifierProperty[] = "name";
24 static const char kStartPropertyValue[] = "promo_start";
25 static const char kEndPropertyValue[] = "promo_end";
26 static const char kTextProperty[] = "tooltip";
27 static const char kTimeProperty[] = "inproduct";
28 static const char kParamsProperty[] = "question";
29
30 } // namespace
31
32 PromoNotification::PromoNotification(PrefService* prefs, Delegate* delegate)
33 : prefs_(prefs),
34 delegate_(delegate),
35 start_(0.0),
36 end_(0.0),
37 build_(0),
38 time_slice_(0),
39 max_group_(0),
40 max_views_(0),
41 group_(0),
42 views_(0),
43 text_(),
44 closed_(false) {
45 DCHECK(prefs);
46 }
47
48 void PromoNotification::InitFromJson(const DictionaryValue& json) {
49 DictionaryValue* dict;
50 if (json.GetDictionary(kHeaderProperty, &dict)) {
51 ListValue* answers;
52 if (dict->GetList(kArrayProperty, &answers)) {
53 for (ListValue::const_iterator it = answers->begin();
54 it != answers->end();
55 ++it) {
56 if ((*it)->IsType(Value::TYPE_DICTIONARY))
57 Parse(static_cast<DictionaryValue*>(*it));
58 }
59 }
60 }
61
62 CheckForNewNotification();
63 }
64
65 void PromoNotification::Parse(const DictionaryValue* dict) {
66 std::string key;
67 if (dict->GetString(kIdentifierProperty, &key)) {
68 if (key == kStartPropertyValue) {
69 ParseParams(dict);
70 dict->GetString(kTextProperty, &text_);
71 start_ = GetTimeFromDict(dict);
72 } else if (key == kEndPropertyValue) {
73 end_ = GetTimeFromDict(dict);
74 }
75 }
76 }
77
78 void PromoNotification::ParseParams(const DictionaryValue* dict) {
79 std::string question;
80 if (!dict->GetString(kParamsProperty, &question))
81 return;
82
83 size_t index = 0;
84 bool err = false;
85
86 build_ = GetNextQuestionValue(question, &index, &err);
87 time_slice_ = GetNextQuestionValue(question, &index, &err);
88 max_group_ = GetNextQuestionValue(question, &index, &err);
89 max_views_ = GetNextQuestionValue(question, &index, &err);
90
91 if (err ||
92 OutOfBounds(build_, PromoResourceService::NO_BUILD,
93 PromoResourceService::ALL_BUILDS) ||
94 OutOfBounds(time_slice_, 0, kMaxTimeSliceHours) ||
95 OutOfBounds(max_group_, 0, kMaxGroupSize) ||
96 OutOfBounds(max_views_, 0, kMaxViews)) {
97 // If values are not valid, do not show promo notification.
98 NOTREACHED() << "Invalid server data, question=" << question <<
99 ", build=" << build_ <<
100 ", time_slice=" << time_slice_ <<
101 ", max_group=" << max_group_ <<
102 ", max_views=" << max_views_;
103 build_ = PromoResourceService::NO_BUILD;
104 time_slice_ = 0;
105 max_group_ = 0;
106 max_views_ = 0;
107 }
108 }
109
110 void PromoNotification::CheckForNewNotification() {
111 const double old_start = GetTimeFromPrefs(prefs::kNTPPromoStart);
112 const double old_end = GetTimeFromPrefs(prefs::kNTPPromoEnd);
113 const bool has_views = prefs_->HasPrefPath(prefs::kNTPPromoViewsMax);
114
115 // Trigger a new notification if the times have changed, or if
116 // we previously never wrote out a max_views preference.
117 if (old_start != start_ || old_end != end_ || !has_views)
118 OnNewNotification();
119 }
120
121 void PromoNotification::OnNewNotification() {
122 group_ = NewGroup();
123 WritePrefs();
124 if (delegate_)
125 delegate_->OnNewNotification(StartTimeWithOffset(), end_);
126 }
127
128 // static
129 int PromoNotification::NewGroup() {
130 return base::RandInt(0, kMaxGroupSize);
131 }
132
133 // static
134 void PromoNotification::RegisterUserPrefs(PrefService* prefs) {
135 prefs->RegisterDoublePref(prefs::kNTPPromoStart,
136 0,
137 PrefService::UNSYNCABLE_PREF);
138 prefs->RegisterDoublePref(prefs::kNTPPromoEnd,
139 0,
140 PrefService::UNSYNCABLE_PREF);
141
142 prefs->RegisterIntegerPref(prefs::kNTPPromoBuild,
143 PromoResourceService::ALL_BUILDS,
144 PrefService::UNSYNCABLE_PREF);
145 prefs->RegisterIntegerPref(prefs::kNTPPromoGroupTimeSlice,
146 0,
147 PrefService::UNSYNCABLE_PREF);
148 prefs->RegisterIntegerPref(prefs::kNTPPromoGroupMax,
149 0,
150 PrefService::UNSYNCABLE_PREF);
151 prefs->RegisterIntegerPref(prefs::kNTPPromoViewsMax,
152 0,
153 PrefService::UNSYNCABLE_PREF);
154
155 prefs->RegisterStringPref(prefs::kNTPPromoLine,
156 std::string(),
157 PrefService::UNSYNCABLE_PREF);
158 prefs->RegisterIntegerPref(prefs::kNTPPromoGroup,
159 0,
160 PrefService::UNSYNCABLE_PREF);
161 prefs->RegisterIntegerPref(prefs::kNTPPromoViews,
162 0,
163 PrefService::UNSYNCABLE_PREF);
164 prefs->RegisterBooleanPref(prefs::kNTPPromoClosed,
165 false,
166 PrefService::UNSYNCABLE_PREF);
167 }
168
169
170 void PromoNotification::WritePrefs() {
171 prefs_->SetDouble(prefs::kNTPPromoStart, start_);
172 prefs_->SetDouble(prefs::kNTPPromoEnd, end_);
173
174 prefs_->SetInteger(prefs::kNTPPromoBuild, build_);
175 prefs_->SetInteger(prefs::kNTPPromoGroupTimeSlice, time_slice_);
176 prefs_->SetInteger(prefs::kNTPPromoGroupMax, max_group_);
177 prefs_->SetInteger(prefs::kNTPPromoViewsMax, max_views_);
178
179 prefs_->SetString(prefs::kNTPPromoLine, text_);
180 prefs_->SetInteger(prefs::kNTPPromoGroup, group_);
181 prefs_->SetInteger(prefs::kNTPPromoViews, views_);
182 prefs_->SetBoolean(prefs::kNTPPromoClosed, closed_);
183 }
184
185 void PromoNotification::InitFromPrefs() {
186 if (prefs_->HasPrefPath(prefs::kNTPPromoStart))
187 start_ = prefs_->GetDouble(prefs::kNTPPromoStart);
188
189 if (prefs_->HasPrefPath(prefs::kNTPPromoEnd))
190 end_ = prefs_->GetDouble(prefs::kNTPPromoEnd);
191
192 if (prefs_->HasPrefPath(prefs::kNTPPromoBuild))
193 build_ = prefs_->GetInteger(prefs::kNTPPromoBuild);
194
195 if (prefs_->HasPrefPath(prefs::kNTPPromoGroupTimeSlice))
196 time_slice_ = prefs_->GetInteger(prefs::kNTPPromoGroupTimeSlice);
197
198 if (prefs_->HasPrefPath(prefs::kNTPPromoGroupMax))
199 max_group_ = prefs_->GetInteger(prefs::kNTPPromoGroupMax);
200
201 if (prefs_->HasPrefPath(prefs::kNTPPromoViewsMax))
202 max_views_ = prefs_->GetInteger(prefs::kNTPPromoViewsMax);
203
204 if (prefs_->HasPrefPath(prefs::kNTPPromoLine))
205 text_ = prefs_->GetString(prefs::kNTPPromoLine);
206
207 if (prefs_->HasPrefPath(prefs::kNTPPromoGroup))
208 group_ = prefs_->GetInteger(prefs::kNTPPromoGroup);
209
210 if (prefs_->HasPrefPath(prefs::kNTPPromoViews))
211 views_ = prefs_->GetInteger(prefs::kNTPPromoViews);
212
213 if (prefs_->HasPrefPath(prefs::kNTPPromoClosed))
214 closed_ = prefs_->GetBoolean(prefs::kNTPPromoClosed);
215 }
216
217 bool PromoNotification::CanShow() const {
218 return !closed_ &&
219 !text_.empty() &&
220 group_ < max_group_ &&
221 views_ < max_views_ &&
222 IsBuildAllowed(build_) &&
223 base::Time::FromDoubleT(StartTimeWithOffset()) < base::Time::Now() &&
224 base::Time::FromDoubleT(end_) > base::Time::Now();
225 }
226
227 bool PromoNotification::IsBuildAllowed(int builds_allowed) const {
228 if (delegate_) // For testing.
229 return delegate_->IsBuildAllowed(builds_allowed);
230 else
231 return PromoResourceService::IsBuildTargeted(
232 PromoResourceService::GetChannel(), builds_allowed);
233 }
234
235 double PromoNotification::StartTimeWithOffset() const {
236 // Adjust start using group and time slice, adjusted from hours to seconds.
237 static const double kSecondsInHour = 60.0 * 60.0;
238 return start_ + group_ * time_slice_ * kSecondsInHour;
239 }
240
241 // static
242 int PromoNotification::GetNextQuestionValue(const std::string& question,
243 size_t* index,
244 bool* err) {
245 if (*err)
246 return 0;
247
248 size_t new_index = question.find(':', *index);
249 // Note that substr correctly handles npos.
250 std::string fragment(question.substr(*index, new_index - *index));
251 *index = new_index + 1;
252
253 int value;
254 *err = !base::StringToInt(fragment, &value);
255 return *err ? 0 : value;
256 }
257
258 // static
259 double PromoNotification::GetTimeFromDict(const DictionaryValue* dict) {
260 std::string time_str;
261 if (!dict->GetString(kTimeProperty, &time_str))
262 return 0.0;
263
264 base::Time time;
265 if (time_str.empty() || !base::Time::FromString(time_str.c_str(), &time))
266 return 0.0;
267
268 return time.ToDoubleT();
269 }
270
271 double PromoNotification::GetTimeFromPrefs(const char* pref) const {
272 return prefs_->HasPrefPath(pref) ? prefs_->GetDouble(pref) : 0.0;
273 }
274
275 bool PromoNotification::operator==(const PromoNotification& other) const {
276 return prefs_ == other.prefs_ &&
277 delegate_ == other.delegate_ &&
278 start_ == other.start_ &&
279 end_ == other.end_ &&
280 build_ == other.build_ &&
281 time_slice_ == other.time_slice_ &&
282 max_group_ == other.max_group_ &&
283 max_views_ == other.max_views_ &&
284 group_ == other.group_ &&
285 views_ == other.views_ &&
286 text_ == other.text_ &&
287 closed_ == other.closed_;
288 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698