blob: a99f9158a744b91c901b7d78e968acdc2bcae9fe [file] [log] [blame]
// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/search/search_terms_tracker.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/search_engines/template_url_service_factory.h"
#include "components/search_engines/template_url.h"
#include "components/search_engines/template_url_service.h"
#include "content/public/browser/navigation_controller.h"
#include "content/public/browser/navigation_entry.h"
#include "content/public/browser/notification_details.h"
#include "content/public/browser/notification_service.h"
#include "content/public/browser/notification_source.h"
#include "content/public/browser/notification_types.h"
#include "content/public/browser/web_contents.h"
namespace chrome {
SearchTermsTracker::SearchTermsTracker() {
registrar_.Add(this, content::NOTIFICATION_NAV_ENTRY_COMMITTED,
content::NotificationService::AllSources());
registrar_.Add(this, content::NOTIFICATION_NAV_ENTRY_CHANGED,
content::NotificationService::AllSources());
registrar_.Add(this, content::NOTIFICATION_WEB_CONTENTS_DESTROYED,
content::NotificationService::AllSources());
}
SearchTermsTracker::~SearchTermsTracker() {
}
bool SearchTermsTracker::GetSearchTerms(
const content::WebContents* contents,
base::string16* search_terms,
int* navigation_index) const {
if (contents) {
TabState::const_iterator it = tabs_.find(contents);
if (it != tabs_.end() && !it->second.search_terms.empty()) {
if (search_terms)
*search_terms = it->second.search_terms;
if (navigation_index)
*navigation_index = it->second.srp_navigation_index;
return true;
}
}
return false;
}
void SearchTermsTracker::Observe(
int type,
const content::NotificationSource& source,
const content::NotificationDetails& details) {
switch (type) {
case content::NOTIFICATION_NAV_ENTRY_COMMITTED:
case content::NOTIFICATION_NAV_ENTRY_CHANGED: {
content::NavigationController* controller =
content::Source<content::NavigationController>(source).ptr();
TabData search;
if (FindMostRecentSearch(controller, &search))
tabs_[controller->GetWebContents()] = search;
else
RemoveTabData(controller->GetWebContents());
break;
}
case content::NOTIFICATION_WEB_CONTENTS_DESTROYED: {
RemoveTabData(content::Source<content::WebContents>(source).ptr());
break;
}
default:
NOTREACHED();
return;
}
}
bool SearchTermsTracker::FindMostRecentSearch(
const content::NavigationController* controller,
SearchTermsTracker::TabData* tab_data) {
Profile* profile =
Profile::FromBrowserContext(controller->GetBrowserContext());
DCHECK(profile);
if (!profile)
return false;
TemplateURLService* service =
TemplateURLServiceFactory::GetForProfile(profile);
TemplateURL* template_url = service->GetDefaultSearchProvider();
for (int i = controller->GetCurrentEntryIndex(); i >= 0; --i) {
content::NavigationEntry* entry = controller->GetEntryAtIndex(i);
if (entry->GetPageType() == content::PAGE_TYPE_NORMAL) {
if (template_url->IsSearchURL(entry->GetURL(),
service->search_terms_data())) {
// This entry is a search results page. Extract the terms only if this
// isn't the last (i.e. most recent/current) entry as we don't want to
// record the search terms when we're on an SRP.
if (i != controller->GetCurrentEntryIndex()) {
tab_data->srp_navigation_index = i;
template_url->ExtractSearchTermsFromURL(entry->GetURL(),
service->search_terms_data(),
&tab_data->search_terms);
return true;
}
// We've found an SRP - stop searching (even if we did not record the
// search terms, as anything before this entry will be unrelated).
break;
}
}
// Do not consider any navigations that precede a non-web-triggerable
// navigation as they are not related to those terms.
if (!content::PageTransitionIsWebTriggerable(
entry->GetTransitionType())) {
break;
}
}
return false;
}
void SearchTermsTracker::RemoveTabData(
const content::WebContents* contents) {
TabState::iterator it = tabs_.find(contents);
if (it != tabs_.end()) {
tabs_.erase(it);
}
}
} // namespace chrome