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

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: Removing observer interface 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
20 } // anonymous namespace
21
14 DEFINE_WEB_CONTENTS_USER_DATA_KEY(SiteEngagementHelper); 22 DEFINE_WEB_CONTENTS_USER_DATA_KEY(SiteEngagementHelper);
15 23
16 SiteEngagementHelper::~SiteEngagementHelper() { 24 SiteEngagementHelper::InputTracker::InputTracker(SiteEngagementHelper* helper)
25 : helper_(helper),
26 pause_timer_(new base::Timer(true, false)),
27 callbacks_added_(false) {
28 key_press_event_callback_ =
29 base::Bind(&SiteEngagementHelper::InputTracker::HandleKeyPressEvent,
30 base::Unretained(this));
31 mouse_event_callback_ =
32 base::Bind(&SiteEngagementHelper::InputTracker::HandleMouseEvent,
33 base::Unretained(this));
17 } 34 }
18 35
19 SiteEngagementHelper::SiteEngagementHelper(content::WebContents* web_contents) 36 SiteEngagementHelper::InputTracker::~InputTracker() { }
20 : content::WebContentsObserver(web_contents) { 37
38 // 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
40 // deleted; if the contents exist, record engagement for the site. Once the
41 // timer finishes running, the callbacks detecting user input will be registered
42 // again.
43 bool SiteEngagementHelper::InputTracker::HandleKeyPressEvent(
44 const content::NativeWebKeyboardEvent& event) {
45 // 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).
47 if (event.type == blink::WebInputEvent::RawKeyDown) {
48 PauseTracking(helper_->web_contents()->GetRenderViewHost());
49 helper_->RecordUserInput();
50 }
51 return false;
21 } 52 }
22 53
23 void SiteEngagementHelper::DidStartNavigationToPendingEntry( 54 bool SiteEngagementHelper::InputTracker::HandleMouseEvent(
24 const GURL& url, 55 const blink::WebMouseEvent& event) {
jdduke (slow) 2015/09/29 15:20:36 So, WebMouseEvents won't actually include wheel ev
dominickn 2015/09/30 00:22:52 I had a look at DidGetUserGesture as the first thi
25 content::NavigationController::ReloadType reload_type) { 56 // Only respond to mouse down with a button or mouse move events (e.g. a click
26 prerender::PrerenderContents* prerender_contents = 57 // is a mouse down and mouse up) to avoid cases where multiple events come in
27 prerender::PrerenderContents::FromWebContents(web_contents()); 58 // before we can pause tracking.
59 if ((event.button != blink::WebMouseEvent::ButtonNone &&
60 event.type == blink::WebInputEvent::MouseDown) ||
61 event.type == blink::WebInputEvent::MouseWheel) {
62 PauseTracking(helper_->web_contents()->GetRenderViewHost());
63 helper_->RecordUserInput();
64 }
65 return false;
66 }
28 67
29 // Ignore pre-render loads. 68 void SiteEngagementHelper::InputTracker::StartTracking(
30 if (prerender_contents != NULL) 69 content::RenderViewHost* host) {
31 return; 70 if (!callbacks_added_) {
71 host->AddKeyPressEventCallback(key_press_event_callback_);
72 host->AddMouseEventCallback(mouse_event_callback_);
73 callbacks_added_ = true;
74 }
75 }
76
77 void SiteEngagementHelper::InputTracker::PauseTracking(
78 content::RenderViewHost* host) {
79 StopTracking(host);
80 pause_timer_->Start(
81 FROM_HERE,
82 base::TimeDelta::FromSeconds(g_seconds_between_user_input_check),
83 base::Bind(&SiteEngagementHelper::InputTracker::ResumeTracking,
84 base::Unretained(this)));
85 }
86
87 void SiteEngagementHelper::InputTracker::ResumeTracking() {
88 content::WebContents* contents = helper_->web_contents();
89 if (contents)
90 StartTracking(contents->GetRenderViewHost());
91 }
92
93 void SiteEngagementHelper::InputTracker::StopTracking(
94 content::RenderViewHost* host) {
95 pause_timer_->Stop();
96 if (callbacks_added_) {
97 host->RemoveKeyPressEventCallback(key_press_event_callback_);
98 host->RemoveMouseEventCallback(mouse_event_callback_);
99 callbacks_added_ = false;
100 }
101 }
102
103 void SiteEngagementHelper::InputTracker::SetTimerForTesting(
104 scoped_ptr<base::Timer> timer) {
105 pause_timer_ = timer.Pass();
106 }
107
108 SiteEngagementHelper::~SiteEngagementHelper() {
109 content::WebContents* contents = web_contents();
110 if (contents)
111 input_tracker_.StopTracking(contents->GetRenderViewHost());
112 }
113
114 SiteEngagementHelper::SiteEngagementHelper(content::WebContents* contents)
115 : content::WebContentsObserver(contents),
116 input_tracker_(this),
117 record_engagement_(false) { }
118
119 void SiteEngagementHelper::RecordUserInput() {
120 TRACE_EVENT0("SiteEngagement", "RecordUserInput");
121 content::WebContents* contents = web_contents();
122 if (contents) {
123 Profile* profile =
124 Profile::FromBrowserContext(contents->GetBrowserContext());
125 SiteEngagementService* service =
126 SiteEngagementServiceFactory::GetForProfile(profile);
127
128 // Service is null in incognito.
129 if (service)
130 service->HandleUserInput(contents->GetVisibleURL());
131 }
132 }
133
134 bool SiteEngagementHelper::ShouldRecordEngagement() {
135 return record_engagement_;
136 }
137
138 void SiteEngagementHelper::DidNavigateMainFrame(
139 const content::LoadCommittedDetails& details,
140 const content::FrameNavigateParams& params) {
141 content::WebContents* contents = web_contents();
142 input_tracker_.StopTracking(contents->GetRenderViewHost());
32 143
33 // Ignore all schemes except HTTP and HTTPS. 144 // Ignore all schemes except HTTP and HTTPS.
34 if (!url.SchemeIsHTTPOrHTTPS()) 145 record_engagement_ = params.url.SchemeIsHTTPOrHTTPS();
146
147 if (!ShouldRecordEngagement())
35 return; 148 return;
36 149
37 Profile* profile = 150 Profile* profile =
38 Profile::FromBrowserContext(web_contents()->GetBrowserContext()); 151 Profile::FromBrowserContext(contents->GetBrowserContext());
39 SiteEngagementService* service = 152 SiteEngagementService* service =
40 SiteEngagementServiceFactory::GetForProfile(profile); 153 SiteEngagementServiceFactory::GetForProfile(profile);
41 // Service is null in incognito.
42 if (!service)
43 return;
44 154
45 service->HandleNavigation(url); 155 if (service)
156 service->HandleNavigation(params.url, params.transition);
157
158 input_tracker_.StartTracking(contents->GetRenderViewHost());
46 } 159 }
160
161 void SiteEngagementHelper::RenderViewHostChanged(
162 content::RenderViewHost* old_host,
163 content::RenderViewHost* new_host) {
164 // On changing the render view host, we need to re-register the callbacks
165 // listening for user input.
166 if (ShouldRecordEngagement()) {
167 if (old_host)
168 input_tracker_.StopTracking(old_host);
169 input_tracker_.StartTracking(new_host);
170 }
171 }
172
173 void SiteEngagementHelper::WasShown() {
174 // Ensure that the input callbacks are registered when we come into view.
175 if (ShouldRecordEngagement())
176 input_tracker_.StartTracking(web_contents()->GetRenderViewHost());
177 }
178
179 void SiteEngagementHelper::WasHidden() {
180 // Ensure that the input callbacks are not registered when hidden.
181 if (ShouldRecordEngagement()) {
182 content::WebContents* contents = web_contents();
183 if (contents)
184 input_tracker_.StopTracking(contents->GetRenderViewHost());
185 }
186 }
187
188 // static
189 void SiteEngagementHelper::SetSecondsBetweenUserInputCheck(double seconds) {
190 g_seconds_between_user_input_check = seconds;
191 }
OLDNEW
« no previous file with comments | « chrome/browser/engagement/site_engagement_helper.h ('k') | chrome/browser/engagement/site_engagement_service.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698