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 "components/autocomplete/autocomplete_input.h" | 11 #include "components/autocomplete/autocomplete_input.h" |
11 #include "components/autocomplete/autocomplete_scheme_classifier.h" | 12 #include "components/autocomplete/autocomplete_scheme_classifier.h" |
| 13 #include "components/autocomplete/search_suggestion_parser.h" |
12 #include "components/metrics/proto/omnibox_event.pb.h" | 14 #include "components/metrics/proto/omnibox_event.pb.h" |
13 #include "components/metrics/proto/omnibox_input_type.pb.h" | 15 #include "components/metrics/proto/omnibox_input_type.pb.h" |
14 #include "components/search_engines/search_terms_data.h" | 16 #include "components/search_engines/search_terms_data.h" |
15 #include "components/search_engines/template_url.h" | 17 #include "components/search_engines/template_url.h" |
16 #include "components/search_engines/template_url_service.h" | 18 #include "components/search_engines/template_url_service.h" |
17 #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" |
| 21 #include "net/base/load_flags.h" |
| 22 #include "net/url_request/url_fetcher.h" |
18 #include "net/url_request/url_request.h" | 23 #include "net/url_request/url_request.h" |
19 #include "ui/app_list/search_result.h" | 24 #include "ui/app_list/search_result.h" |
20 #include "url/gurl.h" | 25 #include "url/gurl.h" |
21 | 26 |
22 namespace athena { | 27 namespace athena { |
23 | 28 |
24 namespace { | 29 namespace { |
25 | 30 |
| 31 // The SearchTermsData implementation for Athena. |
| 32 class AthenaSearchTermsData : public SearchTermsData { |
| 33 public: |
| 34 // SearchTermsData: |
| 35 virtual std::string GetSuggestClient() const OVERRIDE { |
| 36 return "chrome"; |
| 37 } |
| 38 }; |
| 39 |
26 // The AutocompleteSchemeClassifier implementation for Athena. | 40 // The AutocompleteSchemeClassifier implementation for Athena. |
27 // TODO(mukai): Introduce supports of normal schemes like about: or blob: | 41 // TODO(mukai): Introduce supports of normal schemes like about: or blob: |
28 class AthenaSchemeClassifier : public AutocompleteSchemeClassifier { | 42 class AthenaSchemeClassifier : public AutocompleteSchemeClassifier { |
29 public: | 43 public: |
30 AthenaSchemeClassifier() {} | 44 AthenaSchemeClassifier() {} |
31 | 45 |
32 // AutocompleteSchemeClassifier: | 46 // AutocompleteSchemeClassifier: |
33 virtual metrics::OmniboxInputType::Type GetInputTypeForScheme( | 47 virtual metrics::OmniboxInputType::Type GetInputTypeForScheme( |
34 const std::string& scheme) const OVERRIDE { | 48 const std::string& scheme) const OVERRIDE { |
35 if (net::URLRequest::IsHandledProtocol(scheme)) | 49 if (net::URLRequest::IsHandledProtocol(scheme)) |
(...skipping 21 matching lines...) Expand all Loading... |
57 virtual void AddKeywordGeneratedVisit(const GURL& url) OVERRIDE {} | 71 virtual void AddKeywordGeneratedVisit(const GURL& url) OVERRIDE {} |
58 virtual void RestoreExtensionInfoIfNecessary( | 72 virtual void RestoreExtensionInfoIfNecessary( |
59 TemplateURL* template_url) OVERRIDE {} | 73 TemplateURL* template_url) OVERRIDE {} |
60 | 74 |
61 DISALLOW_COPY_AND_ASSIGN(AthenaTemplateURLServiceClient); | 75 DISALLOW_COPY_AND_ASSIGN(AthenaTemplateURLServiceClient); |
62 }; | 76 }; |
63 | 77 |
64 class UrlSearchResult : public app_list::SearchResult { | 78 class UrlSearchResult : public app_list::SearchResult { |
65 public: | 79 public: |
66 UrlSearchResult(content::BrowserContext* browser_context, | 80 UrlSearchResult(content::BrowserContext* browser_context, |
67 TemplateURLService* template_url_service, | 81 const GURL& url, |
68 const base::string16& query) | 82 const base::string16& title) |
69 : browser_context_(browser_context), | 83 : browser_context_(browser_context), |
70 template_url_service_(template_url_service), | 84 url_(url) { |
71 input_(query, | 85 set_title(title); |
72 base::string16::npos /* cursor_position */, | 86 set_id(url_.spec()); |
73 base::string16() /* desired_tld */, | |
74 GURL() /* current_url */, | |
75 metrics::OmniboxEventProto::INVALID_SPEC, | |
76 false /* prevent_inline_autocomplete */, | |
77 false /* prefer_keyword */, | |
78 true /* allow_extract_keyword_match */, | |
79 true /* want_asynchronous_matches */, | |
80 AthenaSchemeClassifier()) { | |
81 set_title(query); | |
82 app_list::SearchResult::Tags title_tags; | |
83 if (input_.type() == metrics::OmniboxInputType::URL) { | |
84 title_tags.push_back(app_list::SearchResult::Tag( | |
85 app_list::SearchResult::Tag::URL, 0, query.size())); | |
86 } | |
87 title_tags.push_back(app_list::SearchResult::Tag( | |
88 app_list::SearchResult::Tag::MATCH, 0, query.size())); | |
89 set_title_tags(title_tags); | |
90 set_id(base::UTF16ToUTF8(query)); | |
91 } | 87 } |
92 | 88 |
93 private: | 89 private: |
94 // Overriddenn from app_list::SearchResult: | 90 // Overriddenn from app_list::SearchResult: |
95 virtual void Open(int event_flags) OVERRIDE { | 91 virtual void Open(int event_flags) OVERRIDE { |
96 GURL url; | |
97 if (input_.type() == metrics::OmniboxInputType::URL) { | |
98 url = input_.canonicalized_url(); | |
99 } else { | |
100 TemplateURL* template_url = | |
101 template_url_service_->GetDefaultSearchProvider(); | |
102 const TemplateURLRef& search_url = template_url->url_ref(); | |
103 TemplateURLRef::SearchTermsArgs search_terms_args(input_.text()); | |
104 url = GURL(search_url.ReplaceSearchTerms( | |
105 search_terms_args, template_url_service_->search_terms_data())); | |
106 } | |
107 ActivityManager::Get()->AddActivity( | 92 ActivityManager::Get()->AddActivity( |
108 ActivityFactory::Get()->CreateWebActivity(browser_context_, url)); | 93 ActivityFactory::Get()->CreateWebActivity(browser_context_, url_)); |
109 } | 94 } |
110 | 95 |
111 content::BrowserContext* browser_context_; | 96 content::BrowserContext* browser_context_; |
112 TemplateURLService* template_url_service_; | 97 GURL url_; |
113 AutocompleteInput input_; | |
114 | 98 |
115 DISALLOW_COPY_AND_ASSIGN(UrlSearchResult); | 99 DISALLOW_COPY_AND_ASSIGN(UrlSearchResult); |
116 }; | 100 }; |
117 | 101 |
| 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 |
118 } // namespace | 138 } // namespace |
119 | 139 |
120 UrlSearchProvider::UrlSearchProvider(content::BrowserContext* browser_context) | 140 UrlSearchProvider::UrlSearchProvider(content::BrowserContext* browser_context) |
121 : browser_context_(browser_context), | 141 : browser_context_(browser_context), |
122 // TODO(mukai): introduce the real parameters when it's necessary. | 142 // TODO(mukai): introduce the real parameters when it's necessary. |
123 template_url_service_( | 143 template_url_service_( |
124 new TemplateURLService(NULL /* prefs */, | 144 new TemplateURLService(NULL /* prefs */, |
125 make_scoped_ptr(new SearchTermsData()), | 145 scoped_ptr<SearchTermsData>( |
| 146 new AthenaSearchTermsData()), |
126 NULL /* KeywordWebDataService */, | 147 NULL /* KeywordWebDataService */, |
127 scoped_ptr<TemplateURLServiceClient>( | 148 scoped_ptr<TemplateURLServiceClient>( |
128 new AthenaTemplateURLServiceClient()), | 149 new AthenaTemplateURLServiceClient()), |
129 NULL /*GoogleURLTracker */, | 150 NULL /*GoogleURLTracker */, |
130 NULL /* RapporService */, | 151 NULL /* RapporService */, |
131 base::Closure() /* dsp_change_callback */)) { | 152 base::Closure() /* dsp_change_callback */)), |
| 153 should_fetch_suggestions_again_(false) { |
132 template_url_service_->Load(); | 154 template_url_service_->Load(); |
133 } | 155 } |
134 | 156 |
135 UrlSearchProvider::~UrlSearchProvider() { | 157 UrlSearchProvider::~UrlSearchProvider() { |
136 } | 158 } |
137 | 159 |
138 void UrlSearchProvider::Start(const base::string16& query) { | 160 void UrlSearchProvider::Start(const base::string16& query) { |
| 161 input_ = AutocompleteInput(query, |
| 162 base::string16::npos /* cursor_position */, |
| 163 base::string16() /* desired_tld */, |
| 164 GURL() /* current_url */, |
| 165 metrics::OmniboxEventProto::INVALID_SPEC, |
| 166 false /* prevent_inline_autocomplete */, |
| 167 false /* prefer_keyword */, |
| 168 true /* allow_extract_keyword_match */, |
| 169 true /* want_asynchronous_matches */, |
| 170 AthenaSchemeClassifier()); |
139 ClearResults(); | 171 ClearResults(); |
140 Add(scoped_ptr<app_list::SearchResult>(new UrlSearchResult( | 172 Add(CreateResultForInput(browser_context_, template_url_service_.get(), |
141 browser_context_, template_url_service_.get(), query))); | 173 input_)); |
| 174 StartFetchingSuggestions(); |
142 } | 175 } |
143 | 176 |
144 void UrlSearchProvider::Stop() { | 177 void UrlSearchProvider::Stop() { |
| 178 suggestion_fetcher_.reset(); |
| 179 } |
| 180 |
| 181 void UrlSearchProvider::OnURLFetchComplete(const net::URLFetcher* source) { |
| 182 DCHECK_EQ(suggestion_fetcher_.get(), source); |
| 183 |
| 184 if (source->GetStatus().is_success() && source->GetResponseCode() == 200) { |
| 185 std::string json_data = SearchSuggestionParser::ExtractJsonData(source); |
| 186 scoped_ptr<base::Value> data( |
| 187 SearchSuggestionParser::DeserializeJsonData(json_data)); |
| 188 if (data) { |
| 189 const int kDefaultRelevance = 0; |
| 190 SearchSuggestionParser::Results results; |
| 191 if (SearchSuggestionParser::ParseSuggestResults( |
| 192 *data, input_, AthenaSchemeClassifier(), kDefaultRelevance, |
| 193 std::string(), // languages |
| 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 } |
| 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(); |
145 } | 245 } |
146 | 246 |
147 } // namespace athena | 247 } // namespace athena |
OLD | NEW |