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

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

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

Powered by Google App Engine
This is Rietveld 408576698