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

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: Addressing nits 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.
135 if (is_tracking_) { 66 // Once the timer finishes running, the callbacks detecting user input will be
136 host_->GetWidget()->RemoveKeyPressEventCallback(key_press_event_callback_); 67 // registered again.
137 host_->GetWidget()->RemoveMouseEventCallback(mouse_event_callback_); 68 void SiteEngagementHelper::InputTracker::DidGetUserInteraction(
138 is_tracking_ = false; 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).
72 if (!is_tracking_)
73 return;
74
75 // This switch has a default NOTREACHED case because it will not test all
76 // of the values of the WebInputEvent::Type enum (hence it won't require the
77 // compiler verifying that all cases are covered).
78 switch (type) {
79 case blink::WebInputEvent::RawKeyDown:
80 helper_->RecordUserInput(SiteEngagementMetrics::ENGAGEMENT_KEYPRESS);
81 break;
82 case blink::WebInputEvent::MouseDown:
83 helper_->RecordUserInput(SiteEngagementMetrics::ENGAGEMENT_MOUSE);
84 break;
85 case blink::WebInputEvent::GestureTapDown:
86 helper_->RecordUserInput(SiteEngagementMetrics::ENGAGEMENT_TOUCH_GESTURE);
87 break;
88 default:
89 NOTREACHED();
139 } 90 }
91 Pause();
140 } 92 }
141 93
142 SiteEngagementHelper::~SiteEngagementHelper() { 94 SiteEngagementHelper::~SiteEngagementHelper() {
143 content::WebContents* contents = web_contents(); 95 content::WebContents* contents = web_contents();
144 if (contents) 96 if (contents)
145 input_tracker_.Stop(); 97 input_tracker_.Stop();
146 } 98 }
147 99
148 SiteEngagementHelper::SiteEngagementHelper(content::WebContents* contents) 100 SiteEngagementHelper::SiteEngagementHelper(content::WebContents* web_contents)
149 : content::WebContentsObserver(contents), 101 : content::WebContentsObserver(web_contents),
150 input_tracker_(this), 102 input_tracker_(web_contents, this),
151 record_engagement_(false) {} 103 record_engagement_(false) {}
152 104
153 void SiteEngagementHelper::RecordUserInput( 105 void SiteEngagementHelper::RecordUserInput(
154 SiteEngagementMetrics::EngagementType type) { 106 SiteEngagementMetrics::EngagementType type) {
155 TRACE_EVENT0("SiteEngagement", "RecordUserInput"); 107 TRACE_EVENT0("SiteEngagement", "RecordUserInput");
156 content::WebContents* contents = web_contents(); 108 content::WebContents* contents = web_contents();
157 if (contents) { 109 if (contents) {
158 Profile* profile = 110 Profile* profile =
159 Profile::FromBrowserContext(contents->GetBrowserContext()); 111 Profile::FromBrowserContext(contents->GetBrowserContext());
160 SiteEngagementService* service = 112 SiteEngagementService* service =
(...skipping 18 matching lines...) Expand all
179 131
180 Profile* profile = 132 Profile* profile =
181 Profile::FromBrowserContext(web_contents()->GetBrowserContext()); 133 Profile::FromBrowserContext(web_contents()->GetBrowserContext());
182 SiteEngagementService* service = 134 SiteEngagementService* service =
183 SiteEngagementServiceFactory::GetForProfile(profile); 135 SiteEngagementServiceFactory::GetForProfile(profile);
184 136
185 if (service) 137 if (service)
186 service->HandleNavigation(params.url, params.transition); 138 service->HandleNavigation(params.url, params.transition);
187 139
188 input_tracker_.Start( 140 input_tracker_.Start(
189 web_contents()->GetRenderViewHost(),
190 base::TimeDelta::FromSeconds(g_seconds_tracking_delay_after_navigation)); 141 base::TimeDelta::FromSeconds(g_seconds_tracking_delay_after_navigation));
191 } 142 }
192 143
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() { 144 void SiteEngagementHelper::WasShown() {
204 // Ensure that the input callbacks are registered when we come into view. 145 // Ensure that the input callbacks are registered when we come into view.
205 if (record_engagement_) { 146 if (record_engagement_) {
206 input_tracker_.Start( 147 input_tracker_.Start(
207 web_contents()->GetRenderViewHost(),
208 base::TimeDelta::FromSeconds(g_seconds_tracking_delay_after_show)); 148 base::TimeDelta::FromSeconds(g_seconds_tracking_delay_after_show));
209 } 149 }
210 } 150 }
211 151
212 void SiteEngagementHelper::WasHidden() { 152 void SiteEngagementHelper::WasHidden() {
213 // Ensure that the input callbacks are not registered when hidden. 153 // Ensure that the input callbacks are not registered when hidden.
214 input_tracker_.Stop(); 154 input_tracker_.Stop();
215 } 155 }
216 156
217 // static 157 // static
218 void SiteEngagementHelper::SetSecondsBetweenUserInputCheck(int seconds) { 158 void SiteEngagementHelper::SetSecondsBetweenUserInputCheck(int seconds) {
219 g_seconds_between_user_input_check = seconds; 159 g_seconds_between_user_input_check = seconds;
220 } 160 }
221 161
222 // static 162 // static
223 void SiteEngagementHelper::SetSecondsTrackingDelayAfterNavigation(int seconds) { 163 void SiteEngagementHelper::SetSecondsTrackingDelayAfterNavigation(int seconds) {
224 g_seconds_tracking_delay_after_navigation = seconds; 164 g_seconds_tracking_delay_after_navigation = seconds;
225 } 165 }
226 166
227 // static 167 // static
228 void SiteEngagementHelper::SetSecondsTrackingDelayAfterShow(int seconds) { 168 void SiteEngagementHelper::SetSecondsTrackingDelayAfterShow(int seconds) {
229 g_seconds_tracking_delay_after_show = seconds; 169 g_seconds_tracking_delay_after_show = seconds;
230 } 170 }
OLDNEW
« no previous file with comments | « chrome/browser/engagement/site_engagement_helper.h ('k') | chrome/browser/engagement/site_engagement_helper_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698