Chromium Code Reviews| 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..16ec469c807c20c115bafbe81a0510c1a4180d97 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_delegate.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,146 @@ class AthenaTemplateURLServiceClient : public TemplateURLServiceClient { |
| DISALLOW_COPY_AND_ASSIGN(AthenaTemplateURLServiceClient); |
| }; |
| +// The AutocompleteProviderDelegate for Athena. |
| +class AthenaAutocompleteProviderDelegate : public AutocompleteProviderDelegate { |
| + public: |
| + explicit AthenaAutocompleteProviderDelegate( |
| + content::BrowserContext* browser_context) |
| + : browser_context_(browser_context) {} |
| + virtual ~AthenaAutocompleteProviderDelegate() {} |
| + |
| + virtual net::URLRequestContextGetter* RequestContext() OVERRIDE { |
| + return browser_context_->GetRequestContext(); |
| + } |
| + virtual bool IsOffTheRecord() OVERRIDE { |
| + return browser_context_->IsOffTheRecord(); |
| + } |
| + virtual std::string AcceptLanguages() OVERRIDE { |
| + return "en-US"; |
|
Jun Mukai
2014/08/27 17:03:20
Can you put a TODO comment here?
hashimoto
2014/08/28 06:30:09
Done.
|
| + } |
| + 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(AthenaAutocompleteProviderDelegate); |
| +}; |
| + |
| +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 +228,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<AutocompleteProviderDelegate>( |
| + new AthenaAutocompleteProviderDelegate(browser_context_)))) { |
| template_url_service_->Load(); |
| } |
| @@ -158,6 +240,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 +251,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 |