Chromium Code Reviews| 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 <cmath> | 10 #include <cmath> |
| (...skipping 18 matching lines...) Expand all Loading... | |
| 29 #include "chrome/common/chrome_switches.h" | 29 #include "chrome/common/chrome_switches.h" |
| 30 #include "components/content_settings/core/browser/host_content_settings_map.h" | 30 #include "components/content_settings/core/browser/host_content_settings_map.h" |
| 31 #include "components/content_settings/core/common/content_settings_pattern.h" | 31 #include "components/content_settings/core/common/content_settings_pattern.h" |
| 32 #include "components/history/core/browser/history_service.h" | 32 #include "components/history/core/browser/history_service.h" |
| 33 #include "components/variations/variations_associated_data.h" | 33 #include "components/variations/variations_associated_data.h" |
| 34 #include "content/public/browser/browser_thread.h" | 34 #include "content/public/browser/browser_thread.h" |
| 35 #include "url/gurl.h" | 35 #include "url/gurl.h" |
| 36 | 36 |
| 37 namespace { | 37 namespace { |
| 38 | 38 |
| 39 const int FOUR_WEEKS_IN_DAYS = 28; | |
| 40 | |
| 39 // Global bool to ensure we only update the parameters from variations once. | 41 // Global bool to ensure we only update the parameters from variations once. |
| 40 bool g_updated_from_variations = false; | 42 bool g_updated_from_variations = false; |
| 41 | 43 |
| 42 // Keys used in the variations params. Order matches | 44 // Keys used in the variations params. Order matches |
| 43 // SiteEngagementScore::Variation enum. | 45 // SiteEngagementScore::Variation enum. |
| 44 const char* kVariationNames[] = { | 46 const char* kVariationNames[] = { |
| 45 "max_points_per_day", | 47 "max_points_per_day", |
| 46 "decay_period_in_days", | 48 "decay_period_in_days", |
| 47 "decay_points", | 49 "decay_points", |
| 48 "navigation_points", | 50 "navigation_points", |
| (...skipping 213 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 262 double to_add = std::min(kMaxPoints - raw_score_, | 264 double to_add = std::min(kMaxPoints - raw_score_, |
| 263 GetMaxPointsPerDay() - points_added_today_); | 265 GetMaxPointsPerDay() - points_added_today_); |
| 264 to_add = std::min(to_add, points); | 266 to_add = std::min(to_add, points); |
| 265 | 267 |
| 266 points_added_today_ += to_add; | 268 points_added_today_ += to_add; |
| 267 raw_score_ += to_add; | 269 raw_score_ += to_add; |
| 268 | 270 |
| 269 last_engagement_time_ = now; | 271 last_engagement_time_ = now; |
| 270 } | 272 } |
| 271 | 273 |
| 272 void SiteEngagementScore::Reset(double points) { | 274 void SiteEngagementScore::Reset(double points, const base::Time* updated_time) { |
| 273 raw_score_ = points; | 275 raw_score_ = points; |
| 274 points_added_today_ = 0; | 276 points_added_today_ = 0; |
| 275 | 277 |
| 276 // This must be set in order to prevent the score from decaying when read. | 278 // This must be set in order to prevent the score from decaying when read. |
| 277 last_engagement_time_ = clock_->Now(); | 279 if (updated_time) { |
| 280 last_engagement_time_ = *updated_time; | |
| 281 if (!last_shortcut_launch_time_.is_null()) | |
| 282 last_shortcut_launch_time_ = *updated_time; | |
| 283 } else { | |
| 284 last_engagement_time_ = clock_->Now(); | |
| 285 } | |
| 278 } | 286 } |
| 279 | 287 |
| 280 bool SiteEngagementScore::MaxPointsPerDayAdded() const { | 288 bool SiteEngagementScore::MaxPointsPerDayAdded() const { |
| 281 if (!last_engagement_time_.is_null() && | 289 if (!last_engagement_time_.is_null() && |
| 282 clock_->Now().LocalMidnight() != last_engagement_time_.LocalMidnight()) { | 290 clock_->Now().LocalMidnight() != last_engagement_time_.LocalMidnight()) { |
| 283 return false; | 291 return false; |
| 284 } | 292 } |
| 285 | 293 |
| 286 return points_added_today_ == GetMaxPointsPerDay(); | 294 return points_added_today_ == GetMaxPointsPerDay(); |
| 287 } | 295 } |
| (...skipping 152 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 440 bool is_hidden) { | 448 bool is_hidden) { |
| 441 SiteEngagementMetrics::RecordEngagement( | 449 SiteEngagementMetrics::RecordEngagement( |
| 442 is_hidden ? SiteEngagementMetrics::ENGAGEMENT_MEDIA_HIDDEN | 450 is_hidden ? SiteEngagementMetrics::ENGAGEMENT_MEDIA_HIDDEN |
| 443 : SiteEngagementMetrics::ENGAGEMENT_MEDIA_VISIBLE); | 451 : SiteEngagementMetrics::ENGAGEMENT_MEDIA_VISIBLE); |
| 444 AddPoints(url, is_hidden ? SiteEngagementScore::GetHiddenMediaPoints() | 452 AddPoints(url, is_hidden ? SiteEngagementScore::GetHiddenMediaPoints() |
| 445 : SiteEngagementScore::GetVisibleMediaPoints()); | 453 : SiteEngagementScore::GetVisibleMediaPoints()); |
| 446 RecordMetrics(); | 454 RecordMetrics(); |
| 447 } | 455 } |
| 448 | 456 |
| 449 void SiteEngagementService::ResetScoreForURL(const GURL& url, double score) { | 457 void SiteEngagementService::ResetScoreForURL(const GURL& url, double score) { |
| 450 DCHECK(url.is_valid()); | 458 ResetScoreAndAccessTimesForURL(url, score, nullptr); |
| 451 DCHECK_GE(score, 0); | |
| 452 DCHECK_LE(score, SiteEngagementScore::kMaxPoints); | |
| 453 | |
| 454 HostContentSettingsMap* settings_map = | |
| 455 HostContentSettingsMapFactory::GetForProfile(profile_); | |
| 456 std::unique_ptr<base::DictionaryValue> score_dict = | |
| 457 GetScoreDictForOrigin(settings_map, url); | |
| 458 SiteEngagementScore engagement_score(clock_.get(), *score_dict); | |
| 459 | |
| 460 engagement_score.Reset(score); | |
| 461 if (score == 0) { | |
| 462 settings_map->SetWebsiteSettingDefaultScope( | |
| 463 url, GURL(), CONTENT_SETTINGS_TYPE_SITE_ENGAGEMENT, std::string(), | |
| 464 nullptr); | |
| 465 return; | |
| 466 } | |
| 467 | |
| 468 if (engagement_score.UpdateScoreDict(score_dict.get())) { | |
| 469 settings_map->SetWebsiteSettingDefaultScope( | |
| 470 url, GURL(), CONTENT_SETTINGS_TYPE_SITE_ENGAGEMENT, std::string(), | |
| 471 score_dict.release()); | |
| 472 } | |
| 473 } | 459 } |
| 474 | 460 |
| 475 void SiteEngagementService::OnURLsDeleted( | 461 void SiteEngagementService::OnURLsDeleted( |
| 476 history::HistoryService* history_service, | 462 history::HistoryService* history_service, |
| 477 bool all_history, | 463 bool all_history, |
| 478 bool expired, | 464 bool expired, |
| 479 const history::URLRows& deleted_rows, | 465 const history::URLRows& deleted_rows, |
| 480 const std::set<GURL>& favicon_urls) { | 466 const std::set<GURL>& favicon_urls) { |
| 481 std::multiset<GURL> origins; | 467 std::multiset<GURL> origins; |
| 482 for (const history::URLRow& row : deleted_rows) | 468 for (const history::URLRow& row : deleted_rows) |
| 483 origins.insert(row.url().GetOrigin()); | 469 origins.insert(row.url().GetOrigin()); |
| 484 | 470 |
| 485 history::HistoryService* hs = HistoryServiceFactory::GetForProfile( | 471 history::HistoryService* hs = HistoryServiceFactory::GetForProfile( |
| 486 profile_, ServiceAccessType::EXPLICIT_ACCESS); | 472 profile_, ServiceAccessType::EXPLICIT_ACCESS); |
| 487 hs->GetCountsForOrigins( | 473 hs->GetCountsAndLastVisitForOrigins( |
| 488 std::set<GURL>(origins.begin(), origins.end()), | 474 std::set<GURL>(origins.begin(), origins.end()), |
| 489 base::Bind(&SiteEngagementService::GetCountsForOriginsComplete, | 475 base::Bind( |
| 490 weak_factory_.GetWeakPtr(), origins, expired)); | 476 &SiteEngagementService::GetCountsAndLastVisitForOriginsComplete, |
| 477 weak_factory_.GetWeakPtr(), hs, origins, expired)); | |
| 491 } | 478 } |
| 492 | 479 |
| 493 void SiteEngagementService::SetLastShortcutLaunchTime(const GURL& url) { | 480 void SiteEngagementService::SetLastShortcutLaunchTime(const GURL& url) { |
| 494 HostContentSettingsMap* settings_map = | 481 HostContentSettingsMap* settings_map = |
| 495 HostContentSettingsMapFactory::GetForProfile(profile_); | 482 HostContentSettingsMapFactory::GetForProfile(profile_); |
| 496 std::unique_ptr<base::DictionaryValue> score_dict = | 483 std::unique_ptr<base::DictionaryValue> score_dict = |
| 497 GetScoreDictForOrigin(settings_map, url); | 484 GetScoreDictForOrigin(settings_map, url); |
| 498 SiteEngagementScore score(clock_.get(), *score_dict); | 485 SiteEngagementScore score(clock_.get(), *score_dict); |
| 499 | 486 |
| 500 // Record the number of days since the last launch in UMA. If the user's clock | 487 // Record the number of days since the last launch in UMA. If the user's clock |
| (...skipping 237 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 738 const std::map<GURL, double>& score_map) const { | 725 const std::map<GURL, double>& score_map) const { |
| 739 int total_origins = 0; | 726 int total_origins = 0; |
| 740 | 727 |
| 741 for (const auto& value : score_map) | 728 for (const auto& value : score_map) |
| 742 if (value.second == SiteEngagementScore::kMaxPoints) | 729 if (value.second == SiteEngagementScore::kMaxPoints) |
| 743 ++total_origins; | 730 ++total_origins; |
| 744 | 731 |
| 745 return total_origins; | 732 return total_origins; |
| 746 } | 733 } |
| 747 | 734 |
| 748 void SiteEngagementService::GetCountsForOriginsComplete( | 735 void SiteEngagementService::GetCountsAndLastVisitForOriginsComplete( |
| 736 history::HistoryService* history_service, | |
| 749 const std::multiset<GURL>& deleted_origins, | 737 const std::multiset<GURL>& deleted_origins, |
| 750 bool expired, | 738 bool expired, |
| 751 const history::OriginCountMap& remaining_origins) { | 739 const history::OriginCountMap& remaining_origins) { |
| 740 | |
| 741 // The most in-the-past option in the Clear Browsing Dialog aside from "all | |
| 742 // time" is 4 weeks ago. Set the last updated date to 4 weeks ago for origins | |
| 743 // where we can't find a valid last visit date. | |
| 744 base::Time now = clock_->Now(); | |
| 745 base::Time four_weeks_ago = | |
| 746 now - base::TimeDelta::FromDays(FOUR_WEEKS_IN_DAYS); | |
| 747 | |
| 752 for (const auto& origin_to_count : remaining_origins) { | 748 for (const auto& origin_to_count : remaining_origins) { |
| 753 GURL origin = origin_to_count.first; | 749 GURL origin = origin_to_count.first; |
| 754 int remaining = origin_to_count.second; | 750 int remaining = origin_to_count.second.first; |
| 751 base::Time last_visit = origin_to_count.second.second; | |
| 755 int deleted = deleted_origins.count(origin); | 752 int deleted = deleted_origins.count(origin); |
| 756 | 753 |
| 757 // Do not update engagement scores if the deletion was an expiry, but the | 754 // Do not update engagement scores if the deletion was an expiry, but the |
| 758 // URL still has entries in history. | 755 // URL still has entries in history. |
| 759 if ((expired && remaining != 0) || deleted == 0) | 756 if ((expired && remaining != 0) || deleted == 0) |
| 760 continue; | 757 continue; |
| 761 | 758 |
| 759 if (last_visit.is_null() || last_visit > now) | |
| 760 last_visit = four_weeks_ago; | |
| 761 | |
| 762 // At this point, we are going to proportionally decay the origin's | |
| 763 // engagement, and reset its last visit date to the last visit to a URL | |
| 764 // under the origin in history. If this new last visit date is long enough | |
| 765 // in the past, the next time the origin's engagement is accessed the | |
| 766 // automatic decay will kick in - i.e. a double decay will have occurred. | |
| 767 // To prevent this, compute the decay that would have taken place since the | |
| 768 // new last visit and add it to the engagement at this point. When the | |
| 769 // engagement is next accessed, it will decay back to the proportionally | |
| 770 // reduced value rather than being decayed once here, and then once again | |
| 771 // when it is next accessed. | |
| 772 int undecay = 0; | |
| 773 int days_since_engagement = (now - last_visit).InDays(); | |
| 774 if (days_since_engagement > 0) { | |
| 775 int periods = days_since_engagement / | |
| 776 SiteEngagementScore::GetDecayPeriodInDays(); | |
| 777 undecay = periods * SiteEngagementScore::GetDecayPoints(); | |
| 778 } | |
| 779 | |
| 762 // Remove engagement proportional to the urls expired from the origin's | 780 // Remove engagement proportional to the urls expired from the origin's |
| 763 // entire history. | 781 // entire history. |
| 764 double proportion_remaining = | 782 double proportion_remaining = |
| 765 static_cast<double>(remaining) / (remaining + deleted); | 783 static_cast<double>(remaining) / (remaining + deleted); |
|
benwells
2016/04/19 07:28:19
Nit: move proportion_remaining calculation up to l
dominickn
2016/04/19 07:59:32
Done.
| |
| 766 ResetScoreForURL(origin, proportion_remaining * GetScore(origin)); | 784 ResetScoreAndAccessTimesForURL( |
| 785 origin, (proportion_remaining * GetScore(origin)) + undecay, | |
| 786 &last_visit); | |
| 767 } | 787 } |
| 768 } | 788 } |
| 789 | |
| 790 void SiteEngagementService::ResetScoreAndAccessTimesForURL( | |
| 791 const GURL& url, double score, const base::Time* updated_time) { | |
| 792 DCHECK(url.is_valid()); | |
| 793 DCHECK_GE(score, 0); | |
| 794 DCHECK_LE(score, SiteEngagementScore::kMaxPoints); | |
|
benwells
2016/04/19 07:28:19
Should it be impossible for this DCHECK to fire? I
dominickn
2016/04/19 07:59:32
Good point. Done.
| |
| 795 | |
| 796 HostContentSettingsMap* settings_map = | |
| 797 HostContentSettingsMapFactory::GetForProfile(profile_); | |
| 798 std::unique_ptr<base::DictionaryValue> score_dict = | |
| 799 GetScoreDictForOrigin(settings_map, url); | |
| 800 SiteEngagementScore engagement_score(clock_.get(), *score_dict); | |
| 801 | |
| 802 engagement_score.Reset(score, updated_time); | |
| 803 if (score == 0) { | |
| 804 settings_map->SetWebsiteSettingDefaultScope( | |
| 805 url, GURL(), CONTENT_SETTINGS_TYPE_SITE_ENGAGEMENT, std::string(), | |
| 806 nullptr); | |
| 807 return; | |
| 808 } | |
| 809 | |
| 810 if (engagement_score.UpdateScoreDict(score_dict.get())) { | |
| 811 settings_map->SetWebsiteSettingDefaultScope( | |
| 812 url, GURL(), CONTENT_SETTINGS_TYPE_SITE_ENGAGEMENT, std::string(), | |
| 813 score_dict.release()); | |
| 814 } | |
| 815 } | |
| OLD | NEW |