| Index: athena/main/url_search_provider.cc
|
| diff --git a/athena/main/url_search_provider.cc b/athena/main/url_search_provider.cc
|
| index 6ab9498054899a08c5bdfec5eb677a03f463faa7..e2766c69356bc5596ad0c0b67f8ce291068de1d7 100644
|
| --- a/athena/main/url_search_provider.cc
|
| +++ b/athena/main/url_search_provider.cc
|
| @@ -11,17 +11,15 @@
|
| #include "components/metrics/proto/omnibox_event.pb.h"
|
| #include "components/metrics/proto/omnibox_input_type.pb.h"
|
| #include "components/omnibox/autocomplete_input.h"
|
| +#include "components/omnibox/autocomplete_provider_client.h"
|
| #include "components/omnibox/autocomplete_scheme_classifier.h"
|
| -#include "components/omnibox/search_suggestion_parser.h"
|
| +#include "components/omnibox/search_provider.h"
|
| #include "components/search_engines/search_terms_data.h"
|
| -#include "components/search_engines/template_url.h"
|
| #include "components/search_engines/template_url_service.h"
|
| #include "components/search_engines/template_url_service_client.h"
|
| #include "content/public/browser/browser_context.h"
|
| -#include "net/base/load_flags.h"
|
| -#include "net/url_request/url_fetcher.h"
|
| -#include "net/url_request/url_request.h"
|
| #include "ui/app_list/search_result.h"
|
| +#include "ui/base/resource/resource_bundle.h"
|
| #include "url/gurl.h"
|
|
|
| namespace athena {
|
| @@ -75,66 +73,147 @@ class AthenaTemplateURLServiceClient : public TemplateURLServiceClient {
|
| DISALLOW_COPY_AND_ASSIGN(AthenaTemplateURLServiceClient);
|
| };
|
|
|
| +// The AutocompleteProviderClient for Athena.
|
| +class AthenaAutocompleteProviderClient : public AutocompleteProviderClient {
|
| + public:
|
| + explicit AthenaAutocompleteProviderClient(
|
| + content::BrowserContext* browser_context)
|
| + : browser_context_(browser_context) {}
|
| + virtual ~AthenaAutocompleteProviderClient() {}
|
| +
|
| + virtual net::URLRequestContextGetter* RequestContext() OVERRIDE {
|
| + return browser_context_->GetRequestContext();
|
| + }
|
| + virtual bool IsOffTheRecord() OVERRIDE {
|
| + return browser_context_->IsOffTheRecord();
|
| + }
|
| + virtual std::string AcceptLanguages() OVERRIDE {
|
| + // TODO(hashimoto): Return the value stored in the prefs.
|
| + return "en-US";
|
| + }
|
| + virtual bool SearchSuggestEnabled() OVERRIDE { return true; }
|
| + virtual bool ShowBookmarkBar() OVERRIDE { return false; }
|
| + virtual const AutocompleteSchemeClassifier& SchemeClassifier() OVERRIDE {
|
| + return scheme_classifier_;
|
| + }
|
| + virtual void Classify(
|
| + const base::string16& text,
|
| + bool prefer_keyword,
|
| + bool allow_exact_keyword_match,
|
| + metrics::OmniboxEventProto::PageClassification page_classification,
|
| + AutocompleteMatch* match,
|
| + GURL* alternate_nav_url) OVERRIDE {}
|
| + virtual history::URLDatabase* InMemoryDatabase() OVERRIDE { return NULL; }
|
| + virtual void DeleteMatchingURLsForKeywordFromHistory(
|
| + history::KeywordID keyword_id,
|
| + const base::string16& term) OVERRIDE {}
|
| + virtual bool TabSyncEnabledAndUnencrypted() OVERRIDE { return false; }
|
| + virtual void PrefetchImage(const GURL& url) OVERRIDE {}
|
| +
|
| + private:
|
| + content::BrowserContext* browser_context_;
|
| + AthenaSchemeClassifier scheme_classifier_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(AthenaAutocompleteProviderClient);
|
| +};
|
| +
|
| +int ACMatchStyleToTagStyle(int styles) {
|
| + int tag_styles = 0;
|
| + if (styles & ACMatchClassification::URL)
|
| + tag_styles |= app_list::SearchResult::Tag::URL;
|
| + if (styles & ACMatchClassification::MATCH)
|
| + tag_styles |= app_list::SearchResult::Tag::MATCH;
|
| + if (styles & ACMatchClassification::DIM)
|
| + tag_styles |= app_list::SearchResult::Tag::DIM;
|
| +
|
| + return tag_styles;
|
| +}
|
| +
|
| +// Translates ACMatchClassifications into SearchResult tags.
|
| +void ACMatchClassificationsToTags(
|
| + const base::string16& text,
|
| + const ACMatchClassifications& text_classes,
|
| + app_list::SearchResult::Tags* tags) {
|
| + int tag_styles = app_list::SearchResult::Tag::NONE;
|
| + size_t tag_start = 0;
|
| +
|
| + for (size_t i = 0; i < text_classes.size(); ++i) {
|
| + const ACMatchClassification& text_class = text_classes[i];
|
| +
|
| + // Closes current tag.
|
| + if (tag_styles != app_list::SearchResult::Tag::NONE) {
|
| + tags->push_back(app_list::SearchResult::Tag(
|
| + tag_styles, tag_start, text_class.offset));
|
| + tag_styles = app_list::SearchResult::Tag::NONE;
|
| + }
|
| +
|
| + if (text_class.style == ACMatchClassification::NONE)
|
| + continue;
|
| +
|
| + tag_start = text_class.offset;
|
| + tag_styles = ACMatchStyleToTagStyle(text_class.style);
|
| + }
|
| +
|
| + if (tag_styles != app_list::SearchResult::Tag::NONE) {
|
| + tags->push_back(app_list::SearchResult::Tag(
|
| + tag_styles, tag_start, text.length()));
|
| + }
|
| +}
|
| +
|
| class UrlSearchResult : public app_list::SearchResult {
|
| public:
|
| UrlSearchResult(content::BrowserContext* browser_context,
|
| - const GURL& url,
|
| - const base::string16& title)
|
| + const AutocompleteMatch& match)
|
| : browser_context_(browser_context),
|
| - url_(url) {
|
| - set_title(title);
|
| - set_id(url_.spec());
|
| + match_(match) {
|
| + set_id(match_.destination_url.spec());
|
| +
|
| + // Derive relevance from omnibox relevance and normalize it to [0, 1].
|
| + // The magic number 1500 is the highest score of an omnibox result.
|
| + // See comments in autocomplete_provider.h.
|
| + set_relevance(match_.relevance / 1500.0);
|
| +
|
| + UpdateIcon();
|
| + UpdateTitleAndDetails();
|
| }
|
|
|
| + virtual ~UrlSearchResult() {}
|
| +
|
| private:
|
| // Overriddenn from app_list::SearchResult:
|
| virtual void Open(int event_flags) OVERRIDE {
|
| ActivityManager::Get()->AddActivity(
|
| - ActivityFactory::Get()->CreateWebActivity(browser_context_, url_));
|
| + ActivityFactory::Get()->CreateWebActivity(browser_context_,
|
| + match_.destination_url));
|
| + }
|
| +
|
| + void UpdateIcon() {
|
| + SetIcon(*ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed(
|
| + AutocompleteMatch::TypeToIcon(match_.type)));
|
| + }
|
| +
|
| + void UpdateTitleAndDetails() {
|
| + set_title(match_.contents);
|
| + SearchResult::Tags title_tags;
|
| + ACMatchClassificationsToTags(match_.contents,
|
| + match_.contents_class,
|
| + &title_tags);
|
| + set_title_tags(title_tags);
|
| +
|
| + set_details(match_.description);
|
| + SearchResult::Tags details_tags;
|
| + ACMatchClassificationsToTags(match_.description,
|
| + match_.description_class,
|
| + &details_tags);
|
| + set_details_tags(details_tags);
|
| }
|
|
|
| content::BrowserContext* browser_context_;
|
| - GURL url_;
|
| + AutocompleteMatch match_;
|
|
|
| DISALLOW_COPY_AND_ASSIGN(UrlSearchResult);
|
| };
|
|
|
| -scoped_ptr<app_list::SearchResult> CreateResultForSearchQuery(
|
| - content::BrowserContext* browser_context,
|
| - TemplateURLService* template_url_service,
|
| - const base::string16& search_query) {
|
| - TemplateURL* template_url =
|
| - template_url_service->GetDefaultSearchProvider();
|
| - const TemplateURLRef& search_url = template_url->url_ref();
|
| - TemplateURLRef::SearchTermsArgs search_terms_args(search_query);
|
| - return scoped_ptr<app_list::SearchResult>(new UrlSearchResult(
|
| - browser_context,
|
| - GURL(search_url.ReplaceSearchTerms(
|
| - search_terms_args, template_url_service->search_terms_data())),
|
| - search_query));
|
| -}
|
| -
|
| -scoped_ptr<app_list::SearchResult> CreateResultForInput(
|
| - content::BrowserContext* browser_context,
|
| - TemplateURLService* template_url_service,
|
| - const AutocompleteInput& input) {
|
| - scoped_ptr<app_list::SearchResult> result;
|
| - app_list::SearchResult::Tags title_tags;
|
| - if (input.type() == metrics::OmniboxInputType::URL) {
|
| - result.reset(new UrlSearchResult(
|
| - browser_context, input.canonicalized_url(), input.text()));
|
| - title_tags.push_back(app_list::SearchResult::Tag(
|
| - app_list::SearchResult::Tag::URL, 0, input.text().size()));
|
| - } else {
|
| - result = CreateResultForSearchQuery(
|
| - browser_context, template_url_service, input.text());
|
| - }
|
| - title_tags.push_back(app_list::SearchResult::Tag(
|
| - app_list::SearchResult::Tag::MATCH, 0, input.text().size()));
|
| - result->set_title_tags(title_tags);
|
| - return result.Pass();
|
| -}
|
| -
|
| } // namespace
|
|
|
| UrlSearchProvider::UrlSearchProvider(content::BrowserContext* browser_context)
|
| @@ -150,7 +229,11 @@ UrlSearchProvider::UrlSearchProvider(content::BrowserContext* browser_context)
|
| NULL /*GoogleURLTracker */,
|
| NULL /* RapporService */,
|
| base::Closure() /* dsp_change_callback */)),
|
| - should_fetch_suggestions_again_(false) {
|
| + provider_(new ::SearchProvider(
|
| + this,
|
| + template_url_service_.get(),
|
| + scoped_ptr<AutocompleteProviderClient>(
|
| + new AthenaAutocompleteProviderClient(browser_context_)))) {
|
| template_url_service_->Load();
|
| }
|
|
|
| @@ -158,6 +241,7 @@ UrlSearchProvider::~UrlSearchProvider() {
|
| }
|
|
|
| void UrlSearchProvider::Start(const base::string16& query) {
|
| + const bool minimal_changes = query == input_.text();
|
| input_ = AutocompleteInput(query,
|
| base::string16::npos /* cursor_position */,
|
| base::string16() /* desired_tld */,
|
| @@ -168,80 +252,29 @@ void UrlSearchProvider::Start(const base::string16& query) {
|
| true /* allow_extract_keyword_match */,
|
| true /* want_asynchronous_matches */,
|
| AthenaSchemeClassifier());
|
| - ClearResults();
|
| - Add(CreateResultForInput(browser_context_, template_url_service_.get(),
|
| - input_));
|
| - StartFetchingSuggestions();
|
| -}
|
|
|
| -void UrlSearchProvider::Stop() {
|
| - suggestion_fetcher_.reset();
|
| + provider_->Start(input_, minimal_changes);
|
| }
|
|
|
| -void UrlSearchProvider::OnURLFetchComplete(const net::URLFetcher* source) {
|
| - DCHECK_EQ(suggestion_fetcher_.get(), source);
|
| -
|
| - if (source->GetStatus().is_success() && source->GetResponseCode() == 200) {
|
| - std::string json_data = SearchSuggestionParser::ExtractJsonData(source);
|
| - scoped_ptr<base::Value> data(
|
| - SearchSuggestionParser::DeserializeJsonData(json_data));
|
| - if (data) {
|
| - const int kDefaultRelevance = 0;
|
| - SearchSuggestionParser::Results results;
|
| - if (SearchSuggestionParser::ParseSuggestResults(
|
| - *data, input_, AthenaSchemeClassifier(), kDefaultRelevance,
|
| - std::string(), // languages
|
| - false, // is_keyword_result
|
| - &results)) {
|
| - ClearResults();
|
| - Add(CreateResultForInput(browser_context_, template_url_service_.get(),
|
| - input_));
|
| - for (size_t i = 0; i < results.suggest_results.size(); ++i) {
|
| - const SearchSuggestionParser::SuggestResult& result =
|
| - results.suggest_results[i];
|
| - Add(CreateResultForSearchQuery(browser_context_,
|
| - template_url_service_.get(),
|
| - result.suggestion()));
|
| - }
|
| - for (size_t i = 0; i < results.navigation_results.size(); ++i) {
|
| - const SearchSuggestionParser::NavigationResult& result =
|
| - results.navigation_results[i];
|
| - Add(scoped_ptr<app_list::SearchResult>(
|
| - new UrlSearchResult(browser_context_, result.url(),
|
| - result.description())));
|
| - }
|
| - }
|
| - }
|
| - }
|
| - suggestion_fetcher_.reset();
|
| - if (should_fetch_suggestions_again_)
|
| - StartFetchingSuggestions();
|
| +void UrlSearchProvider::Stop() {
|
| + provider_->Stop(false);
|
| }
|
|
|
| -void UrlSearchProvider::StartFetchingSuggestions() {
|
| - if (suggestion_fetcher_) {
|
| - should_fetch_suggestions_again_ = true;
|
| - return;
|
| - }
|
| - should_fetch_suggestions_again_ = false;
|
| -
|
| - // Bail if the suggestion URL is invalid with the given replacements.
|
| - TemplateURL* template_url = template_url_service_->GetDefaultSearchProvider();
|
| - TemplateURLRef::SearchTermsArgs search_term_args(input_.text());
|
| - search_term_args.input_type = input_.type();
|
| - search_term_args.cursor_position = input_.cursor_position();
|
| - search_term_args.page_classification = input_.current_page_classification();
|
| - GURL suggest_url(template_url->suggestions_url_ref().ReplaceSearchTerms(
|
| - search_term_args, template_url_service_->search_terms_data()));
|
| - if (!suggest_url.is_valid()) {
|
| - DLOG(ERROR) << "Invalid URL: " << suggest_url;
|
| +void UrlSearchProvider::OnProviderUpdate(bool updated_matches) {
|
| + if (!updated_matches)
|
| return;
|
| +
|
| + ClearResults();
|
| +
|
| + const ACMatches& matches = provider_->matches();
|
| + for (ACMatches::const_iterator it = matches.begin(); it != matches.end();
|
| + ++it) {
|
| + if (!it->destination_url.is_valid())
|
| + continue;
|
| +
|
| + Add(scoped_ptr<app_list::SearchResult>(new UrlSearchResult(
|
| + browser_context_, *it)));
|
| }
|
| - suggestion_fetcher_.reset(
|
| - net::URLFetcher::Create(suggest_url, net::URLFetcher::GET, this));
|
| - suggestion_fetcher_->SetRequestContext(browser_context_->GetRequestContext());
|
| - suggestion_fetcher_->SetLoadFlags(net::LOAD_DO_NOT_SAVE_COOKIES);
|
| - suggestion_fetcher_->Start();
|
| }
|
|
|
| } // namespace athena
|
|
|