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

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

Issue 1338603002: Implement a site engagement score based on time-on-site. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Adding tracing, fixing indentation 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"
8 #include "base/trace_event/trace_event.h"
7 #include "chrome/browser/engagement/site_engagement_service.h" 9 #include "chrome/browser/engagement/site_engagement_service.h"
8 #include "chrome/browser/engagement/site_engagement_service_factory.h" 10 #include "chrome/browser/engagement/site_engagement_service_factory.h"
9 #include "chrome/browser/prerender/prerender_contents.h" 11 #include "chrome/browser/prerender/prerender_contents.h"
10 #include "chrome/browser/profiles/profile.h" 12 #include "chrome/browser/profiles/profile.h"
11 #include "content/public/browser/navigation_entry.h" 13 #include "content/public/browser/navigation_entry.h"
12 #include "content/public/browser/web_contents.h" 14 #include "content/public/browser/web_contents.h"
13 15
16 namespace {
17
18 double g_seconds_between_user_input_check = 10;
19 bool g_disable_callback_registration_for_testing = false;
20
21 } // anonymous namespace
22
14 DEFINE_WEB_CONTENTS_USER_DATA_KEY(SiteEngagementHelper); 23 DEFINE_WEB_CONTENTS_USER_DATA_KEY(SiteEngagementHelper);
15 24
16 SiteEngagementHelper::~SiteEngagementHelper() { 25 SiteEngagementHelper::InputTracker::InputTracker(SiteEngagementHelper* helper)
26 : helper_(helper),
27 pause_timer_(new base::Timer(true, false)),
28 callbacks_added_(false) {
29 key_press_event_callback_ =
30 base::Bind(&SiteEngagementHelper::InputTracker::HandleKeyPressEvent,
31 base::Unretained(this));
32 mouse_event_callback_ =
33 base::Bind(&SiteEngagementHelper::InputTracker::HandleMouseEvent,
34 base::Unretained(this));
17 } 35 }
18 36
19 SiteEngagementHelper::SiteEngagementHelper(content::WebContents* web_contents) 37 SiteEngagementHelper::InputTracker::~InputTracker() { }
20 : content::WebContentsObserver(web_contents) { 38
39 // Record that there was some user input, and defer handling of the input event.
40 // web_contents() will return nullptr if the observed contents have been
41 // deleted; if the contents exist, record engagement for the site. Once the
42 // timer finishes running, the callbacks detecting user input will be registered
43 // again.
44 bool SiteEngagementHelper::InputTracker::HandleKeyPressEvent(
45 const content::NativeWebKeyboardEvent& event) {
46 // Only respond to raw key down to avoid multiple triggering on a single input
47 // (e.g. keypress is a key down then key up).
48 if (event.type == blink::WebInputEvent::RawKeyDown) {
49 PauseTracking(helper_->web_contents()->GetRenderViewHost());
50 helper_->RecordUserInput();
51 }
52 return false;
21 } 53 }
22 54
23 void SiteEngagementHelper::DidStartNavigationToPendingEntry( 55 bool SiteEngagementHelper::InputTracker::HandleMouseEvent(
24 const GURL& url, 56 const blink::WebMouseEvent& event) {
25 content::NavigationController::ReloadType reload_type) { 57 // Only respond to mouse down with a button or mouse move events (e.g. a click
26 prerender::PrerenderContents* prerender_contents = 58 // is a mouse down and mouse up) to avoid cases where multiple events come in
27 prerender::PrerenderContents::FromWebContents(web_contents()); 59 // before we can pause tracking.
60 if ((event.button != blink::WebMouseEvent::ButtonNone &&
61 event.type == blink::WebInputEvent::MouseDown) ||
62 event.type == blink::WebInputEvent::MouseWheel) {
63 PauseTracking(helper_->web_contents()->GetRenderViewHost());
64 helper_->RecordUserInput();
65 }
66 return false;
67 }
28 68
29 // Ignore pre-render loads. 69 void SiteEngagementHelper::InputTracker::StartTracking(
30 if (prerender_contents != NULL) 70 content::RenderViewHost* host) {
31 return; 71 if (!callbacks_added_ && !g_disable_callback_registration_for_testing) {
72 host->AddKeyPressEventCallback(key_press_event_callback_);
73 host->AddMouseEventCallback(mouse_event_callback_);
74 callbacks_added_ = true;
75 }
76 }
77
78 void SiteEngagementHelper::InputTracker::PauseTracking(
79 content::RenderViewHost* host) {
80 StopTracking(host);
81 pause_timer_->Start(
82 FROM_HERE,
83 base::TimeDelta::FromSeconds(g_seconds_between_user_input_check),
84 base::Bind(&SiteEngagementHelper::InputTracker::ResumeTracking,
85 base::Unretained(this)));
86 }
87
88 void SiteEngagementHelper::InputTracker::ResumeTracking() {
89 content::WebContents* contents = helper_->web_contents();
90 if (contents)
91 StartTracking(contents->GetRenderViewHost());
92 }
93
94 void SiteEngagementHelper::InputTracker::StopTracking(
95 content::RenderViewHost* host) {
96 pause_timer_->Stop();
97 if (callbacks_added_) {
98 host->RemoveKeyPressEventCallback(key_press_event_callback_);
99 host->RemoveMouseEventCallback(mouse_event_callback_);
100 callbacks_added_ = false;
101 }
102 }
103
104 void SiteEngagementHelper::InputTracker::SetTimerForTesting(
105 scoped_ptr<base::Timer> timer) {
106 pause_timer_ = timer.Pass();
107 }
108
109 SiteEngagementHelper::~SiteEngagementHelper() {
110 content::WebContents* contents = web_contents();
111 if (contents)
112 input_tracker_->StopTracking(contents->GetRenderViewHost());
113 }
114
115 void SiteEngagementHelper::AddObserverForTesting(Observer* observer) {
116 observer_list_.AddObserver(observer);
117 }
118
119 void SiteEngagementHelper::RemoveObserverForTesting(Observer* observer) {
120 observer_list_.RemoveObserver(observer);
121 }
122
123 SiteEngagementHelper::SiteEngagementHelper(content::WebContents* contents)
124 : content::WebContentsObserver(contents),
125 input_tracker_(new InputTracker(this)),
126 record_engagement_(false) { }
127
128 void SiteEngagementHelper::RecordUserInput() {
129 TRACE_EVENT0("SiteEngagement", "RecordUserInput");
130 content::WebContents* contents = web_contents();
131 if (contents) {
132 Profile* profile =
133 Profile::FromBrowserContext(contents->GetBrowserContext());
134 SiteEngagementService* service =
135 SiteEngagementServiceFactory::GetForProfile(profile);
136
137 // Service is null in incognito.
138 if (service) {
139 service->HandleUserInput(contents->GetVisibleURL());
140 FOR_EACH_OBSERVER(Observer, observer_list_, OnInputRecorded(this));
141 }
142 }
143 }
144
145 void SiteEngagementHelper::DidNavigateMainFrame(
146 const content::LoadCommittedDetails& details,
147 const content::FrameNavigateParams& params) {
148 content::WebContents* contents = web_contents();
149 input_tracker_->StopTracking(contents->GetRenderViewHost());
32 150
33 // Ignore all schemes except HTTP and HTTPS. 151 // Ignore all schemes except HTTP and HTTPS.
34 if (!url.SchemeIsHTTPOrHTTPS()) 152 record_engagement_ = params.url.SchemeIsHTTPOrHTTPS();
153
154 if (!record_engagement_)
35 return; 155 return;
36 156
37 Profile* profile = 157 Profile* profile =
38 Profile::FromBrowserContext(web_contents()->GetBrowserContext()); 158 Profile::FromBrowserContext(contents->GetBrowserContext());
39 SiteEngagementService* service = 159 SiteEngagementService* service =
40 SiteEngagementServiceFactory::GetForProfile(profile); 160 SiteEngagementServiceFactory::GetForProfile(profile);
41 // Service is null in incognito.
42 if (!service)
43 return;
44 161
45 service->HandleNavigation(url); 162 if (service)
163 service->HandleNavigation(params.url, params.transition);
164
165 input_tracker_->StartTracking(contents->GetRenderViewHost());
46 } 166 }
167
168 void SiteEngagementHelper::RenderViewHostChanged(
169 content::RenderViewHost* old_host,
170 content::RenderViewHost* new_host) {
171 // On changing the render view host, we need to re-register the callbacks
172 // listening for user input.
173 if (record_engagement_) {
174 if (old_host)
175 input_tracker_->StopTracking(old_host);
176 input_tracker_->StartTracking(new_host);
177 }
178 }
179
180 void SiteEngagementHelper::WasShown() {
181 // Ensure that the input callbacks are registered when we come into view.
182 if (record_engagement_)
183 input_tracker_->StartTracking(web_contents()->GetRenderViewHost());
184 }
185
186 void SiteEngagementHelper::WasHidden() {
187 // Ensure that the input callbacks are not registered when hidden.
188 if (record_engagement_) {
189 content::WebContents* contents = web_contents();
190 if (contents)
191 input_tracker_->StopTracking(contents->GetRenderViewHost());
192 }
193 }
194
195 // static
196 void SiteEngagementHelper::SetSecondsBetweenUserInputCheck(double seconds) {
197 g_seconds_between_user_input_check = seconds;
198 }
199
200 // static
201 void SiteEngagementHelper::EnableCallbackRegistrationForTesting() {
202 g_disable_callback_registration_for_testing = false;
203 }
204
205 // static
206 void SiteEngagementHelper::DisableCallbackRegistrationForTesting() {
207 g_disable_callback_registration_for_testing = true;
208 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698