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

Side by Side Diff: chrome/browser/engagement/site_engagement_score.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
(Empty)
1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "chrome/browser/engagement/site_engagement_score.h"
6
7 #include <cmath>
8
9 #include "base/strings/string_number_conversions.h"
10 #include "base/time/clock.h"
11 #include "base/time/time.h"
12 #include "base/values.h"
13 #include "chrome/browser/engagement/site_engagement_metrics.h"
14 #include "components/variations/variations_associated_data.h"
15
16 namespace {
17
18 // Delta within which to consider scores equal.
19 const double kScoreDelta = 0.001;
20
21 // Delta within which to consider internal time values equal. Internal time
22 // values are in microseconds, so this delta comes out at one second.
23 const double kTimeDelta = 1000000;
24
25 // Number of days after the last launch of an origin from an installed shortcut
26 // for which WEB_APP_INSTALLED_POINTS will be added to the engagement score.
27 const int kMaxDaysSinceShortcutLaunch = 10;
28
29 // Keys used in the variations params. Order matches
30 // SiteEngagementScore::Variation enum.
31 const char* kVariationNames[] = {
32 "max_points_per_day",
33 "decay_period_in_days",
34 "decay_points",
35 "navigation_points",
36 "user_input_points",
37 "visible_media_playing_points",
38 "hidden_media_playing_points",
39 "web_app_installed_points",
40 "first_daily_engagement_points",
41 "medium_engagement_boundary",
42 "high_engagement_boundary",
43 };
44
45 bool DoublesConsideredDifferent(double value1, double value2, double delta) {
46 double abs_difference = fabs(value1 - value2);
47 return abs_difference > delta;
48 }
49
50 } // namespace
51
52 const double SiteEngagementScore::kMaxPoints = 100;
53 double SiteEngagementScore::param_values[] = {
54 5, // MAX_POINTS_PER_DAY
55 7, // DECAY_PERIOD_IN_DAYS
56 5, // DECAY_POINTS
57 0.5, // NAVIGATION_POINTS
58 0.2, // USER_INPUT_POINTS
59 0.02, // VISIBLE_MEDIA_POINTS
60 0.01, // HIDDEN_MEDIA_POINTS
61 5, // WEB_APP_INSTALLED_POINTS
62 0.5, // FIRST_DAILY_ENGAGEMENT
63 8, // BOOTSTRAP_POINTS
64 5, // MEDIUM_ENGAGEMENT_BOUNDARY
65 50, // HIGH_ENGAGEMENT_BOUNDARY
66 };
67
68 const char* SiteEngagementScore::kRawScoreKey = "rawScore";
69 const char* SiteEngagementScore::kPointsAddedTodayKey = "pointsAddedToday";
70 const char* SiteEngagementScore::kLastEngagementTimeKey = "lastEngagementTime";
71 const char* SiteEngagementScore::kLastShortcutLaunchTimeKey =
72 "lastShortcutLaunchTime";
73
74 double SiteEngagementScore::GetMaxPointsPerDay() {
75 return param_values[MAX_POINTS_PER_DAY];
76 }
77
78 double SiteEngagementScore::GetDecayPeriodInDays() {
79 return param_values[DECAY_PERIOD_IN_DAYS];
80 }
81
82 double SiteEngagementScore::GetDecayPoints() {
83 return param_values[DECAY_POINTS];
84 }
85
86 double SiteEngagementScore::GetNavigationPoints() {
87 return param_values[NAVIGATION_POINTS];
88 }
89
90 double SiteEngagementScore::GetUserInputPoints() {
91 return param_values[USER_INPUT_POINTS];
92 }
93
94 double SiteEngagementScore::GetVisibleMediaPoints() {
95 return param_values[VISIBLE_MEDIA_POINTS];
96 }
97
98 double SiteEngagementScore::GetHiddenMediaPoints() {
99 return param_values[HIDDEN_MEDIA_POINTS];
100 }
101
102 double SiteEngagementScore::GetWebAppInstalledPoints() {
103 return param_values[WEB_APP_INSTALLED_POINTS];
104 }
105
106 double SiteEngagementScore::GetFirstDailyEngagementPoints() {
107 return param_values[FIRST_DAILY_ENGAGEMENT];
108 }
109
110 double SiteEngagementScore::GetBootstrapPoints() {
111 return param_values[BOOTSTRAP_POINTS];
112 }
113
114 double SiteEngagementScore::GetMediumEngagementBoundary() {
115 return param_values[MEDIUM_ENGAGEMENT_BOUNDARY];
116 }
117
118 double SiteEngagementScore::GetHighEngagementBoundary() {
119 return param_values[HIGH_ENGAGEMENT_BOUNDARY];
120 }
121
122 // static
123 void SiteEngagementScore::UpdateFromVariations(const char* param_name) {
124 double param_vals[MAX_VARIATION];
125
126 for (int i = 0; i < MAX_VARIATION; ++i) {
127 std::string param_string =
128 variations::GetVariationParamValue(param_name, kVariationNames[i]);
129
130 // Bail out if we didn't get a param string for the key, or if we couldn't
131 // convert the param string to a double, or if we get a negative value.
132 if (param_string.empty() ||
133 !base::StringToDouble(param_string, &param_vals[i]) ||
134 param_vals[i] < 0) {
135 return;
136 }
137 }
138
139 // Once we're sure everything is valid, assign the variation to the param
140 // values array.
141 for (int i = 0; i < MAX_VARIATION; ++i)
142 SiteEngagementScore::param_values[i] = param_vals[i];
143 }
144
145 SiteEngagementScore::SiteEngagementScore(base::Clock* clock,
146 const base::DictionaryValue& score_dict)
147 : SiteEngagementScore(clock) {
148 score_dict.GetDouble(kRawScoreKey, &raw_score_);
149 score_dict.GetDouble(kPointsAddedTodayKey, &points_added_today_);
150
151 double internal_time;
152 if (score_dict.GetDouble(kLastEngagementTimeKey, &internal_time))
153 last_engagement_time_ = base::Time::FromInternalValue(internal_time);
154 if (score_dict.GetDouble(kLastShortcutLaunchTimeKey, &internal_time))
155 last_shortcut_launch_time_ = base::Time::FromInternalValue(internal_time);
156 }
157
158 SiteEngagementScore::~SiteEngagementScore() {}
159
160 void SiteEngagementScore::AddPoints(double points) {
161 DCHECK_NE(0, points);
162 double decayed_score = DecayedScore();
163
164 // Record the original and decayed scores after a decay event.
165 if (decayed_score < raw_score_) {
166 SiteEngagementMetrics::RecordScoreDecayedFrom(raw_score_);
167 SiteEngagementMetrics::RecordScoreDecayedTo(decayed_score);
168 }
169
170 // As the score is about to be updated, commit any decay that has happened
171 // since the last update.
172 raw_score_ = decayed_score;
173
174 base::Time now = clock_->Now();
175 if (!last_engagement_time_.is_null() &&
176 now.LocalMidnight() != last_engagement_time_.LocalMidnight()) {
177 points_added_today_ = 0;
178 }
179
180 if (points_added_today_ == 0) {
181 // Award bonus engagement for the first engagement of the day for a site.
182 points += GetFirstDailyEngagementPoints();
183 SiteEngagementMetrics::RecordEngagement(
184 SiteEngagementMetrics::ENGAGEMENT_FIRST_DAILY_ENGAGEMENT);
185 }
186
187 double to_add = std::min(kMaxPoints - raw_score_,
188 GetMaxPointsPerDay() - points_added_today_);
189 to_add = std::min(to_add, points);
190
191 points_added_today_ += to_add;
192 raw_score_ += to_add;
193
194 last_engagement_time_ = now;
195 }
196
197 double SiteEngagementScore::GetScore() const {
198 return std::min(DecayedScore() + BonusScore(), kMaxPoints);
199 }
200
201 bool SiteEngagementScore::MaxPointsPerDayAdded() const {
202 if (!last_engagement_time_.is_null() &&
203 clock_->Now().LocalMidnight() != last_engagement_time_.LocalMidnight()) {
204 return false;
205 }
206
207 return points_added_today_ == GetMaxPointsPerDay();
208 }
209
210 void SiteEngagementScore::Reset(double points, const base::Time* updated_time) {
211 raw_score_ = points;
212 points_added_today_ = 0;
213
214 // This must be set in order to prevent the score from decaying when read.
215 if (updated_time) {
216 last_engagement_time_ = *updated_time;
217 if (!last_shortcut_launch_time_.is_null())
218 last_shortcut_launch_time_ = *updated_time;
219 } else {
220 last_engagement_time_ = clock_->Now();
221 }
222 }
223
224 bool SiteEngagementScore::UpdateScoreDict(base::DictionaryValue* score_dict) {
225 double raw_score_orig = 0;
226 double points_added_today_orig = 0;
227 double last_engagement_time_internal_orig = 0;
228 double last_shortcut_launch_time_internal_orig = 0;
229
230 score_dict->GetDouble(kRawScoreKey, &raw_score_orig);
231 score_dict->GetDouble(kPointsAddedTodayKey, &points_added_today_orig);
232 score_dict->GetDouble(kLastEngagementTimeKey,
233 &last_engagement_time_internal_orig);
234 score_dict->GetDouble(kLastShortcutLaunchTimeKey,
235 &last_shortcut_launch_time_internal_orig);
236 bool changed =
237 DoublesConsideredDifferent(raw_score_orig, raw_score_, kScoreDelta) ||
238 DoublesConsideredDifferent(points_added_today_orig, points_added_today_,
239 kScoreDelta) ||
240 DoublesConsideredDifferent(last_engagement_time_internal_orig,
241 last_engagement_time_.ToInternalValue(),
242 kTimeDelta) ||
243 DoublesConsideredDifferent(last_shortcut_launch_time_internal_orig,
244 last_shortcut_launch_time_.ToInternalValue(),
245 kTimeDelta);
246
247 if (!changed)
248 return false;
249
250 score_dict->SetDouble(kRawScoreKey, raw_score_);
251 score_dict->SetDouble(kPointsAddedTodayKey, points_added_today_);
252 score_dict->SetDouble(kLastEngagementTimeKey,
253 last_engagement_time_.ToInternalValue());
254 score_dict->SetDouble(kLastShortcutLaunchTimeKey,
255 last_shortcut_launch_time_.ToInternalValue());
256
257 return true;
258 }
259
260 SiteEngagementScore::SiteEngagementScore(base::Clock* clock)
261 : clock_(clock),
262 raw_score_(0),
263 points_added_today_(0),
264 last_engagement_time_(),
265 last_shortcut_launch_time_() {}
266
267 double SiteEngagementScore::DecayedScore() const {
268 // Note that users can change their clock, so from this system's perspective
269 // time can go backwards. If that does happen and the system detects that the
270 // current day is earlier than the last engagement, no decay (or growth) is
271 // applied.
272 int days_since_engagement = (clock_->Now() - last_engagement_time_).InDays();
273 if (days_since_engagement < 0)
274 return raw_score_;
275
276 int periods = days_since_engagement / GetDecayPeriodInDays();
277 return std::max(0.0, raw_score_ - periods * GetDecayPoints());
278 }
279
280 double SiteEngagementScore::BonusScore() const {
281 int days_since_shortcut_launch =
282 (clock_->Now() - last_shortcut_launch_time_).InDays();
283 if (days_since_shortcut_launch <= kMaxDaysSinceShortcutLaunch)
284 return GetWebAppInstalledPoints();
285
286 return 0;
287 }
288
289 void SiteEngagementScore::SetParamValuesForTesting() {
290 param_values[MAX_POINTS_PER_DAY] = 5;
291 param_values[DECAY_PERIOD_IN_DAYS] = 7;
292 param_values[DECAY_POINTS] = 5;
293 param_values[NAVIGATION_POINTS] = 0.5;
294 param_values[USER_INPUT_POINTS] = 0.05;
295 param_values[VISIBLE_MEDIA_POINTS] = 0.02;
296 param_values[HIDDEN_MEDIA_POINTS] = 0.01;
297 param_values[WEB_APP_INSTALLED_POINTS] = 5;
298 param_values[BOOTSTRAP_POINTS] = 8;
299 param_values[MEDIUM_ENGAGEMENT_BOUNDARY] = 5;
300 param_values[HIGH_ENGAGEMENT_BOUNDARY] = 50;
301
302 // This is set to zero to avoid interference with tests and is set when
303 // testing this functionality.
304 param_values[FIRST_DAILY_ENGAGEMENT] = 0;
305 }
OLDNEW
« no previous file with comments | « chrome/browser/engagement/site_engagement_score.h ('k') | chrome/browser/engagement/site_engagement_score_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698