Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 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 "athena/main/url_search_provider.h" | 5 #include "athena/main/url_search_provider.h" |
| 6 | 6 |
| 7 #include "athena/activity/public/activity_factory.h" | 7 #include "athena/activity/public/activity_factory.h" |
| 8 #include "athena/activity/public/activity_manager.h" | 8 #include "athena/activity/public/activity_manager.h" |
| 9 #include "base/strings/utf_string_conversions.h" | 9 #include "base/strings/utf_string_conversions.h" |
| 10 #include "base/values.h" | 10 #include "base/values.h" |
| 11 #include "components/metrics/proto/omnibox_event.pb.h" | 11 #include "components/metrics/proto/omnibox_event.pb.h" |
| 12 #include "components/metrics/proto/omnibox_input_type.pb.h" | 12 #include "components/metrics/proto/omnibox_input_type.pb.h" |
| 13 #include "components/omnibox/autocomplete_input.h" | 13 #include "components/omnibox/autocomplete_input.h" |
| 14 #include "components/omnibox/autocomplete_provider_delegate.h" | |
| 14 #include "components/omnibox/autocomplete_scheme_classifier.h" | 15 #include "components/omnibox/autocomplete_scheme_classifier.h" |
| 15 #include "components/omnibox/search_suggestion_parser.h" | 16 #include "components/omnibox/search_provider.h" |
| 16 #include "components/search_engines/search_terms_data.h" | 17 #include "components/search_engines/search_terms_data.h" |
| 17 #include "components/search_engines/template_url.h" | |
| 18 #include "components/search_engines/template_url_service.h" | 18 #include "components/search_engines/template_url_service.h" |
| 19 #include "components/search_engines/template_url_service_client.h" | 19 #include "components/search_engines/template_url_service_client.h" |
| 20 #include "content/public/browser/browser_context.h" | 20 #include "content/public/browser/browser_context.h" |
| 21 #include "net/base/load_flags.h" | |
| 22 #include "net/url_request/url_fetcher.h" | |
| 23 #include "net/url_request/url_request.h" | |
| 24 #include "ui/app_list/search_result.h" | 21 #include "ui/app_list/search_result.h" |
| 22 #include "ui/base/resource/resource_bundle.h" | |
| 25 #include "url/gurl.h" | 23 #include "url/gurl.h" |
| 26 | 24 |
| 27 namespace athena { | 25 namespace athena { |
| 28 | 26 |
| 29 namespace { | 27 namespace { |
| 30 | 28 |
| 31 // The SearchTermsData implementation for Athena. | 29 // The SearchTermsData implementation for Athena. |
| 32 class AthenaSearchTermsData : public SearchTermsData { | 30 class AthenaSearchTermsData : public SearchTermsData { |
| 33 public: | 31 public: |
| 34 // SearchTermsData: | 32 // SearchTermsData: |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 68 const GURL& url, | 66 const GURL& url, |
| 69 TemplateURLID id, | 67 TemplateURLID id, |
| 70 const base::string16& term) OVERRIDE {} | 68 const base::string16& term) OVERRIDE {} |
| 71 virtual void AddKeywordGeneratedVisit(const GURL& url) OVERRIDE {} | 69 virtual void AddKeywordGeneratedVisit(const GURL& url) OVERRIDE {} |
| 72 virtual void RestoreExtensionInfoIfNecessary( | 70 virtual void RestoreExtensionInfoIfNecessary( |
| 73 TemplateURL* template_url) OVERRIDE {} | 71 TemplateURL* template_url) OVERRIDE {} |
| 74 | 72 |
| 75 DISALLOW_COPY_AND_ASSIGN(AthenaTemplateURLServiceClient); | 73 DISALLOW_COPY_AND_ASSIGN(AthenaTemplateURLServiceClient); |
| 76 }; | 74 }; |
| 77 | 75 |
| 76 // The AutocompleteProviderDelegate for Athena. | |
| 77 class AthenaAutocompleteProviderDelegate : public AutocompleteProviderDelegate { | |
| 78 public: | |
| 79 explicit AthenaAutocompleteProviderDelegate( | |
| 80 content::BrowserContext* browser_context) | |
| 81 : browser_context_(browser_context) {} | |
| 82 virtual ~AthenaAutocompleteProviderDelegate() {} | |
| 83 | |
| 84 virtual net::URLRequestContextGetter* RequestContext() OVERRIDE { | |
| 85 return browser_context_->GetRequestContext(); | |
| 86 } | |
| 87 virtual bool IsOffTheRecord() OVERRIDE { | |
| 88 return browser_context_->IsOffTheRecord(); | |
| 89 } | |
| 90 virtual std::string AcceptLanguages() OVERRIDE { | |
| 91 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.
| |
| 92 } | |
| 93 virtual bool SearchSuggestEnabled() OVERRIDE { return true; } | |
| 94 virtual bool ShowBookmarkBar() OVERRIDE { return false; } | |
| 95 virtual const AutocompleteSchemeClassifier& SchemeClassifier() OVERRIDE { | |
| 96 return scheme_classifier_; | |
| 97 } | |
| 98 virtual void Classify( | |
| 99 const base::string16& text, | |
| 100 bool prefer_keyword, | |
| 101 bool allow_exact_keyword_match, | |
| 102 metrics::OmniboxEventProto::PageClassification page_classification, | |
| 103 AutocompleteMatch* match, | |
| 104 GURL* alternate_nav_url) OVERRIDE {} | |
| 105 virtual history::URLDatabase* InMemoryDatabase() OVERRIDE { return NULL; } | |
| 106 virtual void DeleteMatchingURLsForKeywordFromHistory( | |
| 107 history::KeywordID keyword_id, | |
| 108 const base::string16& term) OVERRIDE {} | |
| 109 virtual bool TabSyncEnabledAndUnencrypted() OVERRIDE { return false; } | |
| 110 virtual void PrefetchImage(const GURL& url) OVERRIDE {} | |
| 111 | |
| 112 private: | |
| 113 content::BrowserContext* browser_context_; | |
| 114 AthenaSchemeClassifier scheme_classifier_; | |
| 115 | |
| 116 DISALLOW_COPY_AND_ASSIGN(AthenaAutocompleteProviderDelegate); | |
| 117 }; | |
| 118 | |
| 119 int ACMatchStyleToTagStyle(int styles) { | |
| 120 int tag_styles = 0; | |
| 121 if (styles & ACMatchClassification::URL) | |
| 122 tag_styles |= app_list::SearchResult::Tag::URL; | |
| 123 if (styles & ACMatchClassification::MATCH) | |
| 124 tag_styles |= app_list::SearchResult::Tag::MATCH; | |
| 125 if (styles & ACMatchClassification::DIM) | |
| 126 tag_styles |= app_list::SearchResult::Tag::DIM; | |
| 127 | |
| 128 return tag_styles; | |
| 129 } | |
| 130 | |
| 131 // Translates ACMatchClassifications into SearchResult tags. | |
| 132 void ACMatchClassificationsToTags( | |
| 133 const base::string16& text, | |
| 134 const ACMatchClassifications& text_classes, | |
| 135 app_list::SearchResult::Tags* tags) { | |
| 136 int tag_styles = app_list::SearchResult::Tag::NONE; | |
| 137 size_t tag_start = 0; | |
| 138 | |
| 139 for (size_t i = 0; i < text_classes.size(); ++i) { | |
| 140 const ACMatchClassification& text_class = text_classes[i]; | |
| 141 | |
| 142 // Closes current tag. | |
| 143 if (tag_styles != app_list::SearchResult::Tag::NONE) { | |
| 144 tags->push_back(app_list::SearchResult::Tag( | |
| 145 tag_styles, tag_start, text_class.offset)); | |
| 146 tag_styles = app_list::SearchResult::Tag::NONE; | |
| 147 } | |
| 148 | |
| 149 if (text_class.style == ACMatchClassification::NONE) | |
| 150 continue; | |
| 151 | |
| 152 tag_start = text_class.offset; | |
| 153 tag_styles = ACMatchStyleToTagStyle(text_class.style); | |
| 154 } | |
| 155 | |
| 156 if (tag_styles != app_list::SearchResult::Tag::NONE) { | |
| 157 tags->push_back(app_list::SearchResult::Tag( | |
| 158 tag_styles, tag_start, text.length())); | |
| 159 } | |
| 160 } | |
| 161 | |
| 78 class UrlSearchResult : public app_list::SearchResult { | 162 class UrlSearchResult : public app_list::SearchResult { |
| 79 public: | 163 public: |
| 80 UrlSearchResult(content::BrowserContext* browser_context, | 164 UrlSearchResult(content::BrowserContext* browser_context, |
| 81 const GURL& url, | 165 const AutocompleteMatch& match) |
| 82 const base::string16& title) | |
| 83 : browser_context_(browser_context), | 166 : browser_context_(browser_context), |
| 84 url_(url) { | 167 match_(match) { |
| 85 set_title(title); | 168 set_id(match_.destination_url.spec()); |
| 86 set_id(url_.spec()); | 169 |
| 170 // Derive relevance from omnibox relevance and normalize it to [0, 1]. | |
| 171 // The magic number 1500 is the highest score of an omnibox result. | |
| 172 // See comments in autocomplete_provider.h. | |
| 173 set_relevance(match_.relevance / 1500.0); | |
| 174 | |
| 175 UpdateIcon(); | |
| 176 UpdateTitleAndDetails(); | |
| 87 } | 177 } |
| 88 | 178 |
| 179 virtual ~UrlSearchResult() {} | |
| 180 | |
| 89 private: | 181 private: |
| 90 // Overriddenn from app_list::SearchResult: | 182 // Overriddenn from app_list::SearchResult: |
| 91 virtual void Open(int event_flags) OVERRIDE { | 183 virtual void Open(int event_flags) OVERRIDE { |
| 92 ActivityManager::Get()->AddActivity( | 184 ActivityManager::Get()->AddActivity( |
| 93 ActivityFactory::Get()->CreateWebActivity(browser_context_, url_)); | 185 ActivityFactory::Get()->CreateWebActivity(browser_context_, |
| 186 match_.destination_url)); | |
| 187 } | |
| 188 | |
| 189 void UpdateIcon() { | |
| 190 SetIcon(*ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed( | |
| 191 AutocompleteMatch::TypeToIcon(match_.type))); | |
| 192 } | |
| 193 | |
| 194 void UpdateTitleAndDetails() { | |
| 195 set_title(match_.contents); | |
| 196 SearchResult::Tags title_tags; | |
| 197 ACMatchClassificationsToTags(match_.contents, | |
| 198 match_.contents_class, | |
| 199 &title_tags); | |
| 200 set_title_tags(title_tags); | |
| 201 | |
| 202 set_details(match_.description); | |
| 203 SearchResult::Tags details_tags; | |
| 204 ACMatchClassificationsToTags(match_.description, | |
| 205 match_.description_class, | |
| 206 &details_tags); | |
| 207 set_details_tags(details_tags); | |
| 94 } | 208 } |
| 95 | 209 |
| 96 content::BrowserContext* browser_context_; | 210 content::BrowserContext* browser_context_; |
| 97 GURL url_; | 211 AutocompleteMatch match_; |
| 98 | 212 |
| 99 DISALLOW_COPY_AND_ASSIGN(UrlSearchResult); | 213 DISALLOW_COPY_AND_ASSIGN(UrlSearchResult); |
| 100 }; | 214 }; |
| 101 | 215 |
| 102 scoped_ptr<app_list::SearchResult> CreateResultForSearchQuery( | |
| 103 content::BrowserContext* browser_context, | |
| 104 TemplateURLService* template_url_service, | |
| 105 const base::string16& search_query) { | |
| 106 TemplateURL* template_url = | |
| 107 template_url_service->GetDefaultSearchProvider(); | |
| 108 const TemplateURLRef& search_url = template_url->url_ref(); | |
| 109 TemplateURLRef::SearchTermsArgs search_terms_args(search_query); | |
| 110 return scoped_ptr<app_list::SearchResult>(new UrlSearchResult( | |
| 111 browser_context, | |
| 112 GURL(search_url.ReplaceSearchTerms( | |
| 113 search_terms_args, template_url_service->search_terms_data())), | |
| 114 search_query)); | |
| 115 } | |
| 116 | |
| 117 scoped_ptr<app_list::SearchResult> CreateResultForInput( | |
| 118 content::BrowserContext* browser_context, | |
| 119 TemplateURLService* template_url_service, | |
| 120 const AutocompleteInput& input) { | |
| 121 scoped_ptr<app_list::SearchResult> result; | |
| 122 app_list::SearchResult::Tags title_tags; | |
| 123 if (input.type() == metrics::OmniboxInputType::URL) { | |
| 124 result.reset(new UrlSearchResult( | |
| 125 browser_context, input.canonicalized_url(), input.text())); | |
| 126 title_tags.push_back(app_list::SearchResult::Tag( | |
| 127 app_list::SearchResult::Tag::URL, 0, input.text().size())); | |
| 128 } else { | |
| 129 result = CreateResultForSearchQuery( | |
| 130 browser_context, template_url_service, input.text()); | |
| 131 } | |
| 132 title_tags.push_back(app_list::SearchResult::Tag( | |
| 133 app_list::SearchResult::Tag::MATCH, 0, input.text().size())); | |
| 134 result->set_title_tags(title_tags); | |
| 135 return result.Pass(); | |
| 136 } | |
| 137 | |
| 138 } // namespace | 216 } // namespace |
| 139 | 217 |
| 140 UrlSearchProvider::UrlSearchProvider(content::BrowserContext* browser_context) | 218 UrlSearchProvider::UrlSearchProvider(content::BrowserContext* browser_context) |
| 141 : browser_context_(browser_context), | 219 : browser_context_(browser_context), |
| 142 // TODO(mukai): introduce the real parameters when it's necessary. | 220 // TODO(mukai): introduce the real parameters when it's necessary. |
| 143 template_url_service_( | 221 template_url_service_( |
| 144 new TemplateURLService(NULL /* prefs */, | 222 new TemplateURLService(NULL /* prefs */, |
| 145 scoped_ptr<SearchTermsData>( | 223 scoped_ptr<SearchTermsData>( |
| 146 new AthenaSearchTermsData()), | 224 new AthenaSearchTermsData()), |
| 147 NULL /* KeywordWebDataService */, | 225 NULL /* KeywordWebDataService */, |
| 148 scoped_ptr<TemplateURLServiceClient>( | 226 scoped_ptr<TemplateURLServiceClient>( |
| 149 new AthenaTemplateURLServiceClient()), | 227 new AthenaTemplateURLServiceClient()), |
| 150 NULL /*GoogleURLTracker */, | 228 NULL /*GoogleURLTracker */, |
| 151 NULL /* RapporService */, | 229 NULL /* RapporService */, |
| 152 base::Closure() /* dsp_change_callback */)), | 230 base::Closure() /* dsp_change_callback */)), |
| 153 should_fetch_suggestions_again_(false) { | 231 provider_(new ::SearchProvider( |
| 232 this, | |
| 233 template_url_service_.get(), | |
| 234 scoped_ptr<AutocompleteProviderDelegate>( | |
| 235 new AthenaAutocompleteProviderDelegate(browser_context_)))) { | |
| 154 template_url_service_->Load(); | 236 template_url_service_->Load(); |
| 155 } | 237 } |
| 156 | 238 |
| 157 UrlSearchProvider::~UrlSearchProvider() { | 239 UrlSearchProvider::~UrlSearchProvider() { |
| 158 } | 240 } |
| 159 | 241 |
| 160 void UrlSearchProvider::Start(const base::string16& query) { | 242 void UrlSearchProvider::Start(const base::string16& query) { |
| 243 const bool minimal_changes = query == input_.text(); | |
| 161 input_ = AutocompleteInput(query, | 244 input_ = AutocompleteInput(query, |
| 162 base::string16::npos /* cursor_position */, | 245 base::string16::npos /* cursor_position */, |
| 163 base::string16() /* desired_tld */, | 246 base::string16() /* desired_tld */, |
| 164 GURL() /* current_url */, | 247 GURL() /* current_url */, |
| 165 metrics::OmniboxEventProto::INVALID_SPEC, | 248 metrics::OmniboxEventProto::INVALID_SPEC, |
| 166 false /* prevent_inline_autocomplete */, | 249 false /* prevent_inline_autocomplete */, |
| 167 false /* prefer_keyword */, | 250 false /* prefer_keyword */, |
| 168 true /* allow_extract_keyword_match */, | 251 true /* allow_extract_keyword_match */, |
| 169 true /* want_asynchronous_matches */, | 252 true /* want_asynchronous_matches */, |
| 170 AthenaSchemeClassifier()); | 253 AthenaSchemeClassifier()); |
| 171 ClearResults(); | 254 |
| 172 Add(CreateResultForInput(browser_context_, template_url_service_.get(), | 255 provider_->Start(input_, minimal_changes); |
| 173 input_)); | |
| 174 StartFetchingSuggestions(); | |
| 175 } | 256 } |
| 176 | 257 |
| 177 void UrlSearchProvider::Stop() { | 258 void UrlSearchProvider::Stop() { |
| 178 suggestion_fetcher_.reset(); | 259 provider_->Stop(false); |
| 179 } | 260 } |
| 180 | 261 |
| 181 void UrlSearchProvider::OnURLFetchComplete(const net::URLFetcher* source) { | 262 void UrlSearchProvider::OnProviderUpdate(bool updated_matches) { |
| 182 DCHECK_EQ(suggestion_fetcher_.get(), source); | 263 if (!updated_matches) |
| 264 return; | |
| 183 | 265 |
| 184 if (source->GetStatus().is_success() && source->GetResponseCode() == 200) { | 266 ClearResults(); |
| 185 std::string json_data = SearchSuggestionParser::ExtractJsonData(source); | 267 |
| 186 scoped_ptr<base::Value> data( | 268 const ACMatches& matches = provider_->matches(); |
| 187 SearchSuggestionParser::DeserializeJsonData(json_data)); | 269 for (ACMatches::const_iterator it = matches.begin(); it != matches.end(); |
| 188 if (data) { | 270 ++it) { |
| 189 const int kDefaultRelevance = 0; | 271 if (!it->destination_url.is_valid()) |
| 190 SearchSuggestionParser::Results results; | 272 continue; |
| 191 if (SearchSuggestionParser::ParseSuggestResults( | 273 |
| 192 *data, input_, AthenaSchemeClassifier(), kDefaultRelevance, | 274 Add(scoped_ptr<app_list::SearchResult>(new UrlSearchResult( |
| 193 std::string(), // languages | 275 browser_context_, *it))); |
| 194 false, // is_keyword_result | |
| 195 &results)) { | |
| 196 ClearResults(); | |
| 197 Add(CreateResultForInput(browser_context_, template_url_service_.get(), | |
| 198 input_)); | |
| 199 for (size_t i = 0; i < results.suggest_results.size(); ++i) { | |
| 200 const SearchSuggestionParser::SuggestResult& result = | |
| 201 results.suggest_results[i]; | |
| 202 Add(CreateResultForSearchQuery(browser_context_, | |
| 203 template_url_service_.get(), | |
| 204 result.suggestion())); | |
| 205 } | |
| 206 for (size_t i = 0; i < results.navigation_results.size(); ++i) { | |
| 207 const SearchSuggestionParser::NavigationResult& result = | |
| 208 results.navigation_results[i]; | |
| 209 Add(scoped_ptr<app_list::SearchResult>( | |
| 210 new UrlSearchResult(browser_context_, result.url(), | |
| 211 result.description()))); | |
| 212 } | |
| 213 } | |
| 214 } | |
| 215 } | 276 } |
| 216 suggestion_fetcher_.reset(); | |
| 217 if (should_fetch_suggestions_again_) | |
| 218 StartFetchingSuggestions(); | |
| 219 } | |
| 220 | |
| 221 void UrlSearchProvider::StartFetchingSuggestions() { | |
| 222 if (suggestion_fetcher_) { | |
| 223 should_fetch_suggestions_again_ = true; | |
| 224 return; | |
| 225 } | |
| 226 should_fetch_suggestions_again_ = false; | |
| 227 | |
| 228 // Bail if the suggestion URL is invalid with the given replacements. | |
| 229 TemplateURL* template_url = template_url_service_->GetDefaultSearchProvider(); | |
| 230 TemplateURLRef::SearchTermsArgs search_term_args(input_.text()); | |
| 231 search_term_args.input_type = input_.type(); | |
| 232 search_term_args.cursor_position = input_.cursor_position(); | |
| 233 search_term_args.page_classification = input_.current_page_classification(); | |
| 234 GURL suggest_url(template_url->suggestions_url_ref().ReplaceSearchTerms( | |
| 235 search_term_args, template_url_service_->search_terms_data())); | |
| 236 if (!suggest_url.is_valid()) { | |
| 237 DLOG(ERROR) << "Invalid URL: " << suggest_url; | |
| 238 return; | |
| 239 } | |
| 240 suggestion_fetcher_.reset( | |
| 241 net::URLFetcher::Create(suggest_url, net::URLFetcher::GET, this)); | |
| 242 suggestion_fetcher_->SetRequestContext(browser_context_->GetRequestContext()); | |
| 243 suggestion_fetcher_->SetLoadFlags(net::LOAD_DO_NOT_SAVE_COOKIES); | |
| 244 suggestion_fetcher_->Start(); | |
| 245 } | 277 } |
| 246 | 278 |
| 247 } // namespace athena | 279 } // namespace athena |
| OLD | NEW |