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

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: Restore unit tests to test navigations Created 5 years, 3 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 "chrome/browser/engagement/site_engagement_service.h" 8 #include "chrome/browser/engagement/site_engagement_service.h"
8 #include "chrome/browser/engagement/site_engagement_service_factory.h" 9 #include "chrome/browser/engagement/site_engagement_service_factory.h"
9 #include "chrome/browser/prerender/prerender_contents.h" 10 #include "chrome/browser/prerender/prerender_contents.h"
10 #include "chrome/browser/profiles/profile.h" 11 #include "chrome/browser/profiles/profile.h"
11 #include "content/public/browser/navigation_entry.h" 12 #include "content/public/browser/navigation_entry.h"
12 #include "content/public/browser/web_contents.h" 13 #include "content/public/browser/web_contents.h"
13 14
15 namespace {
16
17 double gSecondsBetweenUserInputCheck = 10;
calamity 2015/09/22 02:57:20 The more common style seems to be g_seconds_betwee
dominickn 2015/09/23 00:06:44 Done.
18 bool gDisableCallbackRegistrationForTesting = false;
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 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 PauseTracking(helper_->web_contents()->GetRenderViewHost());
46 helper_->RecordUserInput();
calamity 2015/09/22 02:57:21 Does this mean the first input event can get recor
dominickn 2015/09/23 00:06:44 I can put in a one-shot timer to add that effect b
calamity 2015/09/24 03:50:53 Hmm, maybe we can save that for a follow-up, to ke
47 return false;
21 } 48 }
22 49
23 void SiteEngagementHelper::DidStartNavigationToPendingEntry( 50 bool SiteEngagementHelper::InputTracker::HandleMouseEvent(
24 const GURL& url, 51 const blink::WebMouseEvent& event) {
25 content::NavigationController::ReloadType reload_type) { 52 PauseTracking(helper_->web_contents()->GetRenderViewHost());
26 prerender::PrerenderContents* prerender_contents = 53 helper_->RecordUserInput();
27 prerender::PrerenderContents::FromWebContents(web_contents()); 54 return false;
55 }
28 56
29 // Ignore pre-render loads. 57 void SiteEngagementHelper::InputTracker::StartTracking(
30 if (prerender_contents != NULL) 58 content::RenderViewHost* host) {
31 return; 59 if (!callbacks_added_ && !gDisableCallbackRegistrationForTesting) {
60 host->AddKeyPressEventCallback(key_press_event_callback_);
61 host->AddMouseEventCallback(mouse_event_callback_);
62 callbacks_added_ = true;
63 }
64 }
65
66 void SiteEngagementHelper::InputTracker::PauseTracking(
67 content::RenderViewHost* host) {
68 StopTracking(host);
69 timer_->Start(FROM_HERE,
70 base::TimeDelta::FromSeconds(gSecondsBetweenUserInputCheck),
71 base::Bind(&SiteEngagementHelper::InputTracker::ResumeTracking,
72 base::Unretained(this)));
73 }
74
75 void SiteEngagementHelper::InputTracker::ResumeTracking() {
76 content::WebContents* contents = helper_->web_contents();
77 if (contents)
78 StartTracking(contents->GetRenderViewHost());
79 }
80
81 void SiteEngagementHelper::InputTracker::StopTracking(
82 content::RenderViewHost* host) {
83 timer_->Stop();
84 if (callbacks_added_) {
85 host->RemoveKeyPressEventCallback(key_press_event_callback_);
86 host->RemoveMouseEventCallback(mouse_event_callback_);
87 callbacks_added_ = false;
88 }
89 }
90
91 SiteEngagementHelper::~SiteEngagementHelper() {
92 content::WebContents* contents = web_contents();
93 if (contents)
94 tracker_->StopTracking(contents->GetRenderViewHost());
95 }
96
97 SiteEngagementHelper::SiteEngagementHelper(content::WebContents* contents)
98 : content::WebContentsObserver(contents),
99 tracker_(new InputTracker(this)),
100 record_engagement_(false) { }
101
102 void SiteEngagementHelper::RecordUserInput() {
103 content::WebContents* contents = web_contents();
104 if (contents) {
105 Profile* profile =
106 Profile::FromBrowserContext(contents->GetBrowserContext());
107 SiteEngagementService* service =
108 SiteEngagementServiceFactory::GetForProfile(profile);
109
110 // Service is null in incognito.
111 if (service)
112 service->HandleUserInput(contents->GetVisibleURL());
113 }
114 }
115
116 void SiteEngagementHelper::DidNavigateMainFrame(
117 const content::LoadCommittedDetails& details,
118 const content::FrameNavigateParams& params) {
119 content::WebContents* contents = web_contents();
120 tracker_->StopTracking(contents->GetRenderViewHost());
32 121
33 // Ignore all schemes except HTTP and HTTPS. 122 // Ignore all schemes except HTTP and HTTPS.
34 if (!url.SchemeIsHTTPOrHTTPS()) 123 record_engagement_ = params.url.SchemeIsHTTPOrHTTPS();
calamity 2015/09/22 02:57:21 Needing this bool is a bit unfortunate. Ideally, w
dominickn 2015/09/23 00:06:44 The issue I have with this is that it's the Helper
calamity 2015/09/24 03:50:53 Acknowledged.
35 return;
36 124
37 Profile* profile = 125 if (record_engagement_) {
calamity 2015/09/22 02:57:21 Invert and early return.
dominickn 2015/09/23 00:06:44 Done.
38 Profile::FromBrowserContext(web_contents()->GetBrowserContext()); 126 Profile* profile =
39 SiteEngagementService* service = 127 Profile::FromBrowserContext(contents->GetBrowserContext());
40 SiteEngagementServiceFactory::GetForProfile(profile); 128 SiteEngagementService* service =
41 // Service is null in incognito. 129 SiteEngagementServiceFactory::GetForProfile(profile);
42 if (!service)
43 return;
44 130
45 service->HandleNavigation(url); 131 if (service)
132 service->HandleNavigation(params.url, params.transition);
133
134 tracker_->StartTracking(contents->GetRenderViewHost());
135 }
46 } 136 }
137
138 void SiteEngagementHelper::RenderViewHostChanged(
139 content::RenderViewHost* old_host,
140 content::RenderViewHost* new_host) {
141 // On changing the render view host, we need to re-register the callbacks
142 // listening for user input.
143 if (record_engagement_) {
144 if (old_host)
145 tracker_->StopTracking(old_host);
146 tracker_->StartTracking(new_host);
147 }
148 }
149
150 void SiteEngagementHelper::WasShown() {
151 // Ensure that the input callbacks are registered when we come into view.
152 if (record_engagement_)
153 tracker_->StartTracking(web_contents()->GetRenderViewHost());
154 }
155
156 void SiteEngagementHelper::WasHidden() {
157 // Ensure that the input callbacks are not registered when hidden.
158 if (record_engagement_) {
159 content::WebContents* contents = web_contents();
160 if (contents)
161 tracker_->StopTracking(contents->GetRenderViewHost());
162 }
163 }
164
165 // static
166 void SiteEngagementHelper::SetSecondsBetweenUserInputCheck(double seconds) {
calamity 2015/09/22 02:57:20 SetSecondsBetweenUserInputCheckForTestsing
dominickn 2015/09/23 00:06:44 I'm assuming that this may be Finch'ed at some poi
calamity 2015/09/24 03:50:53 Acknowledged.
167 gSecondsBetweenUserInputCheck = seconds;
168 }
169
calamity 2015/09/22 02:57:20 // static
dominickn 2015/09/23 00:06:44 Done.
170 void SiteEngagementHelper::DisableCallbackRegistrationForTesting() {
171 gDisableCallbackRegistrationForTesting = true;
172 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698