1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/browser/search/search_terms_tracker.h"
7 #include "chrome/browser/profiles/profile.h"
8 #include "chrome/browser/search_engines/template_url.h"
9 #include "chrome/browser/search_engines/template_url_service.h"
10 #include "chrome/browser/search_engines/template_url_service_factory.h"
11 #include "content/public/browser/navigation_controller.h"
12 #include "content/public/browser/navigation_entry.h"
13 #include "content/public/browser/notification_details.h"
14 #include "content/public/browser/notification_service.h"
15 #include "content/public/browser/notification_source.h"
16 #include "content/public/browser/notification_types.h"
17 #include "content/public/browser/web_contents.h"
21 SearchTermsTracker::SearchTermsTracker() {
22 registrar_
.Add(this, content::NOTIFICATION_NAV_ENTRY_COMMITTED
,
23 content::NotificationService::AllSources());
24 registrar_
.Add(this, content::NOTIFICATION_NAV_ENTRY_CHANGED
,
25 content::NotificationService::AllSources());
26 registrar_
.Add(this, content::NOTIFICATION_WEB_CONTENTS_DESTROYED
,
27 content::NotificationService::AllSources());
30 SearchTermsTracker::~SearchTermsTracker() {
33 bool SearchTermsTracker::GetSearchTerms(
34 const content::WebContents
* contents
,
35 base::string16
* search_terms
,
36 int* navigation_index
) const {
38 TabState::const_iterator it
= tabs_
.find(contents
);
39 if (it
!= tabs_
.end() && !it
->second
.search_terms
.empty()) {
41 *search_terms
= it
->second
.search_terms
;
43 *navigation_index
= it
->second
.srp_navigation_index
;
50 void SearchTermsTracker::Observe(
52 const content::NotificationSource
& source
,
53 const content::NotificationDetails
& details
) {
55 case content::NOTIFICATION_NAV_ENTRY_COMMITTED
:
56 case content::NOTIFICATION_NAV_ENTRY_CHANGED
: {
57 content::NavigationController
* controller
=
58 content::Source
<content::NavigationController
>(source
).ptr();
60 if (FindMostRecentSearch(controller
, &search
))
61 tabs_
[controller
->GetWebContents()] = search
;
63 RemoveTabData(controller
->GetWebContents());
67 case content::NOTIFICATION_WEB_CONTENTS_DESTROYED
: {
68 RemoveTabData(content::Source
<content::WebContents
>(source
).ptr());
78 bool SearchTermsTracker::FindMostRecentSearch(
79 const content::NavigationController
* controller
,
80 SearchTermsTracker::TabData
* tab_data
) {
82 Profile::FromBrowserContext(controller
->GetBrowserContext());
87 TemplateURL
* template_url
=
88 TemplateURLServiceFactory::GetForProfile(profile
)->
89 GetDefaultSearchProvider();
91 for (int i
= controller
->GetCurrentEntryIndex(); i
>= 0; --i
) {
92 content::NavigationEntry
* entry
= controller
->GetEntryAtIndex(i
);
93 if (entry
->GetPageType() == content::PAGE_TYPE_NORMAL
) {
94 if (template_url
->IsSearchURL(entry
->GetURL())) {
95 // This entry is a search results page. Extract the terms only if this
96 // isn't the last (i.e. most recent/current) entry as we don't want to
97 // record the search terms when we're on an SRP.
98 if (i
!= controller
->GetCurrentEntryIndex()) {
99 tab_data
->srp_navigation_index
= i
;
100 template_url
->ExtractSearchTermsFromURL(entry
->GetURL(),
101 &tab_data
->search_terms
);
105 // We've found an SRP - stop searching (even if we did not record the
106 // search terms, as anything before this entry will be unrelated).
111 // Do not consider any navigations that precede a non-web-triggerable
112 // navigation as they are not related to those terms.
113 if (!content::PageTransitionIsWebTriggerable(
114 entry
->GetTransitionType())) {
122 void SearchTermsTracker::RemoveTabData(
123 const content::WebContents
* contents
) {
124 TabState::iterator it
= tabs_
.find(contents
);
125 if (it
!= tabs_
.end()) {
130 } // namespace chrome