OLD | NEW |
---|---|
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 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 | 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 "base/bind.h" | |
7 #include "base/rand_util.h" | 8 #include "base/rand_util.h" |
8 #include "base/string_number_conversions.h" | 9 #include "base/string_number_conversions.h" |
10 #include "base/string_split.h" | |
9 #include "base/time.h" | 11 #include "base/time.h" |
10 #include "base/values.h" | 12 #include "base/values.h" |
11 #include "chrome/browser/prefs/pref_service.h" | 13 #include "chrome/browser/prefs/pref_service.h" |
14 #include "chrome/browser/profiles/profile_impl.h" | |
12 #include "chrome/browser/web_resource/promo_resource_service.h" | 15 #include "chrome/browser/web_resource/promo_resource_service.h" |
13 #include "chrome/common/pref_names.h" | 16 #include "chrome/common/pref_names.h" |
17 #include "googleurl/src/gurl.h" | |
18 #include "net/base/cookie_store.h" | |
19 | |
14 | 20 |
15 namespace { | 21 namespace { |
16 | 22 |
17 // Maximum number of views. | 23 // Maximum number of views. |
18 static const int kMaxViews = 1000; | 24 static const int kMaxViews = 1000; |
19 | 25 |
20 // Maximum number of hours for each time slice (4 weeks). | 26 // Maximum number of hours for each time slice (4 weeks). |
21 static const int kMaxTimeSliceHours = 24 * 7 * 4; | 27 static const int kMaxTimeSliceHours = 24 * 7 * 4; |
22 | 28 |
23 bool OutOfBounds(int var, int min, int max) { | 29 bool OutOfBounds(int var, int min, int max) { |
24 return var < min || var > max; | 30 return var < min || var > max; |
25 } | 31 } |
26 | 32 |
27 static const char kHeaderProperty[] = "topic"; | 33 static const char kHeaderProperty[] = "topic"; |
28 static const char kArrayProperty[] = "answers"; | 34 static const char kArrayProperty[] = "answers"; |
29 static const char kIdentifierProperty[] = "name"; | 35 static const char kIdentifierProperty[] = "name"; |
30 static const char kStartPropertyValue[] = "promo_start"; | 36 static const char kStartPropertyValue[] = "promo_start"; |
31 static const char kEndPropertyValue[] = "promo_end"; | 37 static const char kEndPropertyValue[] = "promo_end"; |
32 static const char kTextProperty[] = "tooltip"; | 38 static const char kTextProperty[] = "tooltip"; |
33 static const char kTimeProperty[] = "inproduct"; | 39 static const char kTimeProperty[] = "inproduct"; |
34 static const char kParamsProperty[] = "question"; | 40 static const char kParamsProperty[] = "question"; |
35 | 41 |
42 static const char kGPlusDomainUrl[] = "http://plus.google.com/"; | |
43 static const char kGPlusDomainSecureCookieId[] = "SID="; | |
44 static const char kSplitStringToken = ';'; | |
45 | |
36 // Time getters. | 46 // Time getters. |
37 double GetTimeFromDict(const DictionaryValue* dict) { | 47 double GetTimeFromDict(const DictionaryValue* dict) { |
38 std::string time_str; | 48 std::string time_str; |
39 if (!dict->GetString(kTimeProperty, &time_str)) | 49 if (!dict->GetString(kTimeProperty, &time_str)) |
40 return 0.0; | 50 return 0.0; |
41 | 51 |
42 base::Time time; | 52 base::Time time; |
43 if (time_str.empty() || !base::Time::FromString(time_str.c_str(), &time)) | 53 if (time_str.empty() || !base::Time::FromString(time_str.c_str(), &time)) |
44 return 0.0; | 54 return 0.0; |
45 | 55 |
46 return time.ToDoubleT(); | 56 return time.ToDoubleT(); |
47 } | 57 } |
48 | 58 |
49 double GetTimeFromPrefs(PrefService* prefs, const char* pref) { | 59 double GetTimeFromPrefs(PrefService* prefs, const char* pref) { |
50 return prefs->HasPrefPath(pref) ? prefs->GetDouble(pref) : 0.0; | 60 return prefs->HasPrefPath(pref) ? prefs->GetDouble(pref) : 0.0; |
51 } | 61 } |
52 | 62 |
53 } // namespace | 63 } // namespace |
54 | 64 |
55 NotificationPromo::NotificationPromo(PrefService* prefs, Delegate* delegate) | 65 NotificationPromo::NotificationPromo(Profile* profile, Delegate* delegate) |
56 : prefs_(prefs), | 66 : profile_(profile), |
57 delegate_(delegate), | 67 delegate_(delegate), |
68 prefs_(profile_->GetPrefs()), | |
58 start_(0.0), | 69 start_(0.0), |
59 end_(0.0), | 70 end_(0.0), |
60 build_(0), | 71 build_(0), |
61 time_slice_(0), | 72 time_slice_(0), |
62 max_group_(0), | 73 max_group_(0), |
63 max_views_(0), | 74 max_views_(0), |
64 group_(0), | 75 group_(0), |
65 views_(0), | 76 views_(0), |
66 text_(), | 77 text_(), |
67 closed_(false) { | 78 closed_(false), |
68 DCHECK(prefs); | 79 gplus_(false), |
80 feature_mask_(0) { | |
81 DCHECK(profile); | |
82 DCHECK(prefs_); | |
69 } | 83 } |
70 | 84 |
85 NotificationPromo::~NotificationPromo() {} | |
86 | |
71 void NotificationPromo::InitFromJson(const DictionaryValue& json) { | 87 void NotificationPromo::InitFromJson(const DictionaryValue& json) { |
72 DictionaryValue* dict; | 88 DictionaryValue* dict; |
73 if (json.GetDictionary(kHeaderProperty, &dict)) { | 89 if (json.GetDictionary(kHeaderProperty, &dict)) { |
74 ListValue* answers; | 90 ListValue* answers; |
75 if (dict->GetList(kArrayProperty, &answers)) { | 91 if (dict->GetList(kArrayProperty, &answers)) { |
76 for (ListValue::const_iterator it = answers->begin(); | 92 for (ListValue::const_iterator it = answers->begin(); |
77 it != answers->end(); | 93 it != answers->end(); |
78 ++it) { | 94 ++it) { |
79 if ((*it)->IsType(Value::TYPE_DICTIONARY)) | 95 if ((*it)->IsType(Value::TYPE_DICTIONARY)) |
80 Parse(static_cast<DictionaryValue*>(*it)); | 96 Parse(static_cast<DictionaryValue*>(*it)); |
81 } | 97 } |
82 } | 98 } |
83 } | 99 } |
100 content::BrowserThread::PostTask(content::BrowserThread::IO, FROM_HERE, | |
101 base::Bind(&NotificationPromo::GetCookies, base::Unretained(this), | |
102 base::Unretained(profile_->GetRequestContext()))); | |
103 } | |
84 | 104 |
85 CheckForNewNotification(); | 105 void NotificationPromo::GetCookiesCallback(const std::string& cookies) { |
106 std::vector<std::string> cookie_list; | |
107 bool found_cookie = false; | |
108 base::SplitString(cookies, kSplitStringToken, &cookie_list); | |
109 for (std::vector<std::string>::const_iterator current = cookie_list.begin(); | |
110 current != cookie_list.end(); | |
111 ++current) { | |
112 if ((*current).find(kGPlusDomainSecureCookieId) == 0) { | |
113 found_cookie = true; | |
114 break; | |
115 } | |
116 } | |
117 content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE, | |
118 base::Bind(&NotificationPromo::CheckForNewNotification, this, | |
119 found_cookie)); | |
120 } | |
121 | |
122 void NotificationPromo::GetCookies(net::URLRequestContextGetter* getter) { | |
123 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); | |
124 getter->GetURLRequestContext()->cookie_store()-> | |
125 GetCookiesWithOptionsAsync( | |
126 GURL(kGPlusDomainUrl), net::CookieOptions(), | |
127 base::Bind(&NotificationPromo::GetCookiesCallback, this)); | |
86 } | 128 } |
87 | 129 |
88 void NotificationPromo::Parse(const DictionaryValue* dict) { | 130 void NotificationPromo::Parse(const DictionaryValue* dict) { |
89 std::string key; | 131 std::string key; |
90 if (dict->GetString(kIdentifierProperty, &key)) { | 132 if (dict->GetString(kIdentifierProperty, &key)) { |
91 if (key == kStartPropertyValue) { | 133 if (key == kStartPropertyValue) { |
92 ParseParams(dict); | 134 ParseParams(dict); |
93 dict->GetString(kTextProperty, &text_); | 135 dict->GetString(kTextProperty, &text_); |
94 start_ = GetTimeFromDict(dict); | 136 start_ = GetTimeFromDict(dict); |
95 } else if (key == kEndPropertyValue) { | 137 } else if (key == kEndPropertyValue) { |
96 end_ = GetTimeFromDict(dict); | 138 end_ = GetTimeFromDict(dict); |
97 } | 139 } |
98 } | 140 } |
99 } | 141 } |
100 | 142 |
101 void NotificationPromo::ParseParams(const DictionaryValue* dict) { | 143 void NotificationPromo::ParseParams(const DictionaryValue* dict) { |
102 std::string question; | 144 std::string question; |
103 if (!dict->GetString(kParamsProperty, &question)) | 145 if (!dict->GetString(kParamsProperty, &question)) |
104 return; | 146 return; |
105 | 147 |
106 size_t index = 0; | 148 size_t index = 0; |
107 bool err = false; | 149 bool err = false; |
108 | 150 |
109 build_ = GetNextQuestionValue(question, &index, &err); | 151 build_ = GetNextQuestionValue(question, &index, &err); |
110 time_slice_ = GetNextQuestionValue(question, &index, &err); | 152 time_slice_ = GetNextQuestionValue(question, &index, &err); |
111 max_group_ = GetNextQuestionValue(question, &index, &err); | 153 max_group_ = GetNextQuestionValue(question, &index, &err); |
112 max_views_ = GetNextQuestionValue(question, &index, &err); | 154 max_views_ = GetNextQuestionValue(question, &index, &err); |
155 feature_mask_ = GetNextQuestionValue(question, &index, &err); | |
113 | 156 |
114 if (err || | 157 if (err || |
115 OutOfBounds(build_, PromoResourceService::NO_BUILD, | 158 OutOfBounds(build_, PromoResourceService::NO_BUILD, |
116 PromoResourceService::ALL_BUILDS) || | 159 PromoResourceService::ALL_BUILDS) || |
117 OutOfBounds(time_slice_, 0, kMaxTimeSliceHours) || | 160 OutOfBounds(time_slice_, 0, kMaxTimeSliceHours) || |
118 OutOfBounds(max_group_, 0, kMaxGroupSize) || | 161 OutOfBounds(max_group_, 0, kMaxGroupSize) || |
119 OutOfBounds(max_views_, 0, kMaxViews)) { | 162 OutOfBounds(max_views_, 0, kMaxViews)) { |
120 // If values are not valid, do not show promo notification. | 163 // If values are not valid, do not show promo notification. |
121 DLOG(ERROR) << "Invalid server data, question=" << question << | 164 DLOG(ERROR) << "Invalid server data, question=" << question << |
122 ", build=" << build_ << | 165 ", build=" << build_ << |
123 ", time_slice=" << time_slice_ << | 166 ", time_slice=" << time_slice_ << |
124 ", max_group=" << max_group_ << | 167 ", max_group=" << max_group_ << |
125 ", max_views=" << max_views_; | 168 ", max_views=" << max_views_; |
126 build_ = PromoResourceService::NO_BUILD; | 169 build_ = PromoResourceService::NO_BUILD; |
127 time_slice_ = 0; | 170 time_slice_ = 0; |
128 max_group_ = 0; | 171 max_group_ = 0; |
129 max_views_ = 0; | 172 max_views_ = 0; |
130 } | 173 } |
131 } | 174 } |
132 | 175 |
133 void NotificationPromo::CheckForNewNotification() { | 176 void NotificationPromo::CheckForNewNotification(bool found_cookie) { |
177 gplus_ = found_cookie; | |
achuithb
2011/11/16 23:17:33
Instead of this, you would do:
if (found_cookie)
achuithb
2011/11/16 23:27:03
Ok, I see the problem. I'm sorry, I'm re-using fea
| |
134 const double old_start = GetTimeFromPrefs(prefs_, prefs::kNTPPromoStart); | 178 const double old_start = GetTimeFromPrefs(prefs_, prefs::kNTPPromoStart); |
135 const double old_end = GetTimeFromPrefs(prefs_, prefs::kNTPPromoEnd); | 179 const double old_end = GetTimeFromPrefs(prefs_, prefs::kNTPPromoEnd); |
180 const bool old_gplus = prefs_->GetBoolean(prefs::kNTPPromoIsLoggedInToPlus); | |
achuithb
2011/11/16 23:17:33
don't need this.
Cait (Slow)
2011/11/17 00:05:59
I had this in here to force a refresh of the promo
achuithb
2011/11/17 00:09:34
Ah, ok. That makes sense. Could you add a comment
| |
136 const bool has_views = prefs_->HasPrefPath(prefs::kNTPPromoViewsMax); | 181 const bool has_views = prefs_->HasPrefPath(prefs::kNTPPromoViewsMax); |
achuithb
2011/11/16 23:17:33
don't need this line either.
Cait (Slow)
2011/11/17 00:05:59
Done.
| |
137 | 182 const int old_feature_mask = prefs_->GetInteger(prefs::kNTPPromoFeatureMask); |
138 // Trigger a new notification if the times have changed, or if | 183 // Trigger a new notification if the times have changed, or if |
139 // we previously never wrote out a max_views preference. | 184 // we previously never wrote out a max_views preference. |
achuithb
2011/11/16 23:17:33
please change this comment:
s/max_views/feature_ma
Cait (Slow)
2011/11/17 00:05:59
Done.
| |
140 if (old_start != start_ || old_end != end_ || !has_views) | 185 if (old_start != start_ || old_end != end_ || !has_views |
186 || old_gplus != gplus_ || old_feature_mask != feature_mask_) | |
achuithb
2011/11/16 23:27:03
Just old_feature_mask should be sufficient.
Cait (Slow)
2011/11/17 00:05:59
Done.
| |
141 OnNewNotification(); | 187 OnNewNotification(); |
142 } | 188 } |
143 | 189 |
144 void NotificationPromo::OnNewNotification() { | 190 void NotificationPromo::OnNewNotification() { |
145 group_ = NewGroup(); | 191 group_ = NewGroup(); |
146 WritePrefs(); | 192 WritePrefs(); |
147 if (delegate_) | 193 if (delegate_) |
148 delegate_->OnNewNotification(StartTimeWithOffset(), end_); | 194 delegate_->OnNewNotification(StartTimeWithOffset(), end_); |
149 } | 195 } |
150 | 196 |
(...skipping 29 matching lines...) Expand all Loading... | |
180 PrefService::UNSYNCABLE_PREF); | 226 PrefService::UNSYNCABLE_PREF); |
181 prefs->RegisterIntegerPref(prefs::kNTPPromoGroup, | 227 prefs->RegisterIntegerPref(prefs::kNTPPromoGroup, |
182 0, | 228 0, |
183 PrefService::UNSYNCABLE_PREF); | 229 PrefService::UNSYNCABLE_PREF); |
184 prefs->RegisterIntegerPref(prefs::kNTPPromoViews, | 230 prefs->RegisterIntegerPref(prefs::kNTPPromoViews, |
185 0, | 231 0, |
186 PrefService::UNSYNCABLE_PREF); | 232 PrefService::UNSYNCABLE_PREF); |
187 prefs->RegisterBooleanPref(prefs::kNTPPromoClosed, | 233 prefs->RegisterBooleanPref(prefs::kNTPPromoClosed, |
188 false, | 234 false, |
189 PrefService::UNSYNCABLE_PREF); | 235 PrefService::UNSYNCABLE_PREF); |
236 prefs->RegisterBooleanPref(prefs::kNTPPromoIsLoggedInToPlus, | |
237 false, | |
238 PrefService::UNSYNCABLE_PREF); | |
239 prefs->RegisterIntegerPref(prefs::kNTPPromoFeatureMask, | |
240 0, | |
241 PrefService::UNSYNCABLE_PREF); | |
242 } | |
243 | |
244 // static | |
245 NotificationPromo* NotificationPromo::Factory(Profile *profile, | |
246 NotificationPromo::Delegate * delegate) { | |
247 return new NotificationPromo(profile, delegate); | |
190 } | 248 } |
191 | 249 |
192 | 250 |
193 void NotificationPromo::WritePrefs() { | 251 void NotificationPromo::WritePrefs() { |
194 prefs_->SetDouble(prefs::kNTPPromoStart, start_); | 252 prefs_->SetDouble(prefs::kNTPPromoStart, start_); |
195 prefs_->SetDouble(prefs::kNTPPromoEnd, end_); | 253 prefs_->SetDouble(prefs::kNTPPromoEnd, end_); |
196 | 254 |
197 prefs_->SetInteger(prefs::kNTPPromoBuild, build_); | 255 prefs_->SetInteger(prefs::kNTPPromoBuild, build_); |
198 prefs_->SetInteger(prefs::kNTPPromoGroupTimeSlice, time_slice_); | 256 prefs_->SetInteger(prefs::kNTPPromoGroupTimeSlice, time_slice_); |
199 prefs_->SetInteger(prefs::kNTPPromoGroupMax, max_group_); | 257 prefs_->SetInteger(prefs::kNTPPromoGroupMax, max_group_); |
200 prefs_->SetInteger(prefs::kNTPPromoViewsMax, max_views_); | 258 prefs_->SetInteger(prefs::kNTPPromoViewsMax, max_views_); |
201 | 259 |
202 prefs_->SetString(prefs::kNTPPromoLine, text_); | 260 prefs_->SetString(prefs::kNTPPromoLine, text_); |
203 prefs_->SetInteger(prefs::kNTPPromoGroup, group_); | 261 prefs_->SetInteger(prefs::kNTPPromoGroup, group_); |
204 prefs_->SetInteger(prefs::kNTPPromoViews, views_); | 262 prefs_->SetInteger(prefs::kNTPPromoViews, views_); |
205 prefs_->SetBoolean(prefs::kNTPPromoClosed, closed_); | 263 prefs_->SetBoolean(prefs::kNTPPromoClosed, closed_); |
264 prefs_->SetBoolean(prefs::kNTPPromoIsLoggedInToPlus, gplus_); | |
265 prefs_->SetInteger(prefs::kNTPPromoFeatureMask, feature_mask_); | |
206 } | 266 } |
207 | 267 |
208 void NotificationPromo::InitFromPrefs() { | 268 void NotificationPromo::InitFromPrefs() { |
209 if (prefs_->HasPrefPath(prefs::kNTPPromoStart)) | 269 if (prefs_->HasPrefPath(prefs::kNTPPromoStart)) |
210 start_ = prefs_->GetDouble(prefs::kNTPPromoStart); | 270 start_ = prefs_->GetDouble(prefs::kNTPPromoStart); |
211 | 271 |
212 if (prefs_->HasPrefPath(prefs::kNTPPromoEnd)) | 272 if (prefs_->HasPrefPath(prefs::kNTPPromoEnd)) |
213 end_ = prefs_->GetDouble(prefs::kNTPPromoEnd); | 273 end_ = prefs_->GetDouble(prefs::kNTPPromoEnd); |
214 | 274 |
215 if (prefs_->HasPrefPath(prefs::kNTPPromoBuild)) | 275 if (prefs_->HasPrefPath(prefs::kNTPPromoBuild)) |
(...skipping 12 matching lines...) Expand all Loading... | |
228 text_ = prefs_->GetString(prefs::kNTPPromoLine); | 288 text_ = prefs_->GetString(prefs::kNTPPromoLine); |
229 | 289 |
230 if (prefs_->HasPrefPath(prefs::kNTPPromoGroup)) | 290 if (prefs_->HasPrefPath(prefs::kNTPPromoGroup)) |
231 group_ = prefs_->GetInteger(prefs::kNTPPromoGroup); | 291 group_ = prefs_->GetInteger(prefs::kNTPPromoGroup); |
232 | 292 |
233 if (prefs_->HasPrefPath(prefs::kNTPPromoViews)) | 293 if (prefs_->HasPrefPath(prefs::kNTPPromoViews)) |
234 views_ = prefs_->GetInteger(prefs::kNTPPromoViews); | 294 views_ = prefs_->GetInteger(prefs::kNTPPromoViews); |
235 | 295 |
236 if (prefs_->HasPrefPath(prefs::kNTPPromoClosed)) | 296 if (prefs_->HasPrefPath(prefs::kNTPPromoClosed)) |
237 closed_ = prefs_->GetBoolean(prefs::kNTPPromoClosed); | 297 closed_ = prefs_->GetBoolean(prefs::kNTPPromoClosed); |
298 | |
299 if (prefs_->HasPrefPath(prefs::kNTPPromoIsLoggedInToPlus)) | |
300 gplus_ = prefs_->GetBoolean(prefs::kNTPPromoIsLoggedInToPlus); | |
301 | |
302 if (prefs_->HasPrefPath(prefs::kNTPPromoFeatureMask)) | |
303 feature_mask_ = prefs_->GetInteger(prefs::kNTPPromoFeatureMask); | |
238 } | 304 } |
239 | 305 |
240 bool NotificationPromo::CanShow() const { | 306 bool NotificationPromo::CanShow() const { |
241 return !closed_ && | 307 return !closed_ && |
242 !text_.empty() && | 308 !text_.empty() && |
243 group_ < max_group_ && | 309 group_ < max_group_ && |
244 views_ < max_views_ && | 310 views_ < max_views_ && |
245 IsBuildAllowed(build_) && | 311 IsBuildAllowed(build_) && |
246 base::Time::FromDoubleT(StartTimeWithOffset()) < base::Time::Now() && | 312 base::Time::FromDoubleT(StartTimeWithOffset()) < base::Time::Now() && |
247 base::Time::FromDoubleT(end_) > base::Time::Now(); | 313 base::Time::FromDoubleT(end_) > base::Time::Now() && |
314 ((feature_mask_ & !gplus_) == 0); | |
achuithb
2011/11/16 23:27:03
I think this condition should be:
(feature_mask_ &
Cait (Slow)
2011/11/17 00:05:59
Done.
| |
248 } | 315 } |
249 | 316 |
250 void NotificationPromo::HandleClosed() { | 317 void NotificationPromo::HandleClosed() { |
251 prefs_->SetBoolean(prefs::kNTPPromoClosed, true); | 318 prefs_->SetBoolean(prefs::kNTPPromoClosed, true); |
252 } | 319 } |
253 | 320 |
254 bool NotificationPromo::HandleViewed() { | 321 bool NotificationPromo::HandleViewed() { |
255 if (prefs_->HasPrefPath(prefs::kNTPPromoViewsMax)) | 322 if (prefs_->HasPrefPath(prefs::kNTPPromoViewsMax)) |
256 max_views_ = prefs_->GetInteger(prefs::kNTPPromoViewsMax); | 323 max_views_ = prefs_->GetInteger(prefs::kNTPPromoViewsMax); |
257 | 324 |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
298 delegate_ == other.delegate_ && | 365 delegate_ == other.delegate_ && |
299 start_ == other.start_ && | 366 start_ == other.start_ && |
300 end_ == other.end_ && | 367 end_ == other.end_ && |
301 build_ == other.build_ && | 368 build_ == other.build_ && |
302 time_slice_ == other.time_slice_ && | 369 time_slice_ == other.time_slice_ && |
303 max_group_ == other.max_group_ && | 370 max_group_ == other.max_group_ && |
304 max_views_ == other.max_views_ && | 371 max_views_ == other.max_views_ && |
305 group_ == other.group_ && | 372 group_ == other.group_ && |
306 views_ == other.views_ && | 373 views_ == other.views_ && |
307 text_ == other.text_ && | 374 text_ == other.text_ && |
308 closed_ == other.closed_; | 375 closed_ == other.closed_ && |
376 gplus_ == other.gplus_ && | |
377 feature_mask_ == other.feature_mask_; | |
309 } | 378 } |
OLD | NEW |