Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(226)

Side by Side Diff: chrome/browser/engagement/site_engagement_service.cc

Issue 1975723002: Reduce the site engagement service public interface. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Push messaging now uses engagement Created 4 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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>
11 #include <utility> 10 #include <utility>
12 #include <vector> 11 #include <vector>
13 12
14 #include "base/command_line.h" 13 #include "base/command_line.h"
15 #include "base/memory/ptr_util.h" 14 #include "base/memory/ptr_util.h"
16 #include "base/metrics/field_trial.h" 15 #include "base/metrics/field_trial.h"
17 #include "base/strings/string_number_conversions.h"
18 #include "base/strings/string_util.h" 16 #include "base/strings/string_util.h"
19 #include "base/time/clock.h" 17 #include "base/time/clock.h"
20 #include "base/time/default_clock.h" 18 #include "base/time/default_clock.h"
21 #include "base/time/time.h" 19 #include "base/time/time.h"
22 #include "base/values.h" 20 #include "base/values.h"
23 #include "chrome/browser/banners/app_banner_settings_helper.h" 21 #include "chrome/browser/banners/app_banner_settings_helper.h"
24 #include "chrome/browser/content_settings/host_content_settings_map_factory.h" 22 #include "chrome/browser/content_settings/host_content_settings_map_factory.h"
25 #include "chrome/browser/engagement/site_engagement_eviction_policy.h" 23 #include "chrome/browser/engagement/site_engagement_eviction_policy.h"
26 #include "chrome/browser/engagement/site_engagement_helper.h" 24 #include "chrome/browser/engagement/site_engagement_metrics.h"
25 #include "chrome/browser/engagement/site_engagement_score.h"
27 #include "chrome/browser/engagement/site_engagement_service_factory.h" 26 #include "chrome/browser/engagement/site_engagement_service_factory.h"
28 #include "chrome/browser/history/history_service_factory.h" 27 #include "chrome/browser/history/history_service_factory.h"
29 #include "chrome/common/chrome_switches.h" 28 #include "chrome/common/chrome_switches.h"
30 #include "components/content_settings/core/browser/host_content_settings_map.h" 29 #include "components/content_settings/core/browser/host_content_settings_map.h"
31 #include "components/content_settings/core/common/content_settings_pattern.h" 30 #include "components/content_settings/core/common/content_settings_pattern.h"
32 #include "components/history/core/browser/history_service.h" 31 #include "components/history/core/browser/history_service.h"
33 #include "components/variations/variations_associated_data.h"
34 #include "content/public/browser/browser_thread.h" 32 #include "content/public/browser/browser_thread.h"
35 #include "url/gurl.h" 33 #include "url/gurl.h"
36 34
37 namespace { 35 namespace {
38 36
39 const int FOUR_WEEKS_IN_DAYS = 28; 37 const int FOUR_WEEKS_IN_DAYS = 28;
40 38
41 // 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.
42 bool g_updated_from_variations = false; 40 bool g_updated_from_variations = false;
43 41
44 // Keys used in the variations params. Order matches
45 // SiteEngagementScore::Variation enum.
46 const char* kVariationNames[] = {
47 "max_points_per_day",
48 "decay_period_in_days",
49 "decay_points",
50 "navigation_points",
51 "user_input_points",
52 "visible_media_playing_points",
53 "hidden_media_playing_points",
54 "web_app_installed_points",
55 "first_daily_engagement_points",
56 "medium_engagement_boundary",
57 "high_engagement_boundary",
58 };
59
60 // Length of time between metrics logging. 42 // Length of time between metrics logging.
61 const int kMetricsIntervalInMinutes = 60; 43 const int kMetricsIntervalInMinutes = 60;
62 44
63 // Delta within which to consider scores equal.
64 const double kScoreDelta = 0.001;
65
66 // Delta within which to consider internal time values equal. Internal time
67 // values are in microseconds, so this delta comes out at one second.
68 const double kTimeDelta = 1000000;
69
70 // Number of days after the last launch of an origin from an installed shortcut
71 // for which WEB_APP_INSTALLED_POINTS will be added to the engagement score.
72 const int kMaxDaysSinceShortcutLaunch = 10;
73
74 std::unique_ptr<ContentSettingsForOneType> GetEngagementContentSettings( 45 std::unique_ptr<ContentSettingsForOneType> GetEngagementContentSettings(
75 HostContentSettingsMap* settings_map) { 46 HostContentSettingsMap* settings_map) {
76 std::unique_ptr<ContentSettingsForOneType> engagement_settings( 47 std::unique_ptr<ContentSettingsForOneType> engagement_settings(
77 new ContentSettingsForOneType); 48 new ContentSettingsForOneType);
78 settings_map->GetSettingsForOneType(CONTENT_SETTINGS_TYPE_SITE_ENGAGEMENT, 49 settings_map->GetSettingsForOneType(CONTENT_SETTINGS_TYPE_SITE_ENGAGEMENT,
79 std::string(), engagement_settings.get()); 50 std::string(), engagement_settings.get());
80 return engagement_settings; 51 return engagement_settings;
81 } 52 }
82 53
83 bool DoublesConsideredDifferent(double value1, double value2, double delta) {
84 double abs_difference = fabs(value1 - value2);
85 return abs_difference > delta;
86 }
87
88 // Only accept a navigation event for engagement if it is one of:
89 // a. direct typed navigation
90 // b. clicking on an omnibox suggestion brought up by typing a keyword
91 // c. clicking on a bookmark or opening a bookmark app
92 // d. a custom search engine keyword search (e.g. Wikipedia search box added as
93 // search engine).
94 bool IsEngagementNavigation(ui::PageTransition transition) {
95 return ui::PageTransitionCoreTypeIs(transition, ui::PAGE_TRANSITION_TYPED) ||
96 ui::PageTransitionCoreTypeIs(transition,
97 ui::PAGE_TRANSITION_GENERATED) ||
98 ui::PageTransitionCoreTypeIs(transition,
99 ui::PAGE_TRANSITION_AUTO_BOOKMARK) ||
100 ui::PageTransitionCoreTypeIs(transition,
101 ui::PAGE_TRANSITION_KEYWORD_GENERATED);
102 }
103
104 std::unique_ptr<base::DictionaryValue> GetScoreDictForOrigin( 54 std::unique_ptr<base::DictionaryValue> GetScoreDictForOrigin(
105 HostContentSettingsMap* settings, 55 HostContentSettingsMap* settings,
106 const GURL& origin_url) { 56 const GURL& origin_url) {
107 if (!settings) 57 if (!settings)
108 return std::unique_ptr<base::DictionaryValue>(); 58 return std::unique_ptr<base::DictionaryValue>();
109 59
110 std::unique_ptr<base::Value> value = settings->GetWebsiteSetting( 60 std::unique_ptr<base::Value> value = settings->GetWebsiteSetting(
111 origin_url, origin_url, CONTENT_SETTINGS_TYPE_SITE_ENGAGEMENT, 61 origin_url, origin_url, CONTENT_SETTINGS_TYPE_SITE_ENGAGEMENT,
112 std::string(), NULL); 62 std::string(), NULL);
113 if (!value.get()) 63 if (!value.get())
114 return base::WrapUnique(new base::DictionaryValue()); 64 return base::WrapUnique(new base::DictionaryValue());
115 65
116 if (!value->IsType(base::Value::TYPE_DICTIONARY)) 66 if (!value->IsType(base::Value::TYPE_DICTIONARY))
117 return base::WrapUnique(new base::DictionaryValue()); 67 return base::WrapUnique(new base::DictionaryValue());
118 68
119 return base::WrapUnique(static_cast<base::DictionaryValue*>(value.release())); 69 return base::WrapUnique(static_cast<base::DictionaryValue*>(value.release()));
120 } 70 }
121 71
72 // Only accept a navigation event for engagement if it is one of:
73 // a. direct typed navigation
74 // b. clicking on an omnibox suggestion brought up by typing a keyword
75 // 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
77 // search engine).
78 bool IsEngagementNavigation(ui::PageTransition transition) {
79 return ui::PageTransitionCoreTypeIs(transition, ui::PAGE_TRANSITION_TYPED) ||
80 ui::PageTransitionCoreTypeIs(transition,
81 ui::PAGE_TRANSITION_GENERATED) ||
82 ui::PageTransitionCoreTypeIs(transition,
83 ui::PAGE_TRANSITION_AUTO_BOOKMARK) ||
84 ui::PageTransitionCoreTypeIs(transition,
85 ui::PAGE_TRANSITION_KEYWORD_GENERATED);
86 }
87
122 } // namespace 88 } // namespace
123 89
124 const double SiteEngagementScore::kMaxPoints = 100;
125 double SiteEngagementScore::param_values[] = {
126 5, // MAX_POINTS_PER_DAY
127 7, // DECAY_PERIOD_IN_DAYS
128 5, // DECAY_POINTS
129 0.5, // NAVIGATION_POINTS
130 0.2, // USER_INPUT_POINTS
131 0.02, // VISIBLE_MEDIA_POINTS
132 0.01, // HIDDEN_MEDIA_POINTS
133 5, // WEB_APP_INSTALLED_POINTS
134 0.5, // FIRST_DAILY_ENGAGEMENT
135 8, // BOOTSTRAP_POINTS
136 5, // MEDIUM_ENGAGEMENT_BOUNDARY
137 50, // HIGH_ENGAGEMENT_BOUNDARY
138 };
139
140 const char* SiteEngagementScore::kRawScoreKey = "rawScore";
141 const char* SiteEngagementScore::kPointsAddedTodayKey = "pointsAddedToday";
142 const char* SiteEngagementScore::kLastEngagementTimeKey = "lastEngagementTime";
143 const char* SiteEngagementScore::kLastShortcutLaunchTimeKey =
144 "lastShortcutLaunchTime";
145
146 double SiteEngagementScore::GetMaxPointsPerDay() {
147 return param_values[MAX_POINTS_PER_DAY];
148 }
149
150 double SiteEngagementScore::GetDecayPeriodInDays() {
151 return param_values[DECAY_PERIOD_IN_DAYS];
152 }
153
154 double SiteEngagementScore::GetDecayPoints() {
155 return param_values[DECAY_POINTS];
156 }
157
158 double SiteEngagementScore::GetNavigationPoints() {
159 return param_values[NAVIGATION_POINTS];
160 }
161
162 double SiteEngagementScore::GetUserInputPoints() {
163 return param_values[USER_INPUT_POINTS];
164 }
165
166 double SiteEngagementScore::GetVisibleMediaPoints() {
167 return param_values[VISIBLE_MEDIA_POINTS];
168 }
169
170 double SiteEngagementScore::GetHiddenMediaPoints() {
171 return param_values[HIDDEN_MEDIA_POINTS];
172 }
173
174 double SiteEngagementScore::GetWebAppInstalledPoints() {
175 return param_values[WEB_APP_INSTALLED_POINTS];
176 }
177
178 double SiteEngagementScore::GetFirstDailyEngagementPoints() {
179 return param_values[FIRST_DAILY_ENGAGEMENT];
180 }
181
182 double SiteEngagementScore::GetBootstrapPoints() {
183 return param_values[BOOTSTRAP_POINTS];
184 }
185
186 double SiteEngagementScore::GetMediumEngagementBoundary() {
187 return param_values[MEDIUM_ENGAGEMENT_BOUNDARY];
188 }
189
190 double SiteEngagementScore::GetHighEngagementBoundary() {
191 return param_values[HIGH_ENGAGEMENT_BOUNDARY];
192 }
193
194 void SiteEngagementScore::UpdateFromVariations() {
195 double param_vals[MAX_VARIATION];
196
197 for (int i = 0; i < MAX_VARIATION; ++i) {
198 std::string param_string = variations::GetVariationParamValue(
199 SiteEngagementService::kEngagementParams, kVariationNames[i]);
200
201 // Bail out if we didn't get a param string for the key, or if we couldn't
202 // convert the param string to a double, or if we get a negative value.
203 if (param_string.empty() ||
204 !base::StringToDouble(param_string, &param_vals[i]) ||
205 param_vals[i] < 0) {
206 return;
207 }
208 }
209
210 // Once we're sure everything is valid, assign the variation to the param
211 // values array.
212 for (int i = 0; i < MAX_VARIATION; ++i)
213 SiteEngagementScore::param_values[i] = param_vals[i];
214 }
215
216 SiteEngagementScore::SiteEngagementScore(
217 base::Clock* clock,
218 const base::DictionaryValue& score_dict)
219 : SiteEngagementScore(clock) {
220 score_dict.GetDouble(kRawScoreKey, &raw_score_);
221 score_dict.GetDouble(kPointsAddedTodayKey, &points_added_today_);
222
223 double internal_time;
224 if (score_dict.GetDouble(kLastEngagementTimeKey, &internal_time))
225 last_engagement_time_ = base::Time::FromInternalValue(internal_time);
226 if (score_dict.GetDouble(kLastShortcutLaunchTimeKey, &internal_time))
227 last_shortcut_launch_time_ = base::Time::FromInternalValue(internal_time);
228 }
229
230 SiteEngagementScore::~SiteEngagementScore() {
231 }
232
233 double SiteEngagementScore::Score() const {
234 return std::min(DecayedScore() + BonusScore(), kMaxPoints);
235 }
236
237 void SiteEngagementScore::AddPoints(double points) {
238 DCHECK_NE(0, points);
239 double decayed_score = DecayedScore();
240
241 // Record the original and decayed scores after a decay event.
242 if (decayed_score < raw_score_) {
243 SiteEngagementMetrics::RecordScoreDecayedFrom(raw_score_);
244 SiteEngagementMetrics::RecordScoreDecayedTo(decayed_score);
245 }
246
247 // As the score is about to be updated, commit any decay that has happened
248 // since the last update.
249 raw_score_ = decayed_score;
250
251 base::Time now = clock_->Now();
252 if (!last_engagement_time_.is_null() &&
253 now.LocalMidnight() != last_engagement_time_.LocalMidnight()) {
254 points_added_today_ = 0;
255 }
256
257 if (points_added_today_ == 0) {
258 // Award bonus engagement for the first engagement of the day for a site.
259 points += GetFirstDailyEngagementPoints();
260 SiteEngagementMetrics::RecordEngagement(
261 SiteEngagementMetrics::ENGAGEMENT_FIRST_DAILY_ENGAGEMENT);
262 }
263
264 double to_add = std::min(kMaxPoints - raw_score_,
265 GetMaxPointsPerDay() - points_added_today_);
266 to_add = std::min(to_add, points);
267
268 points_added_today_ += to_add;
269 raw_score_ += to_add;
270
271 last_engagement_time_ = now;
272 }
273
274 void SiteEngagementScore::Reset(double points, const base::Time* updated_time) {
275 raw_score_ = points;
276 points_added_today_ = 0;
277
278 // This must be set in order to prevent the score from decaying when read.
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 }
286 }
287
288 bool SiteEngagementScore::MaxPointsPerDayAdded() const {
289 if (!last_engagement_time_.is_null() &&
290 clock_->Now().LocalMidnight() != last_engagement_time_.LocalMidnight()) {
291 return false;
292 }
293
294 return points_added_today_ == GetMaxPointsPerDay();
295 }
296
297 bool SiteEngagementScore::UpdateScoreDict(base::DictionaryValue* score_dict) {
298 double raw_score_orig = 0;
299 double points_added_today_orig = 0;
300 double last_engagement_time_internal_orig = 0;
301 double last_shortcut_launch_time_internal_orig = 0;
302
303 score_dict->GetDouble(kRawScoreKey, &raw_score_orig);
304 score_dict->GetDouble(kPointsAddedTodayKey, &points_added_today_orig);
305 score_dict->GetDouble(kLastEngagementTimeKey,
306 &last_engagement_time_internal_orig);
307 score_dict->GetDouble(kLastShortcutLaunchTimeKey,
308 &last_shortcut_launch_time_internal_orig);
309 bool changed =
310 DoublesConsideredDifferent(raw_score_orig, raw_score_, kScoreDelta) ||
311 DoublesConsideredDifferent(points_added_today_orig, points_added_today_,
312 kScoreDelta) ||
313 DoublesConsideredDifferent(last_engagement_time_internal_orig,
314 last_engagement_time_.ToInternalValue(),
315 kTimeDelta) ||
316 DoublesConsideredDifferent(last_shortcut_launch_time_internal_orig,
317 last_shortcut_launch_time_.ToInternalValue(),
318 kTimeDelta);
319
320 if (!changed)
321 return false;
322
323 score_dict->SetDouble(kRawScoreKey, raw_score_);
324 score_dict->SetDouble(kPointsAddedTodayKey, points_added_today_);
325 score_dict->SetDouble(kLastEngagementTimeKey,
326 last_engagement_time_.ToInternalValue());
327 score_dict->SetDouble(kLastShortcutLaunchTimeKey,
328 last_shortcut_launch_time_.ToInternalValue());
329
330 return true;
331 }
332
333 SiteEngagementScore::SiteEngagementScore(base::Clock* clock)
334 : clock_(clock),
335 raw_score_(0),
336 points_added_today_(0),
337 last_engagement_time_(),
338 last_shortcut_launch_time_() {}
339
340 double SiteEngagementScore::DecayedScore() const {
341 // Note that users can change their clock, so from this system's perspective
342 // time can go backwards. If that does happen and the system detects that the
343 // current day is earlier than the last engagement, no decay (or growth) is
344 // applied.
345 int days_since_engagement = (clock_->Now() - last_engagement_time_).InDays();
346 if (days_since_engagement < 0)
347 return raw_score_;
348
349 int periods = days_since_engagement / GetDecayPeriodInDays();
350 return std::max(0.0, raw_score_ - periods * GetDecayPoints());
351 }
352
353 double SiteEngagementScore::BonusScore() const {
354 int days_since_shortcut_launch =
355 (clock_->Now() - last_shortcut_launch_time_).InDays();
356 if (days_since_shortcut_launch <= kMaxDaysSinceShortcutLaunch)
357 return GetWebAppInstalledPoints();
358
359 return 0;
360 }
361
362 void SiteEngagementScore::SetParamValuesForTesting() {
363 param_values[MAX_POINTS_PER_DAY] = 5;
364 param_values[DECAY_PERIOD_IN_DAYS] = 7;
365 param_values[DECAY_POINTS] = 5;
366 param_values[NAVIGATION_POINTS] = 0.5;
367 param_values[USER_INPUT_POINTS] = 0.05;
368 param_values[VISIBLE_MEDIA_POINTS] = 0.02;
369 param_values[HIDDEN_MEDIA_POINTS] = 0.01;
370 param_values[WEB_APP_INSTALLED_POINTS] = 5;
371 param_values[BOOTSTRAP_POINTS] = 8;
372 param_values[MEDIUM_ENGAGEMENT_BOUNDARY] = 5;
373 param_values[HIGH_ENGAGEMENT_BOUNDARY] = 50;
374
375 // This is set to zero to avoid interference with tests and is set when
376 // testing this functionality.
377 param_values[FIRST_DAILY_ENGAGEMENT] = 0;
378 }
379
380 const char SiteEngagementService::kEngagementParams[] = "SiteEngagement"; 90 const char SiteEngagementService::kEngagementParams[] = "SiteEngagement";
381 91
382 // static 92 // static
383 SiteEngagementService* SiteEngagementService::Get(Profile* profile) { 93 SiteEngagementService* SiteEngagementService::Get(Profile* profile) {
384 return SiteEngagementServiceFactory::GetForProfile(profile); 94 return SiteEngagementServiceFactory::GetForProfile(profile);
385 } 95 }
386 96
387 // static 97 // static
98 double SiteEngagementService::GetMaxPoints() {
99 return SiteEngagementScore::kMaxPoints;
100 }
101
102 // static
388 bool SiteEngagementService::IsEnabled() { 103 bool SiteEngagementService::IsEnabled() {
389 // If the engagement service or any of its dependencies are force-enabled, 104 // If the engagement service or any of its dependencies are force-enabled,
390 // return true immediately. 105 // return true immediately.
391 if (base::CommandLine::ForCurrentProcess()->HasSwitch( 106 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
392 switches::kEnableSiteEngagementService) || 107 switches::kEnableSiteEngagementService) ||
393 SiteEngagementEvictionPolicy::IsEnabled() || 108 SiteEngagementEvictionPolicy::IsEnabled() ||
394 AppBannerSettingsHelper::ShouldUseSiteEngagementScore()) { 109 AppBannerSettingsHelper::ShouldUseSiteEngagementScore()) {
395 return true; 110 return true;
396 } 111 }
397 112
398 if (base::CommandLine::ForCurrentProcess()->HasSwitch( 113 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
399 switches::kDisableSiteEngagementService)) { 114 switches::kDisableSiteEngagementService)) {
400 return false; 115 return false;
401 } 116 }
402 const std::string group_name = 117 const std::string group_name =
403 base::FieldTrialList::FindFullName(kEngagementParams); 118 base::FieldTrialList::FindFullName(kEngagementParams);
404 return !base::StartsWith(group_name, "Disabled", 119 return !base::StartsWith(group_name, "Disabled",
405 base::CompareCase::SENSITIVE); 120 base::CompareCase::SENSITIVE);
406 } 121 }
407 122
408 SiteEngagementService::SiteEngagementService(Profile* profile) 123 SiteEngagementService::SiteEngagementService(Profile* profile)
409 : SiteEngagementService(profile, base::WrapUnique(new base::DefaultClock)) { 124 : SiteEngagementService(profile, base::WrapUnique(new base::DefaultClock)) {
410 content::BrowserThread::PostAfterStartupTask( 125 content::BrowserThread::PostAfterStartupTask(
411 FROM_HERE, content::BrowserThread::GetMessageLoopProxyForThread( 126 FROM_HERE, content::BrowserThread::GetMessageLoopProxyForThread(
412 content::BrowserThread::UI), 127 content::BrowserThread::UI),
413 base::Bind(&SiteEngagementService::AfterStartupTask, 128 base::Bind(&SiteEngagementService::AfterStartupTask,
414 weak_factory_.GetWeakPtr())); 129 weak_factory_.GetWeakPtr()));
415 130
416 if (!g_updated_from_variations) { 131 if (!g_updated_from_variations) {
417 SiteEngagementScore::UpdateFromVariations(); 132 SiteEngagementScore::UpdateFromVariations(kEngagementParams);
418 g_updated_from_variations = true; 133 g_updated_from_variations = true;
419 } 134 }
420 } 135 }
421 136
422 SiteEngagementService::~SiteEngagementService() { 137 SiteEngagementService::~SiteEngagementService() {
423 history::HistoryService* history = HistoryServiceFactory::GetForProfile( 138 history::HistoryService* history = HistoryServiceFactory::GetForProfile(
424 profile_, ServiceAccessType::IMPLICIT_ACCESS); 139 profile_, ServiceAccessType::IMPLICIT_ACCESS);
425 if (history) 140 if (history)
426 history->RemoveObserver(this); 141 history->RemoveObserver(this);
427 } 142 }
428 143
429 void SiteEngagementService::HandleNavigation(const GURL& url, 144 SiteEngagementService::EngagementLevel
430 ui::PageTransition transition) { 145 SiteEngagementService::GetEngagementLevel(const GURL& url) const {
431 if (IsEngagementNavigation(transition)) { 146 DCHECK_LT(SiteEngagementScore::GetMediumEngagementBoundary(),
432 SiteEngagementMetrics::RecordEngagement( 147 SiteEngagementScore::GetHighEngagementBoundary());
433 SiteEngagementMetrics::ENGAGEMENT_NAVIGATION); 148 double score = GetScore(url);
434 AddPoints(url, SiteEngagementScore::GetNavigationPoints()); 149 if (score == 0)
435 RecordMetrics(); 150 return ENGAGEMENT_LEVEL_NONE;
436 } 151
152 if (score < SiteEngagementScore::GetMediumEngagementBoundary())
153 return ENGAGEMENT_LEVEL_LOW;
154
155 if (score < SiteEngagementScore::GetHighEngagementBoundary())
156 return ENGAGEMENT_LEVEL_MEDIUM;
157
158 if (score < SiteEngagementScore::kMaxPoints)
159 return ENGAGEMENT_LEVEL_HIGH;
160
161 return ENGAGEMENT_LEVEL_MAX;
437 } 162 }
438 163
439 void SiteEngagementService::HandleUserInput( 164 std::map<GURL, double> SiteEngagementService::GetScoreMap() const {
440 const GURL& url, 165 HostContentSettingsMap* settings_map =
441 SiteEngagementMetrics::EngagementType type) { 166 HostContentSettingsMapFactory::GetForProfile(profile_);
442 SiteEngagementMetrics::RecordEngagement(type); 167 std::unique_ptr<ContentSettingsForOneType> engagement_settings =
443 AddPoints(url, SiteEngagementScore::GetUserInputPoints()); 168 GetEngagementContentSettings(settings_map);
444 RecordMetrics(); 169
170 std::map<GURL, double> score_map;
171 for (const auto& site : *engagement_settings) {
172 GURL origin(site.primary_pattern.ToString());
173 if (!origin.is_valid())
174 continue;
175
176 std::unique_ptr<base::DictionaryValue> score_dict =
177 GetScoreDictForOrigin(settings_map, origin);
178 SiteEngagementScore score(clock_.get(), *score_dict);
179 score_map[origin] = score.GetScore();
180 }
181
182 return score_map;
445 } 183 }
446 184
447 void SiteEngagementService::HandleMediaPlaying(const GURL& url, 185 bool SiteEngagementService::IsBootstrapped() {
448 bool is_hidden) { 186 return GetTotalEngagementPoints() >=
449 SiteEngagementMetrics::RecordEngagement( 187 SiteEngagementScore::GetBootstrapPoints();
450 is_hidden ? SiteEngagementMetrics::ENGAGEMENT_MEDIA_HIDDEN 188 }
451 : SiteEngagementMetrics::ENGAGEMENT_MEDIA_VISIBLE); 189
452 AddPoints(url, is_hidden ? SiteEngagementScore::GetHiddenMediaPoints() 190 bool SiteEngagementService::IsEngagementAtLeast(
453 : SiteEngagementScore::GetVisibleMediaPoints()); 191 const GURL& url,
454 RecordMetrics(); 192 EngagementLevel level) const {
193 DCHECK_LT(SiteEngagementScore::GetMediumEngagementBoundary(),
194 SiteEngagementScore::GetHighEngagementBoundary());
195 double score = GetScore(url);
196 switch (level) {
197 case ENGAGEMENT_LEVEL_NONE:
198 return true;
199 case ENGAGEMENT_LEVEL_LOW:
200 return score > 0;
201 case ENGAGEMENT_LEVEL_MEDIUM:
202 return score >= SiteEngagementScore::GetMediumEngagementBoundary();
203 case ENGAGEMENT_LEVEL_HIGH:
204 return score >= SiteEngagementScore::GetHighEngagementBoundary();
205 case ENGAGEMENT_LEVEL_MAX:
206 return score == SiteEngagementScore::kMaxPoints;
207 }
208 NOTREACHED();
209 return false;
455 } 210 }
456 211
457 void SiteEngagementService::ResetScoreForURL(const GURL& url, double score) { 212 void SiteEngagementService::ResetScoreForURL(const GURL& url, double score) {
458 ResetScoreAndAccessTimesForURL(url, score, nullptr); 213 ResetScoreAndAccessTimesForURL(url, score, nullptr);
459 } 214 }
460 215
461 void SiteEngagementService::OnURLsDeleted(
462 history::HistoryService* history_service,
463 bool all_history,
464 bool expired,
465 const history::URLRows& deleted_rows,
466 const std::set<GURL>& favicon_urls) {
467 std::multiset<GURL> origins;
468 for (const history::URLRow& row : deleted_rows)
469 origins.insert(row.url().GetOrigin());
470
471 history::HistoryService* hs = HistoryServiceFactory::GetForProfile(
472 profile_, ServiceAccessType::EXPLICIT_ACCESS);
473 hs->GetCountsAndLastVisitForOrigins(
474 std::set<GURL>(origins.begin(), origins.end()),
475 base::Bind(
476 &SiteEngagementService::GetCountsAndLastVisitForOriginsComplete,
477 weak_factory_.GetWeakPtr(), hs, origins, expired));
478 }
479
480 void SiteEngagementService::SetLastShortcutLaunchTime(const GURL& url) { 216 void SiteEngagementService::SetLastShortcutLaunchTime(const GURL& url) {
481 HostContentSettingsMap* settings_map = 217 HostContentSettingsMap* settings_map =
482 HostContentSettingsMapFactory::GetForProfile(profile_); 218 HostContentSettingsMapFactory::GetForProfile(profile_);
483 std::unique_ptr<base::DictionaryValue> score_dict = 219 std::unique_ptr<base::DictionaryValue> score_dict =
484 GetScoreDictForOrigin(settings_map, url); 220 GetScoreDictForOrigin(settings_map, url);
485 SiteEngagementScore score(clock_.get(), *score_dict); 221 SiteEngagementScore score(clock_.get(), *score_dict);
486 222
487 // Record the number of days since the last launch in UMA. If the user's clock 223 // Record the number of days since the last launch in UMA. If the user's clock
488 // has changed back in time, set this to 0. 224 // has changed back in time, set this to 0.
489 base::Time now = clock_->Now(); 225 base::Time now = clock_->Now();
(...skipping 13 matching lines...) Expand all
503 } 239 }
504 } 240 }
505 241
506 double SiteEngagementService::GetScore(const GURL& url) const { 242 double SiteEngagementService::GetScore(const GURL& url) const {
507 HostContentSettingsMap* settings_map = 243 HostContentSettingsMap* settings_map =
508 HostContentSettingsMapFactory::GetForProfile(profile_); 244 HostContentSettingsMapFactory::GetForProfile(profile_);
509 std::unique_ptr<base::DictionaryValue> score_dict = 245 std::unique_ptr<base::DictionaryValue> score_dict =
510 GetScoreDictForOrigin(settings_map, url); 246 GetScoreDictForOrigin(settings_map, url);
511 SiteEngagementScore score(clock_.get(), *score_dict); 247 SiteEngagementScore score(clock_.get(), *score_dict);
512 248
513 return score.Score(); 249 return score.GetScore();
514 } 250 }
515 251
516 double SiteEngagementService::GetTotalEngagementPoints() const { 252 double SiteEngagementService::GetTotalEngagementPoints() const {
517 std::map<GURL, double> score_map = GetScoreMap(); 253 std::map<GURL, double> score_map = GetScoreMap();
518 254
519 double total_score = 0; 255 double total_score = 0;
520 for (const auto& value : score_map) 256 for (const auto& value : score_map)
521 total_score += value.second; 257 total_score += value.second;
522 258
523 return total_score; 259 return total_score;
524 } 260 }
525 261
526 std::map<GURL, double> SiteEngagementService::GetScoreMap() const {
527 HostContentSettingsMap* settings_map =
528 HostContentSettingsMapFactory::GetForProfile(profile_);
529 std::unique_ptr<ContentSettingsForOneType> engagement_settings =
530 GetEngagementContentSettings(settings_map);
531
532 std::map<GURL, double> score_map;
533 for (const auto& site : *engagement_settings) {
534 GURL origin(site.primary_pattern.ToString());
535 if (!origin.is_valid())
536 continue;
537
538 std::unique_ptr<base::DictionaryValue> score_dict =
539 GetScoreDictForOrigin(settings_map, origin);
540 SiteEngagementScore score(clock_.get(), *score_dict);
541 score_map[origin] = score.Score();
542 }
543
544 return score_map;
545 }
546
547 bool SiteEngagementService::IsBootstrapped() {
548 return GetTotalEngagementPoints() >=
549 SiteEngagementScore::GetBootstrapPoints();
550 }
551
552 SiteEngagementService::EngagementLevel
553 SiteEngagementService::GetEngagementLevel(const GURL& url) const {
554 DCHECK_LT(SiteEngagementScore::GetMediumEngagementBoundary(),
555 SiteEngagementScore::GetHighEngagementBoundary());
556 double score = GetScore(url);
557 if (score == 0)
558 return ENGAGEMENT_LEVEL_NONE;
559
560 if (score < SiteEngagementScore::GetMediumEngagementBoundary())
561 return ENGAGEMENT_LEVEL_LOW;
562
563 if (score < SiteEngagementScore::GetHighEngagementBoundary())
564 return ENGAGEMENT_LEVEL_MEDIUM;
565
566 if (score < SiteEngagementScore::kMaxPoints)
567 return ENGAGEMENT_LEVEL_HIGH;
568
569 return ENGAGEMENT_LEVEL_MAX;
570 }
571
572 bool SiteEngagementService::IsEngagementAtLeast(
573 const GURL& url,
574 EngagementLevel level) const {
575 DCHECK_LT(SiteEngagementScore::GetMediumEngagementBoundary(),
576 SiteEngagementScore::GetHighEngagementBoundary());
577 double score = GetScore(url);
578 switch (level) {
579 case ENGAGEMENT_LEVEL_NONE:
580 return true;
581 case ENGAGEMENT_LEVEL_LOW:
582 return score > 0;
583 case ENGAGEMENT_LEVEL_MEDIUM:
584 return score >= SiteEngagementScore::GetMediumEngagementBoundary();
585 case ENGAGEMENT_LEVEL_HIGH:
586 return score >= SiteEngagementScore::GetHighEngagementBoundary();
587 case ENGAGEMENT_LEVEL_MAX:
588 return score == SiteEngagementScore::kMaxPoints;
589 }
590 NOTREACHED();
591 return false;
592 }
593
594 SiteEngagementService::SiteEngagementService(Profile* profile, 262 SiteEngagementService::SiteEngagementService(Profile* profile,
595 std::unique_ptr<base::Clock> clock) 263 std::unique_ptr<base::Clock> clock)
596 : profile_(profile), clock_(std::move(clock)), weak_factory_(this) { 264 : profile_(profile), clock_(std::move(clock)), weak_factory_(this) {
597 // May be null in tests. 265 // May be null in tests.
598 history::HistoryService* history = HistoryServiceFactory::GetForProfile( 266 history::HistoryService* history = HistoryServiceFactory::GetForProfile(
599 profile, ServiceAccessType::IMPLICIT_ACCESS); 267 profile, ServiceAccessType::IMPLICIT_ACCESS);
600 if (history) 268 if (history)
601 history->AddObserver(this); 269 history->AddObserver(this);
602 } 270 }
603 271
(...skipping 22 matching lines...) Expand all
626 HostContentSettingsMapFactory::GetForProfile(profile_); 294 HostContentSettingsMapFactory::GetForProfile(profile_);
627 std::unique_ptr<ContentSettingsForOneType> engagement_settings = 295 std::unique_ptr<ContentSettingsForOneType> engagement_settings =
628 GetEngagementContentSettings(settings_map); 296 GetEngagementContentSettings(settings_map);
629 297
630 for (const auto& site : *engagement_settings) { 298 for (const auto& site : *engagement_settings) {
631 GURL origin(site.primary_pattern.ToString()); 299 GURL origin(site.primary_pattern.ToString());
632 if (origin.is_valid()) { 300 if (origin.is_valid()) {
633 std::unique_ptr<base::DictionaryValue> score_dict = 301 std::unique_ptr<base::DictionaryValue> score_dict =
634 GetScoreDictForOrigin(settings_map, origin); 302 GetScoreDictForOrigin(settings_map, origin);
635 SiteEngagementScore score(clock_.get(), *score_dict); 303 SiteEngagementScore score(clock_.get(), *score_dict);
636 if (score.Score() != 0) 304 if (score.GetScore() != 0)
637 continue; 305 continue;
638 } 306 }
639 307
640 settings_map->SetWebsiteSettingDefaultScope( 308 settings_map->SetWebsiteSettingDefaultScope(
641 origin, GURL(), CONTENT_SETTINGS_TYPE_SITE_ENGAGEMENT, std::string(), 309 origin, GURL(), CONTENT_SETTINGS_TYPE_SITE_ENGAGEMENT, std::string(),
642 nullptr); 310 nullptr);
643 } 311 }
644 } 312 }
645 313
646 void SiteEngagementService::RecordMetrics() { 314 void SiteEngagementService::RecordMetrics() {
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
690 // if there are an odd number of scores, or the average of the two middle 358 // if there are an odd number of scores, or the average of the two middle
691 // scores otherwise. 359 // scores otherwise.
692 std::sort(scores.begin(), scores.end()); 360 std::sort(scores.begin(), scores.end());
693 size_t mid = scores.size() / 2; 361 size_t mid = scores.size() / 2;
694 if (scores.size() % 2 == 1) 362 if (scores.size() % 2 == 1)
695 return scores[mid]; 363 return scores[mid];
696 else 364 else
697 return (scores[mid - 1] + scores[mid]) / 2; 365 return (scores[mid - 1] + scores[mid]) / 2;
698 } 366 }
699 367
368 void SiteEngagementService::HandleMediaPlaying(const GURL& url,
369 bool is_hidden) {
370 SiteEngagementMetrics::RecordEngagement(
371 is_hidden ? SiteEngagementMetrics::ENGAGEMENT_MEDIA_HIDDEN
372 : SiteEngagementMetrics::ENGAGEMENT_MEDIA_VISIBLE);
373 AddPoints(url, is_hidden ? SiteEngagementScore::GetHiddenMediaPoints()
374 : SiteEngagementScore::GetVisibleMediaPoints());
375 RecordMetrics();
376 }
377
378 void SiteEngagementService::HandleNavigation(const GURL& url,
379 ui::PageTransition transition) {
380 if (IsEngagementNavigation(transition)) {
381 SiteEngagementMetrics::RecordEngagement(
382 SiteEngagementMetrics::ENGAGEMENT_NAVIGATION);
383 AddPoints(url, SiteEngagementScore::GetNavigationPoints());
384 RecordMetrics();
385 }
386 }
387
388 void SiteEngagementService::HandleUserInput(
389 const GURL& url,
390 SiteEngagementMetrics::EngagementType type) {
391 SiteEngagementMetrics::RecordEngagement(type);
392 AddPoints(url, SiteEngagementScore::GetUserInputPoints());
393 RecordMetrics();
394 }
395
396 void SiteEngagementService::OnURLsDeleted(
397 history::HistoryService* history_service,
398 bool all_history,
399 bool expired,
400 const history::URLRows& deleted_rows,
401 const std::set<GURL>& favicon_urls) {
402 std::multiset<GURL> origins;
403 for (const history::URLRow& row : deleted_rows)
404 origins.insert(row.url().GetOrigin());
405
406 history::HistoryService* hs = HistoryServiceFactory::GetForProfile(
407 profile_, ServiceAccessType::EXPLICIT_ACCESS);
408 hs->GetCountsAndLastVisitForOrigins(
409 std::set<GURL>(origins.begin(), origins.end()),
410 base::Bind(
411 &SiteEngagementService::GetCountsAndLastVisitForOriginsComplete,
412 weak_factory_.GetWeakPtr(), hs, origins, expired));
413 }
414
700 int SiteEngagementService::OriginsWithMaxDailyEngagement() const { 415 int SiteEngagementService::OriginsWithMaxDailyEngagement() const {
701 HostContentSettingsMap* settings_map = 416 HostContentSettingsMap* settings_map =
702 HostContentSettingsMapFactory::GetForProfile(profile_); 417 HostContentSettingsMapFactory::GetForProfile(profile_);
703 std::unique_ptr<ContentSettingsForOneType> engagement_settings = 418 std::unique_ptr<ContentSettingsForOneType> engagement_settings =
704 GetEngagementContentSettings(settings_map); 419 GetEngagementContentSettings(settings_map);
705 420
706 int total_origins = 0; 421 int total_origins = 0;
707 422
708 // We cannot call GetScoreMap as we need the score objects, not raw scores. 423 // We cannot call GetScoreMap as we need the score objects, not raw scores.
709 for (const auto& site : *engagement_settings) { 424 for (const auto& site : *engagement_settings) {
(...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after
807 nullptr); 522 nullptr);
808 return; 523 return;
809 } 524 }
810 525
811 if (engagement_score.UpdateScoreDict(score_dict.get())) { 526 if (engagement_score.UpdateScoreDict(score_dict.get())) {
812 settings_map->SetWebsiteSettingDefaultScope( 527 settings_map->SetWebsiteSettingDefaultScope(
813 url, GURL(), CONTENT_SETTINGS_TYPE_SITE_ENGAGEMENT, std::string(), 528 url, GURL(), CONTENT_SETTINGS_TYPE_SITE_ENGAGEMENT, std::string(),
814 score_dict.release()); 529 score_dict.release());
815 } 530 }
816 } 531 }
OLDNEW
« no previous file with comments | « chrome/browser/engagement/site_engagement_service.h ('k') | chrome/browser/engagement/site_engagement_service_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698