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

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

Issue 1388293002: Notify WebContentsObservers of user interactions. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Moving impl to RenderWidgetHost Created 5 years, 1 month 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"
12 #include "chrome/browser/profiles/profile.h" 11 #include "chrome/browser/profiles/profile.h"
13 #include "content/public/browser/navigation_entry.h" 12 #include "content/public/browser/navigation_entry.h"
14 #include "content/public/browser/web_contents.h" 13 #include "content/public/browser/web_contents.h"
15 14
16 namespace { 15 namespace {
17 16
18 int g_seconds_between_user_input_check = 10; 17 int g_seconds_between_user_input_check = 10;
19 int g_seconds_tracking_delay_after_navigation = 10; 18 int g_seconds_tracking_delay_after_navigation = 10;
20 int g_seconds_tracking_delay_after_show = 5; 19 int g_seconds_tracking_delay_after_show = 5;
21 20
22 } // anonymous namespace 21 } // anonymous namespace
23 22
24 DEFINE_WEB_CONTENTS_USER_DATA_KEY(SiteEngagementHelper); 23 DEFINE_WEB_CONTENTS_USER_DATA_KEY(SiteEngagementHelper);
25 24
26 SiteEngagementHelper::InputTracker::InputTracker(SiteEngagementHelper* helper) 25 SiteEngagementHelper::InputTracker::InputTracker(
27 : helper_(helper), 26 content::WebContents* web_contents,
27 SiteEngagementHelper* helper)
28 : WebContentsObserver(web_contents),
29 helper_(helper),
28 pause_timer_(new base::Timer(true, false)), 30 pause_timer_(new base::Timer(true, false)),
29 host_(nullptr), 31 is_tracking_(false) {}
30 is_tracking_(false) {
31 key_press_event_callback_ =
32 base::Bind(&SiteEngagementHelper::InputTracker::HandleKeyPressEvent,
33 base::Unretained(this));
34 mouse_event_callback_ =
35 base::Bind(&SiteEngagementHelper::InputTracker::HandleMouseEvent,
36 base::Unretained(this));
37 }
38 32
39 SiteEngagementHelper::InputTracker::~InputTracker() {} 33 SiteEngagementHelper::InputTracker::~InputTracker() {}
40 34
41 // Record that there was some user input, and defer handling of the input event. 35 void SiteEngagementHelper::InputTracker::Start(base::TimeDelta initial_delay) {
42 // web_contents() will return nullptr if the observed contents have been
43 // deleted; if the contents exist, record engagement for the site. Once the
44 // timer finishes running, the callbacks detecting user input will be registered
45 // again.
46 bool SiteEngagementHelper::InputTracker::HandleKeyPressEvent(
47 const content::NativeWebKeyboardEvent& event) {
48 // Only respond to raw key down to avoid multiple triggering on a single input
49 // (e.g. keypress is a key down then key up).
50 if (event.type == blink::WebInputEvent::RawKeyDown) {
51 Pause();
52 helper_->RecordUserInput(SiteEngagementMetrics::ENGAGEMENT_KEYPRESS);
53 }
54 return false;
55 }
56
57 bool SiteEngagementHelper::InputTracker::HandleMouseEvent(
58 const blink::WebMouseEvent& event) {
59 // Only respond to mouse down with a button or mouse move events (e.g. a click
60 // is a mouse down and mouse up) to avoid cases where multiple events come in
61 // before we can pause tracking.
62 if ((event.button != blink::WebMouseEvent::ButtonNone &&
63 event.type == blink::WebInputEvent::MouseDown) ||
64 event.type == blink::WebInputEvent::MouseWheel) {
65 Pause();
66 helper_->RecordUserInput(SiteEngagementMetrics::ENGAGEMENT_MOUSE);
67 }
68 return false;
69 }
70
71 void SiteEngagementHelper::InputTracker::Start(content::RenderViewHost* host,
72 base::TimeDelta initial_delay) {
73 DCHECK(!host_);
74 DCHECK(host);
75 host_ = host;
76 StartTimer(initial_delay); 36 StartTimer(initial_delay);
77 } 37 }
78 38
79 void SiteEngagementHelper::InputTracker::Pause() { 39 void SiteEngagementHelper::InputTracker::Pause() {
80 RemoveCallbacks(); 40 is_tracking_ = false;
81 StartTimer(base::TimeDelta::FromSeconds(g_seconds_between_user_input_check)); 41 StartTimer(base::TimeDelta::FromSeconds(g_seconds_between_user_input_check));
82 } 42 }
83 43
84 void SiteEngagementHelper::InputTracker::SwitchRenderViewHost(
85 content::RenderViewHost* old_host,
86 content::RenderViewHost* new_host) {
87 DCHECK(host_);
88 DCHECK(new_host);
89
90 bool was_tracking = is_tracking_;
91 if (old_host) {
92 DCHECK_EQ(host_, old_host);
93 RemoveCallbacks();
94 }
95
96 host_ = new_host;
97
98 if (was_tracking)
99 AddCallbacks();
100 }
101
102 void SiteEngagementHelper::InputTracker::Stop() { 44 void SiteEngagementHelper::InputTracker::Stop() {
45 is_tracking_ = false;
103 pause_timer_->Stop(); 46 pause_timer_->Stop();
104 RemoveCallbacks();
105 host_ = nullptr;
106 }
107
108 bool SiteEngagementHelper::InputTracker::IsActive() const {
109 return host_ != nullptr;
110 } 47 }
111 48
112 void SiteEngagementHelper::InputTracker::SetPauseTimerForTesting( 49 void SiteEngagementHelper::InputTracker::SetPauseTimerForTesting(
113 scoped_ptr<base::Timer> timer) { 50 scoped_ptr<base::Timer> timer) {
114 pause_timer_ = timer.Pass(); 51 pause_timer_ = timer.Pass();
115 } 52 }
116 53
117 void SiteEngagementHelper::InputTracker::StartTimer(base::TimeDelta delay) { 54 void SiteEngagementHelper::InputTracker::StartTimer(base::TimeDelta delay) {
118 pause_timer_->Start( 55 pause_timer_->Start(
119 FROM_HERE, delay, 56 FROM_HERE, delay,
120 base::Bind(&SiteEngagementHelper::InputTracker::AddCallbacks, 57 base::Bind(&SiteEngagementHelper::InputTracker::StartTracking,
121 base::Unretained(this))); 58 base::Unretained(this)));
122 } 59 }
123 60
124 void SiteEngagementHelper::InputTracker::AddCallbacks() { 61 void SiteEngagementHelper::InputTracker::StartTracking() {
125 content::WebContents* contents = helper_->web_contents();
126 if (!contents)
127 return;
128
129 host_->GetWidget()->AddKeyPressEventCallback(key_press_event_callback_);
130 host_->GetWidget()->AddMouseEventCallback(mouse_event_callback_);
131 is_tracking_ = true; 62 is_tracking_ = true;
132 } 63 }
133 64
134 void SiteEngagementHelper::InputTracker::RemoveCallbacks() { 65 // Record that there was some user input, and defer handling of the input event.
66 // Once the timer finishes running, the callbacks detecting user input will be
67 // registered again.
68 void SiteEngagementHelper::InputTracker::DidGetUserInteraction(
69 const blink::WebInputEvent::Type type) {
70 // Only respond to raw key down to avoid multiple triggering on a single input
71 // (e.g. keypress is a key down then key up).
135 if (is_tracking_) { 72 if (is_tracking_) {
calamity 2015/10/28 03:00:24 nit: Invert and early return.
dominickn 2015/10/28 03:28:17 Done.
136 host_->GetWidget()->RemoveKeyPressEventCallback(key_press_event_callback_); 73 if (type == blink::WebInputEvent::RawKeyDown) {
137 host_->GetWidget()->RemoveMouseEventCallback(mouse_event_callback_); 74 helper_->RecordUserInput(SiteEngagementMetrics::ENGAGEMENT_KEYPRESS);
138 is_tracking_ = false; 75 } else if (type == blink::WebInputEvent::MouseDown) {
76 helper_->RecordUserInput(SiteEngagementMetrics::ENGAGEMENT_MOUSE);
77 } else if (type == blink::WebInputEvent::GestureTapDown) {
calamity 2015/10/28 03:00:24 Consider a switch-case here.
dominickn 2015/10/28 03:28:17 Done.
78 helper_->RecordUserInput(SiteEngagementMetrics::ENGAGEMENT_GESTURE);
79 } else {
80 NOTREACHED();
81 }
82 Pause();
139 } 83 }
140 } 84 }
141 85
142 SiteEngagementHelper::~SiteEngagementHelper() { 86 SiteEngagementHelper::~SiteEngagementHelper() {
143 content::WebContents* contents = web_contents(); 87 content::WebContents* contents = web_contents();
144 if (contents) 88 if (contents)
145 input_tracker_.Stop(); 89 input_tracker_.Stop();
146 } 90 }
147 91
148 SiteEngagementHelper::SiteEngagementHelper(content::WebContents* contents) 92 SiteEngagementHelper::SiteEngagementHelper(content::WebContents* web_contents)
149 : content::WebContentsObserver(contents), 93 : content::WebContentsObserver(web_contents),
150 input_tracker_(this), 94 input_tracker_(web_contents, this),
151 record_engagement_(false) {} 95 record_engagement_(false) {}
152 96
153 void SiteEngagementHelper::RecordUserInput( 97 void SiteEngagementHelper::RecordUserInput(
154 SiteEngagementMetrics::EngagementType type) { 98 SiteEngagementMetrics::EngagementType type) {
155 TRACE_EVENT0("SiteEngagement", "RecordUserInput"); 99 TRACE_EVENT0("SiteEngagement", "RecordUserInput");
156 content::WebContents* contents = web_contents(); 100 content::WebContents* contents = web_contents();
157 if (contents) { 101 if (contents) {
158 Profile* profile = 102 Profile* profile =
159 Profile::FromBrowserContext(contents->GetBrowserContext()); 103 Profile::FromBrowserContext(contents->GetBrowserContext());
160 SiteEngagementService* service = 104 SiteEngagementService* service =
(...skipping 18 matching lines...) Expand all
179 123
180 Profile* profile = 124 Profile* profile =
181 Profile::FromBrowserContext(web_contents()->GetBrowserContext()); 125 Profile::FromBrowserContext(web_contents()->GetBrowserContext());
182 SiteEngagementService* service = 126 SiteEngagementService* service =
183 SiteEngagementServiceFactory::GetForProfile(profile); 127 SiteEngagementServiceFactory::GetForProfile(profile);
184 128
185 if (service) 129 if (service)
186 service->HandleNavigation(params.url, params.transition); 130 service->HandleNavigation(params.url, params.transition);
187 131
188 input_tracker_.Start( 132 input_tracker_.Start(
189 web_contents()->GetRenderViewHost(),
190 base::TimeDelta::FromSeconds(g_seconds_tracking_delay_after_navigation)); 133 base::TimeDelta::FromSeconds(g_seconds_tracking_delay_after_navigation));
191 } 134 }
192 135
193 void SiteEngagementHelper::RenderViewHostChanged(
194 content::RenderViewHost* old_host,
195 content::RenderViewHost* new_host) {
196 // On changing the render view host, we need to re-register the callbacks
197 // listening for user input.
198 if (input_tracker_.IsActive()) {
199 input_tracker_.SwitchRenderViewHost(old_host, new_host);
200 }
201 }
202
203 void SiteEngagementHelper::WasShown() { 136 void SiteEngagementHelper::WasShown() {
204 // Ensure that the input callbacks are registered when we come into view. 137 // Ensure that the input callbacks are registered when we come into view.
205 if (record_engagement_) { 138 if (record_engagement_) {
206 input_tracker_.Start( 139 input_tracker_.Start(
207 web_contents()->GetRenderViewHost(),
208 base::TimeDelta::FromSeconds(g_seconds_tracking_delay_after_show)); 140 base::TimeDelta::FromSeconds(g_seconds_tracking_delay_after_show));
209 } 141 }
210 } 142 }
211 143
212 void SiteEngagementHelper::WasHidden() { 144 void SiteEngagementHelper::WasHidden() {
213 // Ensure that the input callbacks are not registered when hidden. 145 // Ensure that the input callbacks are not registered when hidden.
214 input_tracker_.Stop(); 146 input_tracker_.Stop();
215 } 147 }
216 148
217 // static 149 // static
218 void SiteEngagementHelper::SetSecondsBetweenUserInputCheck(int seconds) { 150 void SiteEngagementHelper::SetSecondsBetweenUserInputCheck(int seconds) {
219 g_seconds_between_user_input_check = seconds; 151 g_seconds_between_user_input_check = seconds;
220 } 152 }
221 153
222 // static 154 // static
223 void SiteEngagementHelper::SetSecondsTrackingDelayAfterNavigation(int seconds) { 155 void SiteEngagementHelper::SetSecondsTrackingDelayAfterNavigation(int seconds) {
224 g_seconds_tracking_delay_after_navigation = seconds; 156 g_seconds_tracking_delay_after_navigation = seconds;
225 } 157 }
226 158
227 // static 159 // static
228 void SiteEngagementHelper::SetSecondsTrackingDelayAfterShow(int seconds) { 160 void SiteEngagementHelper::SetSecondsTrackingDelayAfterShow(int seconds) {
229 g_seconds_tracking_delay_after_show = seconds; 161 g_seconds_tracking_delay_after_show = seconds;
230 } 162 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698