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

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

Issue 1373363005: Add a delay to Site Engagement tracking after navigation. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: address comments Created 5 years, 2 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_helper.h" 5 #include "chrome/browser/engagement/site_engagement_helper.h"
6 6
7 #include "base/time/time.h" 7 #include "base/time/time.h"
8 #include "base/trace_event/trace_event.h" 8 #include "base/trace_event/trace_event.h"
9 #include "chrome/browser/engagement/site_engagement_service.h" 9 #include "chrome/browser/engagement/site_engagement_service.h"
10 #include "chrome/browser/engagement/site_engagement_service_factory.h" 10 #include "chrome/browser/engagement/site_engagement_service_factory.h"
11 #include "chrome/browser/prerender/prerender_contents.h" 11 #include "chrome/browser/prerender/prerender_contents.h"
12 #include "chrome/browser/profiles/profile.h" 12 #include "chrome/browser/profiles/profile.h"
13 #include "content/public/browser/navigation_entry.h" 13 #include "content/public/browser/navigation_entry.h"
14 #include "content/public/browser/web_contents.h" 14 #include "content/public/browser/web_contents.h"
15 15
16 namespace { 16 namespace {
17 17
18 double g_seconds_between_user_input_check = 10; 18 int g_seconds_between_user_input_check = 10;
19 int g_seconds_tracking_delay_after_navigation = 10;
20 int g_seconds_tracking_delay_after_show = 5;
19 21
20 } // anonymous namespace 22 } // anonymous namespace
21 23
22 DEFINE_WEB_CONTENTS_USER_DATA_KEY(SiteEngagementHelper); 24 DEFINE_WEB_CONTENTS_USER_DATA_KEY(SiteEngagementHelper);
23 25
24 SiteEngagementHelper::InputTracker::InputTracker(SiteEngagementHelper* helper) 26 SiteEngagementHelper::InputTracker::InputTracker(SiteEngagementHelper* helper)
25 : helper_(helper), 27 : helper_(helper),
26 pause_timer_(new base::Timer(true, false)), 28 pause_timer_(new base::Timer(true, false)),
29 host_(nullptr),
30 is_tracking_(false),
27 callbacks_added_(false) { 31 callbacks_added_(false) {
28 key_press_event_callback_ = 32 key_press_event_callback_ =
29 base::Bind(&SiteEngagementHelper::InputTracker::HandleKeyPressEvent, 33 base::Bind(&SiteEngagementHelper::InputTracker::HandleKeyPressEvent,
30 base::Unretained(this)); 34 base::Unretained(this));
31 mouse_event_callback_ = 35 mouse_event_callback_ =
32 base::Bind(&SiteEngagementHelper::InputTracker::HandleMouseEvent, 36 base::Bind(&SiteEngagementHelper::InputTracker::HandleMouseEvent,
33 base::Unretained(this)); 37 base::Unretained(this));
34 } 38 }
35 39
36 SiteEngagementHelper::InputTracker::~InputTracker() { } 40 SiteEngagementHelper::InputTracker::~InputTracker() {}
37 41
38 // Record that there was some user input, and defer handling of the input event. 42 // Record that there was some user input, and defer handling of the input event.
39 // web_contents() will return nullptr if the observed contents have been 43 // web_contents() will return nullptr if the observed contents have been
40 // deleted; if the contents exist, record engagement for the site. Once the 44 // deleted; if the contents exist, record engagement for the site. Once the
41 // timer finishes running, the callbacks detecting user input will be registered 45 // timer finishes running, the callbacks detecting user input will be registered
42 // again. 46 // again.
43 bool SiteEngagementHelper::InputTracker::HandleKeyPressEvent( 47 bool SiteEngagementHelper::InputTracker::HandleKeyPressEvent(
44 const content::NativeWebKeyboardEvent& event) { 48 const content::NativeWebKeyboardEvent& event) {
45 // Only respond to raw key down to avoid multiple triggering on a single input 49 // Only respond to raw key down to avoid multiple triggering on a single input
46 // (e.g. keypress is a key down then key up). 50 // (e.g. keypress is a key down then key up).
47 if (event.type == blink::WebInputEvent::RawKeyDown) { 51 if (event.type == blink::WebInputEvent::RawKeyDown) {
48 PauseTracking(helper_->web_contents()->GetRenderViewHost()); 52 PauseTracking();
49 helper_->RecordUserInput(SiteEngagementMetrics::ENGAGEMENT_KEYPRESS); 53 helper_->RecordUserInput(SiteEngagementMetrics::ENGAGEMENT_KEYPRESS);
50 } 54 }
51 return false; 55 return false;
52 } 56 }
53 57
54 bool SiteEngagementHelper::InputTracker::HandleMouseEvent( 58 bool SiteEngagementHelper::InputTracker::HandleMouseEvent(
55 const blink::WebMouseEvent& event) { 59 const blink::WebMouseEvent& event) {
56 // Only respond to mouse down with a button or mouse move events (e.g. a click 60 // Only respond to mouse down with a button or mouse move events (e.g. a click
57 // is a mouse down and mouse up) to avoid cases where multiple events come in 61 // is a mouse down and mouse up) to avoid cases where multiple events come in
58 // before we can pause tracking. 62 // before we can pause tracking.
59 if ((event.button != blink::WebMouseEvent::ButtonNone && 63 if ((event.button != blink::WebMouseEvent::ButtonNone &&
60 event.type == blink::WebInputEvent::MouseDown) || 64 event.type == blink::WebInputEvent::MouseDown) ||
61 event.type == blink::WebInputEvent::MouseWheel) { 65 event.type == blink::WebInputEvent::MouseWheel) {
62 PauseTracking(helper_->web_contents()->GetRenderViewHost()); 66 PauseTracking();
63 helper_->RecordUserInput(SiteEngagementMetrics::ENGAGEMENT_MOUSE); 67 helper_->RecordUserInput(SiteEngagementMetrics::ENGAGEMENT_MOUSE);
64 } 68 }
65 return false; 69 return false;
66 } 70 }
67 71
68 void SiteEngagementHelper::InputTracker::StartTracking( 72 void SiteEngagementHelper::InputTracker::StartTracking(
69 content::RenderViewHost* host) { 73 content::RenderViewHost* host,
70 if (!callbacks_added_) { 74 base::TimeDelta initial_delay) {
71 host->AddKeyPressEventCallback(key_press_event_callback_); 75 DCHECK(!is_tracking_);
72 host->AddMouseEventCallback(mouse_event_callback_); 76 DCHECK(host);
73 callbacks_added_ = true; 77 host_ = host;
74 } 78 StartTimer(initial_delay);
79 is_tracking_ = true;
75 } 80 }
76 81
77 void SiteEngagementHelper::InputTracker::PauseTracking( 82 void SiteEngagementHelper::InputTracker::PauseTracking() {
78 content::RenderViewHost* host) { 83 RemoveCallbacks();
79 StopTracking(host); 84 StartTimer(base::TimeDelta::FromSeconds(g_seconds_between_user_input_check));
85 }
86
87 void SiteEngagementHelper::InputTracker::SwitchRenderViewHost(
88 content::RenderViewHost* new_host) {
89 DCHECK(is_tracking_);
90 DCHECK(new_host);
91 bool callbacks_were_added = callbacks_added_;
92 RemoveCallbacks();
dominickn 2015/10/07 05:38:50 I'm not sure it's safe to implement it this way: t
calamity 2015/10/07 07:13:34 Good catch. Fixed.
93 host_ = new_host;
94 if (callbacks_were_added)
95 AddCallbacks();
96 }
97
98 void SiteEngagementHelper::InputTracker::StopTracking() {
99 pause_timer_->Stop();
100 is_tracking_ = false;
101 RemoveCallbacks();
102 host_ = nullptr;
103 }
104
105 void SiteEngagementHelper::InputTracker::SetPauseTimerForTesting(
106 scoped_ptr<base::Timer> timer) {
107 pause_timer_ = timer.Pass();
108 }
109
110 void SiteEngagementHelper::InputTracker::StartTimer(base::TimeDelta delay) {
80 pause_timer_->Start( 111 pause_timer_->Start(
81 FROM_HERE, 112 FROM_HERE, delay,
82 base::TimeDelta::FromSeconds(g_seconds_between_user_input_check), 113 base::Bind(&SiteEngagementHelper::InputTracker::AddCallbacks,
83 base::Bind(&SiteEngagementHelper::InputTracker::ResumeTracking,
84 base::Unretained(this))); 114 base::Unretained(this)));
85 } 115 }
86 116
87 void SiteEngagementHelper::InputTracker::ResumeTracking() { 117 void SiteEngagementHelper::InputTracker::AddCallbacks() {
88 content::WebContents* contents = helper_->web_contents(); 118 content::WebContents* contents = helper_->web_contents();
89 if (contents) 119 if (!contents)
90 StartTracking(contents->GetRenderViewHost()); 120 return;
121
122 host_->AddKeyPressEventCallback(key_press_event_callback_);
123 host_->AddMouseEventCallback(mouse_event_callback_);
124 callbacks_added_ = true;
91 } 125 }
92 126
93 void SiteEngagementHelper::InputTracker::StopTracking( 127 void SiteEngagementHelper::InputTracker::RemoveCallbacks() {
94 content::RenderViewHost* host) {
95 pause_timer_->Stop();
96 if (callbacks_added_) { 128 if (callbacks_added_) {
97 host->RemoveKeyPressEventCallback(key_press_event_callback_); 129 host_->RemoveKeyPressEventCallback(key_press_event_callback_);
98 host->RemoveMouseEventCallback(mouse_event_callback_); 130 host_->RemoveMouseEventCallback(mouse_event_callback_);
99 callbacks_added_ = false; 131 callbacks_added_ = false;
100 } 132 }
101 } 133 }
102 134
103 void SiteEngagementHelper::InputTracker::SetTimerForTesting(
104 scoped_ptr<base::Timer> timer) {
105 pause_timer_ = timer.Pass();
106 }
107
108 SiteEngagementHelper::~SiteEngagementHelper() { 135 SiteEngagementHelper::~SiteEngagementHelper() {
109 content::WebContents* contents = web_contents(); 136 content::WebContents* contents = web_contents();
110 if (contents) 137 if (contents)
111 input_tracker_.StopTracking(contents->GetRenderViewHost()); 138 input_tracker_.StopTracking();
112 } 139 }
113 140
114 SiteEngagementHelper::SiteEngagementHelper(content::WebContents* contents) 141 SiteEngagementHelper::SiteEngagementHelper(content::WebContents* contents)
115 : content::WebContentsObserver(contents), 142 : content::WebContentsObserver(contents),
116 input_tracker_(this), 143 input_tracker_(this),
117 record_engagement_(false) { } 144 record_engagement_(false) {}
118 145
119 void SiteEngagementHelper::RecordUserInput( 146 void SiteEngagementHelper::RecordUserInput(
120 SiteEngagementMetrics::EngagementType type) { 147 SiteEngagementMetrics::EngagementType type) {
121 TRACE_EVENT0("SiteEngagement", "RecordUserInput"); 148 TRACE_EVENT0("SiteEngagement", "RecordUserInput");
122 content::WebContents* contents = web_contents(); 149 content::WebContents* contents = web_contents();
123 if (contents) { 150 if (contents) {
124 Profile* profile = 151 Profile* profile =
125 Profile::FromBrowserContext(contents->GetBrowserContext()); 152 Profile::FromBrowserContext(contents->GetBrowserContext());
126 SiteEngagementService* service = 153 SiteEngagementService* service =
127 SiteEngagementServiceFactory::GetForProfile(profile); 154 SiteEngagementServiceFactory::GetForProfile(profile);
128 155
129 // Service is null in incognito. 156 // Service is null in incognito.
130 if (service) 157 if (service)
131 service->HandleUserInput(contents->GetVisibleURL(), type); 158 service->HandleUserInput(contents->GetVisibleURL(), type);
132 } 159 }
133 } 160 }
134 161
135 bool SiteEngagementHelper::ShouldRecordEngagement() {
136 return record_engagement_;
137 }
138
139 void SiteEngagementHelper::DidNavigateMainFrame( 162 void SiteEngagementHelper::DidNavigateMainFrame(
140 const content::LoadCommittedDetails& details, 163 const content::LoadCommittedDetails& details,
141 const content::FrameNavigateParams& params) { 164 const content::FrameNavigateParams& params) {
142 content::WebContents* contents = web_contents(); 165 input_tracker_.StopTracking();
143 input_tracker_.StopTracking(contents->GetRenderViewHost()); 166
167 record_engagement_ = params.url.SchemeIsHTTPOrHTTPS();
144 168
145 // Ignore all schemes except HTTP and HTTPS. 169 // Ignore all schemes except HTTP and HTTPS.
146 record_engagement_ = params.url.SchemeIsHTTPOrHTTPS(); 170 if (!record_engagement_)
147
148 if (!ShouldRecordEngagement())
149 return; 171 return;
150 172
151 Profile* profile = 173 Profile* profile =
152 Profile::FromBrowserContext(contents->GetBrowserContext()); 174 Profile::FromBrowserContext(web_contents()->GetBrowserContext());
153 SiteEngagementService* service = 175 SiteEngagementService* service =
154 SiteEngagementServiceFactory::GetForProfile(profile); 176 SiteEngagementServiceFactory::GetForProfile(profile);
155 177
156 if (service) 178 if (service)
157 service->HandleNavigation(params.url, params.transition); 179 service->HandleNavigation(params.url, params.transition);
158 180
159 input_tracker_.StartTracking(contents->GetRenderViewHost()); 181 input_tracker_.StartTracking(
182 web_contents()->GetRenderViewHost(),
183 base::TimeDelta::FromSeconds(g_seconds_tracking_delay_after_navigation));
160 } 184 }
161 185
162 void SiteEngagementHelper::RenderViewHostChanged( 186 void SiteEngagementHelper::RenderViewHostChanged(
163 content::RenderViewHost* old_host, 187 content::RenderViewHost* old_host,
164 content::RenderViewHost* new_host) { 188 content::RenderViewHost* new_host) {
165 // On changing the render view host, we need to re-register the callbacks 189 // On changing the render view host, we need to re-register the callbacks
166 // listening for user input. 190 // listening for user input.
167 if (ShouldRecordEngagement()) { 191 if (input_tracker_.is_tracking()) {
168 if (old_host) 192 input_tracker_.SwitchRenderViewHost(new_host);
169 input_tracker_.StopTracking(old_host);
170 input_tracker_.StartTracking(new_host);
171 } 193 }
172 } 194 }
173 195
174 void SiteEngagementHelper::WasShown() { 196 void SiteEngagementHelper::WasShown() {
175 // Ensure that the input callbacks are registered when we come into view. 197 // Ensure that the input callbacks are registered when we come into view.
176 if (ShouldRecordEngagement()) 198 if (record_engagement_) {
177 input_tracker_.StartTracking(web_contents()->GetRenderViewHost()); 199 input_tracker_.StartTracking(
200 web_contents()->GetRenderViewHost(),
201 base::TimeDelta::FromSeconds(g_seconds_tracking_delay_after_show));
202 }
178 } 203 }
179 204
180 void SiteEngagementHelper::WasHidden() { 205 void SiteEngagementHelper::WasHidden() {
181 // Ensure that the input callbacks are not registered when hidden. 206 // Ensure that the input callbacks are not registered when hidden.
182 if (ShouldRecordEngagement()) { 207 input_tracker_.StopTracking();
183 content::WebContents* contents = web_contents();
184 if (contents)
185 input_tracker_.StopTracking(contents->GetRenderViewHost());
186 }
187 } 208 }
188 209
189 // static 210 // static
190 void SiteEngagementHelper::SetSecondsBetweenUserInputCheck(double seconds) { 211 void SiteEngagementHelper::SetSecondsBetweenUserInputCheck(int seconds) {
191 g_seconds_between_user_input_check = seconds; 212 g_seconds_between_user_input_check = seconds;
192 } 213 }
214
215 // static
216 void SiteEngagementHelper::SetSecondsTrackingDelayAfterNavigation(int seconds) {
217 g_seconds_tracking_delay_after_navigation = seconds;
218 }
219
220 // static
221 void SiteEngagementHelper::SetSecondsTrackingDelayAfterShow(int seconds) {
222 g_seconds_tracking_delay_after_show = seconds;
223 }
OLDNEW
« no previous file with comments | « chrome/browser/engagement/site_engagement_helper.h ('k') | chrome/browser/engagement/site_engagement_service_browsertest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698