| 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> |
| 11 #include <vector> | |
| 12 | 11 |
| 13 #include "base/command_line.h" | 12 #include "base/command_line.h" |
| 14 #include "base/memory/ptr_util.h" | 13 #include "base/memory/ptr_util.h" |
| 15 #include "base/metrics/field_trial.h" | 14 #include "base/metrics/field_trial.h" |
| 16 #include "base/strings/string_util.h" | 15 #include "base/strings/string_util.h" |
| 17 #include "base/time/clock.h" | 16 #include "base/time/clock.h" |
| 18 #include "base/time/default_clock.h" | 17 #include "base/time/default_clock.h" |
| 19 #include "base/time/time.h" | 18 #include "base/time/time.h" |
| 20 #include "base/values.h" | 19 #include "base/values.h" |
| 21 #include "chrome/browser/banners/app_banner_settings_helper.h" | 20 #include "chrome/browser/banners/app_banner_settings_helper.h" |
| (...skipping 23 matching lines...) Expand all Loading... |
| 45 namespace { | 44 namespace { |
| 46 | 45 |
| 47 const int FOUR_WEEKS_IN_DAYS = 28; | 46 const int FOUR_WEEKS_IN_DAYS = 28; |
| 48 | 47 |
| 49 // Global bool to ensure we only update the parameters from variations once. | 48 // Global bool to ensure we only update the parameters from variations once. |
| 50 bool g_updated_from_variations = false; | 49 bool g_updated_from_variations = false; |
| 51 | 50 |
| 52 // Length of time between metrics logging. | 51 // Length of time between metrics logging. |
| 53 const int kMetricsIntervalInMinutes = 60; | 52 const int kMetricsIntervalInMinutes = 60; |
| 54 | 53 |
| 55 std::unique_ptr<ContentSettingsForOneType> GetEngagementContentSettings( | 54 // Helper for fetching content settings for one type. |
| 56 HostContentSettingsMap* settings_map) { | 55 ContentSettingsForOneType GetContentSettingsFromProfile( |
| 57 std::unique_ptr<ContentSettingsForOneType> engagement_settings( | 56 Profile* profile, |
| 58 new ContentSettingsForOneType); | 57 ContentSettingsType type) { |
| 59 settings_map->GetSettingsForOneType(CONTENT_SETTINGS_TYPE_SITE_ENGAGEMENT, | 58 ContentSettingsForOneType content_settings; |
| 60 std::string(), engagement_settings.get()); | 59 HostContentSettingsMapFactory::GetForProfile(profile)->GetSettingsForOneType( |
| 61 return engagement_settings; | 60 type, content_settings::ResourceIdentifier(), &content_settings); |
| 61 return content_settings; |
| 62 } |
| 63 |
| 64 // Returns the combined list of origins which either have site engagement |
| 65 // data stored, or have other settings that would provide a score bonus. |
| 66 std::set<GURL> GetEngagementOriginsFromContentSettings(Profile* profile) { |
| 67 std::set<GURL> urls; |
| 68 |
| 69 // Fetch URLs of sites with engagement details stored. |
| 70 for (const auto& site : GetContentSettingsFromProfile( |
| 71 profile, CONTENT_SETTINGS_TYPE_SITE_ENGAGEMENT)) { |
| 72 urls.insert(GURL(site.primary_pattern.ToString())); |
| 73 } |
| 74 |
| 75 // Fetch URLs of sites for which notifications are allowed. |
| 76 for (const auto& site : GetContentSettingsFromProfile( |
| 77 profile, CONTENT_SETTINGS_TYPE_NOTIFICATIONS)) { |
| 78 if (site.setting != CONTENT_SETTING_ALLOW) |
| 79 continue; |
| 80 urls.insert(GURL(site.primary_pattern.ToString())); |
| 81 } |
| 82 |
| 83 return urls; |
| 62 } | 84 } |
| 63 | 85 |
| 64 // Only accept a navigation event for engagement if it is one of: | 86 // Only accept a navigation event for engagement if it is one of: |
| 65 // a. direct typed navigation | 87 // a. direct typed navigation |
| 66 // b. clicking on an omnibox suggestion brought up by typing a keyword | 88 // b. clicking on an omnibox suggestion brought up by typing a keyword |
| 67 // c. clicking on a bookmark or opening a bookmark app | 89 // c. clicking on a bookmark or opening a bookmark app |
| 68 // d. a custom search engine keyword search (e.g. Wikipedia search box added as | 90 // d. a custom search engine keyword search (e.g. Wikipedia search box added as |
| 69 // search engine). | 91 // search engine). |
| 70 bool IsEngagementNavigation(ui::PageTransition transition) { | 92 bool IsEngagementNavigation(ui::PageTransition transition) { |
| 71 return ui::PageTransitionCoreTypeIs(transition, ui::PAGE_TRANSITION_TYPED) || | 93 return ui::PageTransitionCoreTypeIs(transition, ui::PAGE_TRANSITION_TYPED) || |
| (...skipping 25 matching lines...) Expand all Loading... |
| 97 base::FieldTrialList::FindFullName(kEngagementParams); | 119 base::FieldTrialList::FindFullName(kEngagementParams); |
| 98 return !base::StartsWith(group_name, "Disabled", | 120 return !base::StartsWith(group_name, "Disabled", |
| 99 base::CompareCase::SENSITIVE); | 121 base::CompareCase::SENSITIVE); |
| 100 } | 122 } |
| 101 | 123 |
| 102 // static | 124 // static |
| 103 double SiteEngagementService::GetScoreFromSettings( | 125 double SiteEngagementService::GetScoreFromSettings( |
| 104 HostContentSettingsMap* settings, | 126 HostContentSettingsMap* settings, |
| 105 const GURL& origin) { | 127 const GURL& origin) { |
| 106 auto clock = base::MakeUnique<base::DefaultClock>(); | 128 auto clock = base::MakeUnique<base::DefaultClock>(); |
| 107 return SiteEngagementScore(clock.get(), origin, settings) | 129 return SiteEngagementScore(clock.get(), origin, settings).GetTotalScore(); |
| 108 .GetScore(); | |
| 109 } | 130 } |
| 110 | 131 |
| 111 SiteEngagementService::SiteEngagementService(Profile* profile) | 132 SiteEngagementService::SiteEngagementService(Profile* profile) |
| 112 : SiteEngagementService(profile, base::MakeUnique<base::DefaultClock>()) { | 133 : SiteEngagementService(profile, base::MakeUnique<base::DefaultClock>()) { |
| 113 content::BrowserThread::PostAfterStartupTask( | 134 content::BrowserThread::PostAfterStartupTask( |
| 114 FROM_HERE, content::BrowserThread::GetTaskRunnerForThread( | 135 FROM_HERE, content::BrowserThread::GetTaskRunnerForThread( |
| 115 content::BrowserThread::UI), | 136 content::BrowserThread::UI), |
| 116 base::Bind(&SiteEngagementService::AfterStartupTask, | 137 base::Bind(&SiteEngagementService::AfterStartupTask, |
| 117 weak_factory_.GetWeakPtr())); | 138 weak_factory_.GetWeakPtr())); |
| 118 | 139 |
| (...skipping 13 matching lines...) Expand all Loading... |
| 132 } | 153 } |
| 133 | 154 |
| 134 blink::mojom::EngagementLevel | 155 blink::mojom::EngagementLevel |
| 135 SiteEngagementService::GetEngagementLevel(const GURL& url) const { | 156 SiteEngagementService::GetEngagementLevel(const GURL& url) const { |
| 136 if (IsLastEngagementStale()) | 157 if (IsLastEngagementStale()) |
| 137 CleanupEngagementScores(true); | 158 CleanupEngagementScores(true); |
| 138 | 159 |
| 139 return CreateEngagementScore(url).GetEngagementLevel(); | 160 return CreateEngagementScore(url).GetEngagementLevel(); |
| 140 } | 161 } |
| 141 | 162 |
| 142 std::map<GURL, double> SiteEngagementService::GetScoreMap() const { | 163 std::vector<mojom::SiteEngagementDetails> SiteEngagementService::GetAllDetails() |
| 143 HostContentSettingsMap* settings_map = | 164 const { |
| 144 HostContentSettingsMapFactory::GetForProfile(profile_); | 165 std::set<GURL> origins = GetEngagementOriginsFromContentSettings(profile_); |
| 145 std::unique_ptr<ContentSettingsForOneType> engagement_settings = | |
| 146 GetEngagementContentSettings(settings_map); | |
| 147 | 166 |
| 148 std::map<GURL, double> score_map; | 167 std::vector<mojom::SiteEngagementDetails> details; |
| 149 for (const auto& site : *engagement_settings) { | 168 details.reserve(origins.size()); |
| 150 GURL origin(site.primary_pattern.ToString()); | 169 for (const GURL& origin : origins) { |
| 151 if (!origin.is_valid()) | 170 if (!origin.is_valid()) |
| 152 continue; | 171 continue; |
| 172 details.push_back(GetDetails(origin)); |
| 173 } |
| 153 | 174 |
| 175 return details; |
| 176 } |
| 177 |
| 178 std::map<GURL, double> SiteEngagementService::GetScoreMap() const { |
| 179 std::map<GURL, double> score_map; |
| 180 for (const GURL& origin : GetEngagementOriginsFromContentSettings(profile_)) { |
| 181 if (!origin.is_valid()) |
| 182 continue; |
| 154 score_map[origin] = GetScore(origin); | 183 score_map[origin] = GetScore(origin); |
| 155 } | 184 } |
| 156 | |
| 157 return score_map; | 185 return score_map; |
| 158 } | 186 } |
| 159 | 187 |
| 160 void SiteEngagementService::HandleNotificationInteraction(const GURL& url) { | 188 void SiteEngagementService::HandleNotificationInteraction(const GURL& url) { |
| 161 if (!ShouldRecordEngagement(url)) | 189 if (!ShouldRecordEngagement(url)) |
| 162 return; | 190 return; |
| 163 | 191 |
| 164 SiteEngagementMetrics::RecordEngagement( | 192 SiteEngagementMetrics::RecordEngagement( |
| 165 SiteEngagementMetrics::ENGAGEMENT_NOTIFICATION_INTERACTION); | 193 SiteEngagementMetrics::ENGAGEMENT_NOTIFICATION_INTERACTION); |
| 166 AddPoints(url, SiteEngagementScore::GetNotificationInteractionPoints()); | 194 AddPoints(url, SiteEngagementScore::GetNotificationInteractionPoints()); |
| (...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 237 SiteEngagementService::Helper* helper) { | 265 SiteEngagementService::Helper* helper) { |
| 238 helpers_.insert(helper); | 266 helpers_.insert(helper); |
| 239 } | 267 } |
| 240 | 268 |
| 241 void SiteEngagementService::HelperDeleted( | 269 void SiteEngagementService::HelperDeleted( |
| 242 SiteEngagementService::Helper* helper) { | 270 SiteEngagementService::Helper* helper) { |
| 243 helpers_.erase(helper); | 271 helpers_.erase(helper); |
| 244 } | 272 } |
| 245 | 273 |
| 246 double SiteEngagementService::GetScore(const GURL& url) const { | 274 double SiteEngagementService::GetScore(const GURL& url) const { |
| 275 return GetDetails(url).total_score; |
| 276 } |
| 277 |
| 278 mojom::SiteEngagementDetails SiteEngagementService::GetDetails( |
| 279 const GURL& url) const { |
| 247 // Ensure that if engagement is stale, we clean things up before fetching the | 280 // Ensure that if engagement is stale, we clean things up before fetching the |
| 248 // score. | 281 // score. |
| 249 if (IsLastEngagementStale()) | 282 if (IsLastEngagementStale()) |
| 250 CleanupEngagementScores(true); | 283 CleanupEngagementScores(true); |
| 251 | 284 |
| 252 return CreateEngagementScore(url).GetScore(); | 285 return CreateEngagementScore(url).GetDetails(); |
| 253 } | 286 } |
| 254 | 287 |
| 255 double SiteEngagementService::GetTotalEngagementPoints() const { | 288 double SiteEngagementService::GetTotalEngagementPoints() const { |
| 256 std::map<GURL, double> score_map = GetScoreMap(); | 289 std::map<GURL, double> score_map = GetScoreMap(); |
| 257 | 290 |
| 258 double total_score = 0; | 291 double total_score = 0; |
| 259 for (const auto& value : score_map) | 292 for (const auto& value : score_map) |
| 260 total_score += value.second; | 293 total_score += value.second; |
| 261 | 294 |
| 262 return total_score; | 295 return total_score; |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 310 // Check if we need to reset last engagement times on startup - we want to | 343 // Check if we need to reset last engagement times on startup - we want to |
| 311 // avoid doing this in AddPoints() if possible. It is still necessary to check | 344 // avoid doing this in AddPoints() if possible. It is still necessary to check |
| 312 // in AddPoints for people who never restart Chrome, but leave it open and | 345 // in AddPoints for people who never restart Chrome, but leave it open and |
| 313 // their computer on standby. | 346 // their computer on standby. |
| 314 CleanupEngagementScores(IsLastEngagementStale()); | 347 CleanupEngagementScores(IsLastEngagementStale()); |
| 315 RecordMetrics(); | 348 RecordMetrics(); |
| 316 } | 349 } |
| 317 | 350 |
| 318 void SiteEngagementService::CleanupEngagementScores( | 351 void SiteEngagementService::CleanupEngagementScores( |
| 319 bool update_last_engagement_time) const { | 352 bool update_last_engagement_time) const { |
| 320 HostContentSettingsMap* settings_map = | |
| 321 HostContentSettingsMapFactory::GetForProfile(profile_); | |
| 322 std::unique_ptr<ContentSettingsForOneType> engagement_settings = | |
| 323 GetEngagementContentSettings(settings_map); | |
| 324 | |
| 325 // We want to rebase last engagement times relative to MaxDecaysPerScore | 353 // We want to rebase last engagement times relative to MaxDecaysPerScore |
| 326 // periods of decay in the past. | 354 // periods of decay in the past. |
| 327 base::Time now = clock_->Now(); | 355 base::Time now = clock_->Now(); |
| 328 base::Time last_engagement_time = GetLastEngagementTime(); | 356 base::Time last_engagement_time = GetLastEngagementTime(); |
| 329 base::Time rebase_time = now - GetMaxDecayPeriod(); | 357 base::Time rebase_time = now - GetMaxDecayPeriod(); |
| 330 base::Time new_last_engagement_time; | 358 base::Time new_last_engagement_time; |
| 331 | 359 |
| 332 // If |update_last_engagement_time| is true, we must have either: | 360 // If |update_last_engagement_time| is true, we must have either: |
| 333 // a) last_engagement_time is in the future; OR | 361 // a) last_engagement_time is in the future; OR |
| 334 // b) last_engagement_time < rebase_time < now | 362 // b) last_engagement_time < rebase_time < now |
| 335 DCHECK(!update_last_engagement_time || last_engagement_time >= now || | 363 DCHECK(!update_last_engagement_time || last_engagement_time >= now || |
| 336 (last_engagement_time < rebase_time && rebase_time < now)); | 364 (last_engagement_time < rebase_time && rebase_time < now)); |
| 337 | 365 |
| 338 // Cap |last_engagement_time| at |now| if it is in the future. This ensures | 366 // Cap |last_engagement_time| at |now| if it is in the future. This ensures |
| 339 // that we use sane offsets when a user has adjusted their clock backwards and | 367 // that we use sane offsets when a user has adjusted their clock backwards and |
| 340 // have a mix of scores prior to and after |now|. | 368 // have a mix of scores prior to and after |now|. |
| 341 if (last_engagement_time > now) | 369 if (last_engagement_time > now) |
| 342 last_engagement_time = now; | 370 last_engagement_time = now; |
| 343 | 371 |
| 344 for (const auto& site : *engagement_settings) { | 372 HostContentSettingsMap* settings_map = |
| 373 HostContentSettingsMapFactory::GetForProfile(profile_); |
| 374 for (const auto& site : GetContentSettingsFromProfile( |
| 375 profile_, CONTENT_SETTINGS_TYPE_SITE_ENGAGEMENT)) { |
| 345 GURL origin(site.primary_pattern.ToString()); | 376 GURL origin(site.primary_pattern.ToString()); |
| 346 | 377 |
| 347 if (origin.is_valid()) { | 378 if (origin.is_valid()) { |
| 348 SiteEngagementScore score = CreateEngagementScore(origin); | 379 SiteEngagementScore score = CreateEngagementScore(origin); |
| 349 if (update_last_engagement_time) { | 380 if (update_last_engagement_time) { |
| 350 // Catch cases of users moving their clocks, or a potential race where | 381 // Catch cases of users moving their clocks, or a potential race where |
| 351 // a score content setting is written out to prefs, but the updated | 382 // a score content setting is written out to prefs, but the updated |
| 352 // |last_engagement_time| was not written, as both are lossy | 383 // |last_engagement_time| was not written, as both are lossy |
| 353 // preferences. |rebase_time| is strictly in the past, so any score with | 384 // preferences. |rebase_time| is strictly in the past, so any score with |
| 354 // a last updated time in the future is caught by this branch. | 385 // a last updated time in the future is caught by this branch. |
| (...skipping 14 matching lines...) Expand all Loading... |
| 369 last_engagement_time - score.last_engagement_time(); | 400 last_engagement_time - score.last_engagement_time(); |
| 370 base::Time rebase_score_time = rebase_time - offset; | 401 base::Time rebase_score_time = rebase_time - offset; |
| 371 score.set_last_engagement_time(rebase_score_time); | 402 score.set_last_engagement_time(rebase_score_time); |
| 372 } | 403 } |
| 373 | 404 |
| 374 if (score.last_engagement_time() > new_last_engagement_time) | 405 if (score.last_engagement_time() > new_last_engagement_time) |
| 375 new_last_engagement_time = score.last_engagement_time(); | 406 new_last_engagement_time = score.last_engagement_time(); |
| 376 score.Commit(); | 407 score.Commit(); |
| 377 } | 408 } |
| 378 | 409 |
| 379 if (score.GetScore() > SiteEngagementScore::GetScoreCleanupThreshold()) | 410 if (score.GetTotalScore() > |
| 411 SiteEngagementScore::GetScoreCleanupThreshold()) |
| 380 continue; | 412 continue; |
| 381 } | 413 } |
| 382 | 414 |
| 383 // This origin has a score of 0. Wipe it from content settings. | 415 // This origin has a score of 0. Wipe it from content settings. |
| 384 settings_map->SetWebsiteSettingDefaultScope( | 416 settings_map->SetWebsiteSettingDefaultScope( |
| 385 origin, GURL(), CONTENT_SETTINGS_TYPE_SITE_ENGAGEMENT, std::string(), | 417 origin, GURL(), CONTENT_SETTINGS_TYPE_SITE_ENGAGEMENT, |
| 386 nullptr); | 418 content_settings::ResourceIdentifier(), nullptr); |
| 387 } | 419 } |
| 388 | 420 |
| 389 // Set the last engagement time to be consistent with the scores. This will | 421 // Set the last engagement time to be consistent with the scores. This will |
| 390 // only occur if |update_last_engagement_time| is true. | 422 // only occur if |update_last_engagement_time| is true. |
| 391 if (!new_last_engagement_time.is_null()) | 423 if (!new_last_engagement_time.is_null()) |
| 392 SetLastEngagementTime(new_last_engagement_time); | 424 SetLastEngagementTime(new_last_engagement_time); |
| 393 } | 425 } |
| 394 | 426 |
| 395 void SiteEngagementService::RecordMetrics() { | 427 void SiteEngagementService::RecordMetrics() { |
| 396 base::Time now = clock_->Now(); | 428 base::Time now = clock_->Now(); |
| (...skipping 173 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 570 const GURL& origin) const { | 602 const GURL& origin) const { |
| 571 // If we are in incognito, |settings| will automatically have the data from | 603 // If we are in incognito, |settings| will automatically have the data from |
| 572 // the original profile migrated in, so all engagement scores in incognito | 604 // the original profile migrated in, so all engagement scores in incognito |
| 573 // will be initialised to the values from the original profile. | 605 // will be initialised to the values from the original profile. |
| 574 return SiteEngagementScore( | 606 return SiteEngagementScore( |
| 575 clock_.get(), origin, | 607 clock_.get(), origin, |
| 576 HostContentSettingsMapFactory::GetForProfile(profile_)); | 608 HostContentSettingsMapFactory::GetForProfile(profile_)); |
| 577 } | 609 } |
| 578 | 610 |
| 579 int SiteEngagementService::OriginsWithMaxDailyEngagement() const { | 611 int SiteEngagementService::OriginsWithMaxDailyEngagement() const { |
| 580 HostContentSettingsMap* settings_map = | |
| 581 HostContentSettingsMapFactory::GetForProfile(profile_); | |
| 582 std::unique_ptr<ContentSettingsForOneType> engagement_settings = | |
| 583 GetEngagementContentSettings(settings_map); | |
| 584 | |
| 585 int total_origins = 0; | 612 int total_origins = 0; |
| 586 | 613 |
| 587 // We cannot call GetScoreMap as we need the score objects, not raw scores. | 614 // We cannot call GetScoreMap as we need the score objects, not raw scores. |
| 588 for (const auto& site : *engagement_settings) { | 615 for (const auto& site : GetContentSettingsFromProfile( |
| 616 profile_, CONTENT_SETTINGS_TYPE_SITE_ENGAGEMENT)) { |
| 589 GURL origin(site.primary_pattern.ToString()); | 617 GURL origin(site.primary_pattern.ToString()); |
| 618 |
| 590 if (!origin.is_valid()) | 619 if (!origin.is_valid()) |
| 591 continue; | 620 continue; |
| 592 | 621 |
| 593 if (CreateEngagementScore(origin).MaxPointsPerDayAdded()) | 622 if (CreateEngagementScore(origin).MaxPointsPerDayAdded()) |
| 594 ++total_origins; | 623 ++total_origins; |
| 595 } | 624 } |
| 596 | 625 |
| 597 return total_origins; | 626 return total_origins; |
| 598 } | 627 } |
| 599 | 628 |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 646 // At this point, we are going to proportionally decay the origin's | 675 // At this point, we are going to proportionally decay the origin's |
| 647 // engagement, and reset its last visit date to the last visit to a URL | 676 // engagement, and reset its last visit date to the last visit to a URL |
| 648 // under the origin in history. If this new last visit date is long enough | 677 // under the origin in history. If this new last visit date is long enough |
| 649 // in the past, the next time the origin's engagement is accessed the | 678 // in the past, the next time the origin's engagement is accessed the |
| 650 // automatic decay will kick in - i.e. a double decay will have occurred. | 679 // automatic decay will kick in - i.e. a double decay will have occurred. |
| 651 // To prevent this, compute the decay that would have taken place since the | 680 // To prevent this, compute the decay that would have taken place since the |
| 652 // new last visit and add it to the engagement at this point. When the | 681 // new last visit and add it to the engagement at this point. When the |
| 653 // engagement is next accessed, it will decay back to the proportionally | 682 // engagement is next accessed, it will decay back to the proportionally |
| 654 // reduced value rather than being decayed once here, and then once again | 683 // reduced value rather than being decayed once here, and then once again |
| 655 // when it is next accessed. | 684 // when it is next accessed. |
| 685 // TODO(703848): Move the proportional decay logic into SiteEngagementScore, |
| 686 // so it can decay raw_score_ directly, without the double-decay issue. |
| 656 SiteEngagementScore engagement_score = CreateEngagementScore(origin); | 687 SiteEngagementScore engagement_score = CreateEngagementScore(origin); |
| 657 | 688 |
| 658 double new_score = proportion_remaining * engagement_score.GetScore(); | 689 double new_score = proportion_remaining * engagement_score.GetTotalScore(); |
| 659 int hours_since_engagement = (now - last_visit).InHours(); | 690 int hours_since_engagement = (now - last_visit).InHours(); |
| 660 int periods = | 691 int periods = |
| 661 hours_since_engagement / SiteEngagementScore::GetDecayPeriodInHours(); | 692 hours_since_engagement / SiteEngagementScore::GetDecayPeriodInHours(); |
| 662 new_score += periods * SiteEngagementScore::GetDecayPoints(); | 693 new_score += periods * SiteEngagementScore::GetDecayPoints(); |
| 663 new_score *= pow(1.0 / SiteEngagementScore::GetDecayProportion(), periods); | 694 new_score *= pow(1.0 / SiteEngagementScore::GetDecayProportion(), periods); |
| 664 | 695 |
| 665 double score = std::min(SiteEngagementScore::kMaxPoints, new_score); | 696 double score = std::min(SiteEngagementScore::kMaxPoints, new_score); |
| 666 engagement_score.Reset(score, last_visit); | 697 engagement_score.Reset(score, last_visit); |
| 667 if (!engagement_score.last_shortcut_launch_time().is_null() && | 698 if (!engagement_score.last_shortcut_launch_time().is_null() && |
| 668 engagement_score.last_shortcut_launch_time() > last_visit) { | 699 engagement_score.last_shortcut_launch_time() > last_visit) { |
| 669 engagement_score.set_last_shortcut_launch_time(last_visit); | 700 engagement_score.set_last_shortcut_launch_time(last_visit); |
| 670 } | 701 } |
| 671 | 702 |
| 672 engagement_score.Commit(); | 703 engagement_score.Commit(); |
| 673 } | 704 } |
| 674 | 705 |
| 675 SetLastEngagementTime(now); | 706 SetLastEngagementTime(now); |
| 676 } | 707 } |
| OLD | NEW |