OLD | NEW |
---|---|
1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 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/engagement/site_engagement_service.h" | 5 #include "chrome/browser/engagement/site_engagement_service.h" |
6 | 6 |
7 #include <stddef.h> | 7 #include <stddef.h> |
8 | 8 |
9 #include <algorithm> | 9 #include <algorithm> |
10 #include <utility> | 10 #include <utility> |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
44 | 44 |
45 std::unique_ptr<ContentSettingsForOneType> GetEngagementContentSettings( | 45 std::unique_ptr<ContentSettingsForOneType> GetEngagementContentSettings( |
46 HostContentSettingsMap* settings_map) { | 46 HostContentSettingsMap* settings_map) { |
47 std::unique_ptr<ContentSettingsForOneType> engagement_settings( | 47 std::unique_ptr<ContentSettingsForOneType> engagement_settings( |
48 new ContentSettingsForOneType); | 48 new ContentSettingsForOneType); |
49 settings_map->GetSettingsForOneType(CONTENT_SETTINGS_TYPE_SITE_ENGAGEMENT, | 49 settings_map->GetSettingsForOneType(CONTENT_SETTINGS_TYPE_SITE_ENGAGEMENT, |
50 std::string(), engagement_settings.get()); | 50 std::string(), engagement_settings.get()); |
51 return engagement_settings; | 51 return engagement_settings; |
52 } | 52 } |
53 | 53 |
54 std::unique_ptr<base::DictionaryValue> GetScoreDictForOrigin( | |
55 HostContentSettingsMap* settings, | |
56 const GURL& origin_url) { | |
57 if (!settings) | |
58 return std::unique_ptr<base::DictionaryValue>(); | |
59 | |
60 std::unique_ptr<base::Value> value = settings->GetWebsiteSetting( | |
61 origin_url, origin_url, CONTENT_SETTINGS_TYPE_SITE_ENGAGEMENT, | |
62 std::string(), NULL); | |
63 if (!value.get()) | |
64 return base::WrapUnique(new base::DictionaryValue()); | |
65 | |
66 if (!value->IsType(base::Value::TYPE_DICTIONARY)) | |
67 return base::WrapUnique(new base::DictionaryValue()); | |
68 | |
69 return base::WrapUnique(static_cast<base::DictionaryValue*>(value.release())); | |
70 } | |
71 | |
72 // Only accept a navigation event for engagement if it is one of: | 54 // Only accept a navigation event for engagement if it is one of: |
73 // a. direct typed navigation | 55 // a. direct typed navigation |
74 // b. clicking on an omnibox suggestion brought up by typing a keyword | 56 // b. clicking on an omnibox suggestion brought up by typing a keyword |
75 // c. clicking on a bookmark or opening a bookmark app | 57 // c. clicking on a bookmark or opening a bookmark app |
76 // d. a custom search engine keyword search (e.g. Wikipedia search box added as | 58 // d. a custom search engine keyword search (e.g. Wikipedia search box added as |
77 // search engine). | 59 // search engine). |
78 bool IsEngagementNavigation(ui::PageTransition transition) { | 60 bool IsEngagementNavigation(ui::PageTransition transition) { |
79 return ui::PageTransitionCoreTypeIs(transition, ui::PAGE_TRANSITION_TYPED) || | 61 return ui::PageTransitionCoreTypeIs(transition, ui::PAGE_TRANSITION_TYPED) || |
80 ui::PageTransitionCoreTypeIs(transition, | 62 ui::PageTransitionCoreTypeIs(transition, |
81 ui::PAGE_TRANSITION_GENERATED) || | 63 ui::PAGE_TRANSITION_GENERATED) || |
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
166 HostContentSettingsMapFactory::GetForProfile(profile_); | 148 HostContentSettingsMapFactory::GetForProfile(profile_); |
167 std::unique_ptr<ContentSettingsForOneType> engagement_settings = | 149 std::unique_ptr<ContentSettingsForOneType> engagement_settings = |
168 GetEngagementContentSettings(settings_map); | 150 GetEngagementContentSettings(settings_map); |
169 | 151 |
170 std::map<GURL, double> score_map; | 152 std::map<GURL, double> score_map; |
171 for (const auto& site : *engagement_settings) { | 153 for (const auto& site : *engagement_settings) { |
172 GURL origin(site.primary_pattern.ToString()); | 154 GURL origin(site.primary_pattern.ToString()); |
173 if (!origin.is_valid()) | 155 if (!origin.is_valid()) |
174 continue; | 156 continue; |
175 | 157 |
176 std::unique_ptr<base::DictionaryValue> score_dict = | 158 const SiteEngagementScore score(GetEngagementScore(origin)); |
177 GetScoreDictForOrigin(settings_map, origin); | |
178 SiteEngagementScore score(clock_.get(), *score_dict); | |
179 score_map[origin] = score.GetScore(); | 159 score_map[origin] = score.GetScore(); |
dominickn
2016/05/25 06:52:43
score_map[origin] = GetScore(origin);
Delete the
calamity
2016/05/26 08:26:20
Done.
| |
180 } | 160 } |
181 | 161 |
182 return score_map; | 162 return score_map; |
183 } | 163 } |
184 | 164 |
185 bool SiteEngagementService::IsBootstrapped() { | 165 bool SiteEngagementService::IsBootstrapped() { |
186 return GetTotalEngagementPoints() >= | 166 return GetTotalEngagementPoints() >= |
187 SiteEngagementScore::GetBootstrapPoints(); | 167 SiteEngagementScore::GetBootstrapPoints(); |
188 } | 168 } |
189 | 169 |
(...skipping 13 matching lines...) Expand all Loading... | |
203 case ENGAGEMENT_LEVEL_HIGH: | 183 case ENGAGEMENT_LEVEL_HIGH: |
204 return score >= SiteEngagementScore::GetHighEngagementBoundary(); | 184 return score >= SiteEngagementScore::GetHighEngagementBoundary(); |
205 case ENGAGEMENT_LEVEL_MAX: | 185 case ENGAGEMENT_LEVEL_MAX: |
206 return score == SiteEngagementScore::kMaxPoints; | 186 return score == SiteEngagementScore::kMaxPoints; |
207 } | 187 } |
208 NOTREACHED(); | 188 NOTREACHED(); |
209 return false; | 189 return false; |
210 } | 190 } |
211 | 191 |
212 void SiteEngagementService::ResetScoreForURL(const GURL& url, double score) { | 192 void SiteEngagementService::ResetScoreForURL(const GURL& url, double score) { |
213 ResetScoreAndAccessTimesForURL(url, score, nullptr); | 193 SiteEngagementScore engagement_score = GetEngagementScore(url); |
194 engagement_score.Reset(score, clock_->Now()); | |
195 engagement_score.Commit(); | |
214 } | 196 } |
215 | 197 |
216 void SiteEngagementService::SetLastShortcutLaunchTime(const GURL& url) { | 198 void SiteEngagementService::SetLastShortcutLaunchTime(const GURL& url) { |
217 HostContentSettingsMap* settings_map = | 199 SiteEngagementScore score = GetEngagementScore(url); |
218 HostContentSettingsMapFactory::GetForProfile(profile_); | |
219 std::unique_ptr<base::DictionaryValue> score_dict = | |
220 GetScoreDictForOrigin(settings_map, url); | |
221 SiteEngagementScore score(clock_.get(), *score_dict); | |
222 | 200 |
223 // Record the number of days since the last launch in UMA. If the user's clock | 201 // Record the number of days since the last launch in UMA. If the user's clock |
224 // has changed back in time, set this to 0. | 202 // has changed back in time, set this to 0. |
225 base::Time now = clock_->Now(); | 203 base::Time now = clock_->Now(); |
226 base::Time last_launch = score.last_shortcut_launch_time(); | 204 base::Time last_launch = score.last_shortcut_launch_time(); |
227 if (!last_launch.is_null()) { | 205 if (!last_launch.is_null()) { |
228 SiteEngagementMetrics::RecordDaysSinceLastShortcutLaunch( | 206 SiteEngagementMetrics::RecordDaysSinceLastShortcutLaunch( |
229 std::max(0, (now - last_launch).InDays())); | 207 std::max(0, (now - last_launch).InDays())); |
230 } | 208 } |
231 SiteEngagementMetrics::RecordEngagement( | 209 SiteEngagementMetrics::RecordEngagement( |
232 SiteEngagementMetrics::ENGAGEMENT_WEBAPP_SHORTCUT_LAUNCH); | 210 SiteEngagementMetrics::ENGAGEMENT_WEBAPP_SHORTCUT_LAUNCH); |
233 | 211 |
234 score.set_last_shortcut_launch_time(now); | 212 score.set_last_shortcut_launch_time(now); |
235 if (score.UpdateScoreDict(score_dict.get())) { | 213 score.Commit(); |
236 settings_map->SetWebsiteSettingDefaultScope( | |
237 url, GURL(), CONTENT_SETTINGS_TYPE_SITE_ENGAGEMENT, std::string(), | |
238 score_dict.release()); | |
239 } | |
240 } | 214 } |
241 | 215 |
242 double SiteEngagementService::GetScore(const GURL& url) const { | 216 double SiteEngagementService::GetScore(const GURL& url) const { |
243 HostContentSettingsMap* settings_map = | 217 return GetEngagementScore(url).GetScore(); |
244 HostContentSettingsMapFactory::GetForProfile(profile_); | |
245 std::unique_ptr<base::DictionaryValue> score_dict = | |
246 GetScoreDictForOrigin(settings_map, url); | |
247 SiteEngagementScore score(clock_.get(), *score_dict); | |
248 | |
249 return score.GetScore(); | |
250 } | 218 } |
251 | 219 |
252 double SiteEngagementService::GetTotalEngagementPoints() const { | 220 double SiteEngagementService::GetTotalEngagementPoints() const { |
253 std::map<GURL, double> score_map = GetScoreMap(); | 221 std::map<GURL, double> score_map = GetScoreMap(); |
254 | 222 |
255 double total_score = 0; | 223 double total_score = 0; |
256 for (const auto& value : score_map) | 224 for (const auto& value : score_map) |
257 total_score += value.second; | 225 total_score += value.second; |
258 | 226 |
259 return total_score; | 227 return total_score; |
260 } | 228 } |
261 | 229 |
262 SiteEngagementService::SiteEngagementService(Profile* profile, | 230 SiteEngagementService::SiteEngagementService(Profile* profile, |
263 std::unique_ptr<base::Clock> clock) | 231 std::unique_ptr<base::Clock> clock) |
264 : profile_(profile), clock_(std::move(clock)), weak_factory_(this) { | 232 : profile_(profile), clock_(std::move(clock)), weak_factory_(this) { |
265 // May be null in tests. | 233 // May be null in tests. |
266 history::HistoryService* history = HistoryServiceFactory::GetForProfile( | 234 history::HistoryService* history = HistoryServiceFactory::GetForProfile( |
267 profile, ServiceAccessType::IMPLICIT_ACCESS); | 235 profile, ServiceAccessType::IMPLICIT_ACCESS); |
268 if (history) | 236 if (history) |
269 history->AddObserver(this); | 237 history->AddObserver(this); |
270 } | 238 } |
271 | 239 |
272 void SiteEngagementService::AddPoints(const GURL& url, double points) { | 240 void SiteEngagementService::AddPoints(const GURL& url, double points) { |
273 HostContentSettingsMap* settings_map = | 241 SiteEngagementScore score = GetEngagementScore(url); |
274 HostContentSettingsMapFactory::GetForProfile(profile_); | |
275 std::unique_ptr<base::DictionaryValue> score_dict = | |
276 GetScoreDictForOrigin(settings_map, url); | |
277 SiteEngagementScore score(clock_.get(), *score_dict); | |
278 | 242 |
279 score.AddPoints(points); | 243 score.AddPoints(points); |
280 if (score.UpdateScoreDict(score_dict.get())) { | 244 score.Commit(); |
281 settings_map->SetWebsiteSettingDefaultScope( | |
282 url, GURL(), CONTENT_SETTINGS_TYPE_SITE_ENGAGEMENT, std::string(), | |
283 score_dict.release()); | |
284 } | |
285 } | 245 } |
286 | 246 |
287 void SiteEngagementService::AfterStartupTask() { | 247 void SiteEngagementService::AfterStartupTask() { |
288 CleanupEngagementScores(); | 248 CleanupEngagementScores(); |
289 RecordMetrics(); | 249 RecordMetrics(); |
290 } | 250 } |
291 | 251 |
292 void SiteEngagementService::CleanupEngagementScores() { | 252 void SiteEngagementService::CleanupEngagementScores() { |
293 HostContentSettingsMap* settings_map = | 253 HostContentSettingsMap* settings_map = |
294 HostContentSettingsMapFactory::GetForProfile(profile_); | 254 HostContentSettingsMapFactory::GetForProfile(profile_); |
295 std::unique_ptr<ContentSettingsForOneType> engagement_settings = | 255 std::unique_ptr<ContentSettingsForOneType> engagement_settings = |
296 GetEngagementContentSettings(settings_map); | 256 GetEngagementContentSettings(settings_map); |
297 | 257 |
298 for (const auto& site : *engagement_settings) { | 258 for (const auto& site : *engagement_settings) { |
299 GURL origin(site.primary_pattern.ToString()); | 259 GURL origin(site.primary_pattern.ToString()); |
300 if (origin.is_valid()) { | 260 if (origin.is_valid()) { |
301 std::unique_ptr<base::DictionaryValue> score_dict = | 261 const SiteEngagementScore score = GetEngagementScore(origin); |
302 GetScoreDictForOrigin(settings_map, origin); | |
303 SiteEngagementScore score(clock_.get(), *score_dict); | |
304 if (score.GetScore() != 0) | 262 if (score.GetScore() != 0) |
dominickn
2016/05/25 06:52:43
if (GetScore(origin) != 0)
Delete the line above.
calamity
2016/05/26 08:26:20
Done.
| |
305 continue; | 263 continue; |
306 } | 264 } |
307 | 265 |
308 settings_map->SetWebsiteSettingDefaultScope( | 266 settings_map->SetWebsiteSettingDefaultScope( |
309 origin, GURL(), CONTENT_SETTINGS_TYPE_SITE_ENGAGEMENT, std::string(), | 267 origin, GURL(), CONTENT_SETTINGS_TYPE_SITE_ENGAGEMENT, std::string(), |
310 nullptr); | 268 nullptr); |
311 } | 269 } |
312 } | 270 } |
313 | 271 |
314 void SiteEngagementService::RecordMetrics() { | 272 void SiteEngagementService::RecordMetrics() { |
(...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
405 | 363 |
406 history::HistoryService* hs = HistoryServiceFactory::GetForProfile( | 364 history::HistoryService* hs = HistoryServiceFactory::GetForProfile( |
407 profile_, ServiceAccessType::EXPLICIT_ACCESS); | 365 profile_, ServiceAccessType::EXPLICIT_ACCESS); |
408 hs->GetCountsAndLastVisitForOrigins( | 366 hs->GetCountsAndLastVisitForOrigins( |
409 std::set<GURL>(origins.begin(), origins.end()), | 367 std::set<GURL>(origins.begin(), origins.end()), |
410 base::Bind( | 368 base::Bind( |
411 &SiteEngagementService::GetCountsAndLastVisitForOriginsComplete, | 369 &SiteEngagementService::GetCountsAndLastVisitForOriginsComplete, |
412 weak_factory_.GetWeakPtr(), hs, origins, expired)); | 370 weak_factory_.GetWeakPtr(), hs, origins, expired)); |
413 } | 371 } |
414 | 372 |
373 SiteEngagementScore SiteEngagementService::GetEngagementScore( | |
374 const GURL& origin) const { | |
375 return SiteEngagementScore( | |
376 clock_.get(), origin, | |
377 HostContentSettingsMapFactory::GetForProfile(profile_)); | |
378 } | |
379 | |
415 int SiteEngagementService::OriginsWithMaxDailyEngagement() const { | 380 int SiteEngagementService::OriginsWithMaxDailyEngagement() const { |
416 HostContentSettingsMap* settings_map = | 381 HostContentSettingsMap* settings_map = |
417 HostContentSettingsMapFactory::GetForProfile(profile_); | 382 HostContentSettingsMapFactory::GetForProfile(profile_); |
418 std::unique_ptr<ContentSettingsForOneType> engagement_settings = | 383 std::unique_ptr<ContentSettingsForOneType> engagement_settings = |
419 GetEngagementContentSettings(settings_map); | 384 GetEngagementContentSettings(settings_map); |
420 | 385 |
421 int total_origins = 0; | 386 int total_origins = 0; |
422 | 387 |
423 // We cannot call GetScoreMap as we need the score objects, not raw scores. | 388 // We cannot call GetScoreMap as we need the score objects, not raw scores. |
424 for (const auto& site : *engagement_settings) { | 389 for (const auto& site : *engagement_settings) { |
425 GURL origin(site.primary_pattern.ToString()); | 390 GURL origin(site.primary_pattern.ToString()); |
426 if (!origin.is_valid()) | 391 if (!origin.is_valid()) |
427 continue; | 392 continue; |
428 | 393 |
429 std::unique_ptr<base::DictionaryValue> score_dict = | 394 const SiteEngagementScore score = GetEngagementScore(origin); |
430 GetScoreDictForOrigin(settings_map, origin); | |
431 SiteEngagementScore score(clock_.get(), *score_dict); | |
432 if (score.MaxPointsPerDayAdded()) | 395 if (score.MaxPointsPerDayAdded()) |
dominickn
2016/05/25 06:52:43
if (GetEngagementScore(origin).MaxPointsPerDayAdde
calamity
2016/05/26 08:26:20
Done.
| |
433 ++total_origins; | 396 ++total_origins; |
434 } | 397 } |
435 | 398 |
436 return total_origins; | 399 return total_origins; |
437 } | 400 } |
438 | 401 |
439 int SiteEngagementService::OriginsWithMaxEngagement( | 402 int SiteEngagementService::OriginsWithMaxEngagement( |
440 const std::map<GURL, double>& score_map) const { | 403 const std::map<GURL, double>& score_map) const { |
441 int total_origins = 0; | 404 int total_origins = 0; |
442 | 405 |
(...skipping 12 matching lines...) Expand all Loading... | |
455 | 418 |
456 // The most in-the-past option in the Clear Browsing Dialog aside from "all | 419 // The most in-the-past option in the Clear Browsing Dialog aside from "all |
457 // time" is 4 weeks ago. Set the last updated date to 4 weeks ago for origins | 420 // time" is 4 weeks ago. Set the last updated date to 4 weeks ago for origins |
458 // where we can't find a valid last visit date. | 421 // where we can't find a valid last visit date. |
459 base::Time now = clock_->Now(); | 422 base::Time now = clock_->Now(); |
460 base::Time four_weeks_ago = | 423 base::Time four_weeks_ago = |
461 now - base::TimeDelta::FromDays(FOUR_WEEKS_IN_DAYS); | 424 now - base::TimeDelta::FromDays(FOUR_WEEKS_IN_DAYS); |
462 | 425 |
463 for (const auto& origin_to_count : remaining_origins) { | 426 for (const auto& origin_to_count : remaining_origins) { |
464 GURL origin = origin_to_count.first; | 427 GURL origin = origin_to_count.first; |
428 // It appears that the history service occasionally sends bad URLs to us. | |
429 // See crbug.com/612881. | |
430 if (!origin.is_valid()) | |
431 return; | |
dominickn
2016/05/25 06:52:43
continue?
calamity
2016/05/26 08:26:20
Done.
| |
432 | |
465 int remaining = origin_to_count.second.first; | 433 int remaining = origin_to_count.second.first; |
466 base::Time last_visit = origin_to_count.second.second; | 434 base::Time last_visit = origin_to_count.second.second; |
467 int deleted = deleted_origins.count(origin); | 435 int deleted = deleted_origins.count(origin); |
468 | 436 |
469 // Do not update engagement scores if the deletion was an expiry, but the | 437 // Do not update engagement scores if the deletion was an expiry, but the |
470 // URL still has entries in history. | 438 // URL still has entries in history. |
471 if ((expired && remaining != 0) || deleted == 0) | 439 if ((expired && remaining != 0) || deleted == 0) |
472 continue; | 440 continue; |
473 | 441 |
474 // Remove engagement proportional to the urls expired from the origin's | 442 // Remove engagement proportional to the urls expired from the origin's |
(...skipping 14 matching lines...) Expand all Loading... | |
489 // reduced value rather than being decayed once here, and then once again | 457 // reduced value rather than being decayed once here, and then once again |
490 // when it is next accessed. | 458 // when it is next accessed. |
491 int undecay = 0; | 459 int undecay = 0; |
492 int days_since_engagement = (now - last_visit).InDays(); | 460 int days_since_engagement = (now - last_visit).InDays(); |
493 if (days_since_engagement > 0) { | 461 if (days_since_engagement > 0) { |
494 int periods = days_since_engagement / | 462 int periods = days_since_engagement / |
495 SiteEngagementScore::GetDecayPeriodInDays(); | 463 SiteEngagementScore::GetDecayPeriodInDays(); |
496 undecay = periods * SiteEngagementScore::GetDecayPoints(); | 464 undecay = periods * SiteEngagementScore::GetDecayPoints(); |
497 } | 465 } |
498 | 466 |
499 double score = | 467 SiteEngagementScore engagement_score = GetEngagementScore(origin); |
500 std::min(SiteEngagementScore::kMaxPoints, | 468 |
501 (proportion_remaining * GetScore(origin)) + undecay); | 469 double score = std::min( |
502 ResetScoreAndAccessTimesForURL(origin, score, &last_visit); | 470 SiteEngagementScore::kMaxPoints, |
471 (proportion_remaining * engagement_score.GetScore()) + undecay); | |
472 engagement_score.Reset(score, last_visit); | |
473 if (!engagement_score.last_shortcut_launch_time().is_null()) | |
474 engagement_score.set_last_shortcut_launch_time(last_visit); | |
dominickn
2016/05/25 06:52:43
if (!engagement_score.last_shortcut_launch_time().
calamity
2016/05/26 08:26:20
Done.
| |
475 | |
476 engagement_score.Commit(); | |
503 } | 477 } |
504 } | 478 } |
505 | |
506 void SiteEngagementService::ResetScoreAndAccessTimesForURL( | |
507 const GURL& url, double score, const base::Time* updated_time) { | |
508 // It appears that the history service occassionally sends bad URLs to us. | |
509 // See crbug.com/612881. | |
510 if (!url.is_valid()) | |
511 return; | |
512 | |
513 DCHECK_GE(score, 0); | |
514 DCHECK_LE(score, SiteEngagementScore::kMaxPoints); | |
515 | |
516 HostContentSettingsMap* settings_map = | |
517 HostContentSettingsMapFactory::GetForProfile(profile_); | |
518 std::unique_ptr<base::DictionaryValue> score_dict = | |
519 GetScoreDictForOrigin(settings_map, url); | |
520 SiteEngagementScore engagement_score(clock_.get(), *score_dict); | |
521 | |
522 engagement_score.Reset(score, updated_time); | |
523 if (score == 0) { | |
524 settings_map->SetWebsiteSettingDefaultScope( | |
525 url, GURL(), CONTENT_SETTINGS_TYPE_SITE_ENGAGEMENT, std::string(), | |
526 nullptr); | |
527 return; | |
528 } | |
529 | |
530 if (engagement_score.UpdateScoreDict(score_dict.get())) { | |
531 settings_map->SetWebsiteSettingDefaultScope( | |
532 url, GURL(), CONTENT_SETTINGS_TYPE_SITE_ENGAGEMENT, std::string(), | |
533 score_dict.release()); | |
534 } | |
535 } | |
OLD | NEW |