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