OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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 "chrome/browser/autocomplete/zero_suggest_provider.h" | 5 #include "chrome/browser/autocomplete/zero_suggest_provider.h" |
6 | 6 |
7 #include "base/callback.h" | 7 #include "base/bind.h" |
8 #include "base/i18n/case_conversion.h" | |
9 #include "base/json/json_string_value_serializer.h" | |
10 #include "base/metrics/histogram.h" | 8 #include "base/metrics/histogram.h" |
| 9 #include "base/metrics/user_metrics_action.h" |
11 #include "base/prefs/pref_service.h" | 10 #include "base/prefs/pref_service.h" |
12 #include "base/strings/string16.h" | 11 #include "base/strings/string16.h" |
13 #include "base/strings/string_util.h" | |
14 #include "base/strings/utf_string_conversions.h" | 12 #include "base/strings/utf_string_conversions.h" |
15 #include "base/time/time.h" | |
16 #include "chrome/browser/autocomplete/autocomplete_classifier.h" | 13 #include "chrome/browser/autocomplete/autocomplete_classifier.h" |
17 #include "chrome/browser/autocomplete/autocomplete_classifier_factory.h" | 14 #include "chrome/browser/autocomplete/autocomplete_classifier_factory.h" |
18 #include "chrome/browser/autocomplete/autocomplete_input.h" | 15 #include "chrome/browser/autocomplete/autocomplete_input.h" |
19 #include "chrome/browser/autocomplete/autocomplete_match.h" | 16 #include "chrome/browser/autocomplete/autocomplete_match.h" |
| 17 #include "chrome/browser/autocomplete/autocomplete_provider.h" |
20 #include "chrome/browser/autocomplete/autocomplete_provider_listener.h" | 18 #include "chrome/browser/autocomplete/autocomplete_provider_listener.h" |
21 #include "chrome/browser/autocomplete/history_url_provider.h" | 19 #include "chrome/browser/autocomplete/base_search_provider.h" |
22 #include "chrome/browser/autocomplete/search_provider.h" | |
23 #include "chrome/browser/autocomplete/url_prefix.h" | |
24 #include "chrome/browser/history/history_types.h" | |
25 #include "chrome/browser/history/top_sites.h" | 20 #include "chrome/browser/history/top_sites.h" |
26 #include "chrome/browser/metrics/variations/variations_http_header_provider.h" | 21 #include "chrome/browser/metrics/variations/variations_http_header_provider.h" |
27 #include "chrome/browser/omnibox/omnibox_field_trial.h" | 22 #include "chrome/browser/omnibox/omnibox_field_trial.h" |
28 #include "chrome/browser/profiles/profile.h" | 23 #include "chrome/browser/profiles/profile.h" |
29 #include "chrome/browser/search/search.h" | 24 #include "chrome/browser/search_engines/template_url.h" |
30 #include "chrome/browser/search_engines/template_url_service.h" | 25 #include "chrome/browser/search_engines/template_url_service.h" |
31 #include "chrome/browser/search_engines/template_url_service_factory.h" | 26 #include "chrome/browser/search_engines/template_url_service_factory.h" |
32 #include "chrome/common/net/url_fixer_upper.h" | |
33 #include "chrome/common/pref_names.h" | 27 #include "chrome/common/pref_names.h" |
34 #include "chrome/common/url_constants.h" | 28 #include "content/public/browser/user_metrics.h" |
35 #include "net/base/escape.h" | 29 #include "net/base/escape.h" |
36 #include "net/base/load_flags.h" | 30 #include "net/base/load_flags.h" |
37 #include "net/base/net_util.h" | 31 #include "net/base/net_util.h" |
38 #include "net/http/http_request_headers.h" | 32 #include "net/http/http_request_headers.h" |
39 #include "net/http/http_response_headers.h" | |
40 #include "net/url_request/url_fetcher.h" | 33 #include "net/url_request/url_fetcher.h" |
41 #include "net/url_request/url_request_status.h" | |
42 #include "url/gurl.h" | 34 #include "url/gurl.h" |
43 | 35 |
44 namespace { | 36 namespace { |
45 | 37 |
46 // TODO(hfung): The histogram code was copied and modified from | 38 // TODO(hfung): The histogram code was copied and modified from |
47 // search_provider.cc. Refactor and consolidate the code. | 39 // search_provider.cc. Refactor and consolidate the code. |
48 // We keep track in a histogram how many suggest requests we send, how | 40 // We keep track in a histogram how many suggest requests we send, how |
49 // many suggest requests we invalidate (e.g., due to a user typing | 41 // many suggest requests we invalidate (e.g., due to a user typing |
50 // another character), and how many replies we receive. | 42 // another character), and how many replies we receive. |
51 // *** ADD NEW ENUMS AFTER ALL PREVIOUSLY DEFINED ONES! *** | 43 // *** ADD NEW ENUMS AFTER ALL PREVIOUSLY DEFINED ONES! *** |
(...skipping 21 matching lines...) Expand all Loading... |
73 | 65 |
74 } // namespace | 66 } // namespace |
75 | 67 |
76 // static | 68 // static |
77 ZeroSuggestProvider* ZeroSuggestProvider::Create( | 69 ZeroSuggestProvider* ZeroSuggestProvider::Create( |
78 AutocompleteProviderListener* listener, | 70 AutocompleteProviderListener* listener, |
79 Profile* profile) { | 71 Profile* profile) { |
80 return new ZeroSuggestProvider(listener, profile); | 72 return new ZeroSuggestProvider(listener, profile); |
81 } | 73 } |
82 | 74 |
83 void ZeroSuggestProvider::Start(const AutocompleteInput& input, | |
84 bool /*minimal_changes*/) { | |
85 } | |
86 | |
87 void ZeroSuggestProvider::Stop(bool clear_cached_results) { | |
88 if (have_pending_request_) | |
89 LogOmniboxZeroSuggestRequest(ZERO_SUGGEST_REQUEST_INVALIDATED); | |
90 have_pending_request_ = false; | |
91 fetcher_.reset(); | |
92 done_ = true; | |
93 if (clear_cached_results) { | |
94 query_matches_map_.clear(); | |
95 navigation_results_.clear(); | |
96 current_query_.clear(); | |
97 matches_.clear(); | |
98 } | |
99 } | |
100 | |
101 void ZeroSuggestProvider::AddProviderInfo(ProvidersInfo* provider_info) const { | |
102 provider_info->push_back(metrics::OmniboxEventProto_ProviderInfo()); | |
103 metrics::OmniboxEventProto_ProviderInfo& new_entry = provider_info->back(); | |
104 new_entry.set_provider(AsOmniboxEventProviderType()); | |
105 new_entry.set_provider_done(done_); | |
106 std::vector<uint32> field_trial_hashes; | |
107 OmniboxFieldTrial::GetActiveSuggestFieldTrialHashes(&field_trial_hashes); | |
108 for (size_t i = 0; i < field_trial_hashes.size(); ++i) { | |
109 if (field_trial_triggered_) | |
110 new_entry.mutable_field_trial_triggered()->Add(field_trial_hashes[i]); | |
111 if (field_trial_triggered_in_session_) { | |
112 new_entry.mutable_field_trial_triggered_in_session()->Add( | |
113 field_trial_hashes[i]); | |
114 } | |
115 } | |
116 } | |
117 | |
118 void ZeroSuggestProvider::ResetSession() { | 75 void ZeroSuggestProvider::ResetSession() { |
119 // The user has started editing in the omnibox, so leave | 76 // The user has started editing in the omnibox, so leave |
120 // |field_trial_triggered_in_session_| unchanged and set | 77 // |field_trial_triggered_in_session_| unchanged and set |
121 // |field_trial_triggered_| to false since zero suggest is inactive now. | 78 // |field_trial_triggered_| to false since zero suggest is inactive now. |
122 field_trial_triggered_ = false; | 79 field_trial_triggered_ = false; |
123 Stop(true); | 80 Stop(true); |
124 } | 81 } |
125 | 82 |
126 void ZeroSuggestProvider::OnURLFetchComplete(const net::URLFetcher* source) { | 83 void ZeroSuggestProvider::LogFetchComplete(const net::URLFetcher* source) { |
127 have_pending_request_ = false; | |
128 LogOmniboxZeroSuggestRequest(ZERO_SUGGEST_REPLY_RECEIVED); | 84 LogOmniboxZeroSuggestRequest(ZERO_SUGGEST_REPLY_RECEIVED); |
| 85 } |
129 | 86 |
130 std::string json_data; | 87 bool ZeroSuggestProvider::ShouldSendProviderUpdate(bool results_updated) { |
131 source->GetResponseAsString(&json_data); | 88 // If we have matches, the results must have successfully parsed. |
132 const bool request_succeeded = | 89 DCHECK(!matches_.empty() ? results_updated : true); |
133 source->GetStatus().is_success() && source->GetResponseCode() == 200; | 90 return !matches_.empty(); |
134 | |
135 if (request_succeeded) { | |
136 scoped_ptr<base::Value> data( | |
137 SearchProvider::DeserializeJsonData(json_data)); | |
138 if (data.get()) | |
139 ParseSuggestResults(*data.get()); | |
140 } | |
141 done_ = true; | |
142 | |
143 ConvertResultsToAutocompleteMatches(); | |
144 if (!matches_.empty()) | |
145 listener_->OnProviderUpdate(true); | |
146 } | 91 } |
147 | 92 |
148 void ZeroSuggestProvider::StartZeroSuggest( | 93 void ZeroSuggestProvider::StartZeroSuggest( |
149 const GURL& current_page_url, | 94 const GURL& current_page_url, |
150 AutocompleteInput::PageClassification page_classification, | 95 AutocompleteInput::PageClassification page_classification, |
151 const base::string16& permanent_text) { | 96 const base::string16& permanent_text) { |
152 Stop(true); | 97 Stop(true); |
153 field_trial_triggered_ = false; | 98 field_trial_triggered_ = false; |
154 field_trial_triggered_in_session_ = false; | 99 field_trial_triggered_in_session_ = false; |
155 permanent_text_ = permanent_text; | 100 permanent_text_ = permanent_text; |
156 current_query_ = current_page_url.spec(); | 101 current_query_ = current_page_url.spec(); |
157 current_page_classification_ = page_classification; | 102 current_page_classification_ = page_classification; |
158 current_url_match_ = MatchForCurrentURL(); | 103 current_url_match_ = MatchForCurrentURL(); |
159 | 104 |
160 const TemplateURL* default_provider = | 105 const TemplateURL* default_provider = |
161 template_url_service_->GetDefaultSearchProvider(); | 106 template_url_service_->GetDefaultSearchProvider(); |
162 if (default_provider == NULL) | 107 if (default_provider == NULL) |
163 return; | 108 return; |
164 base::string16 prefix; | 109 base::string16 prefix; |
165 TemplateURLRef::SearchTermsArgs search_term_args(prefix); | 110 TemplateURLRef::SearchTermsArgs search_term_args(prefix); |
166 search_term_args.current_page_url = current_query_; | 111 search_term_args.current_page_url = current_query_; |
167 GURL suggest_url(default_provider->suggestions_url_ref(). | 112 GURL suggest_url(default_provider->suggestions_url_ref(). |
168 ReplaceSearchTerms(search_term_args)); | 113 ReplaceSearchTerms(search_term_args)); |
169 if (!SearchProvider::CanSendURL( | 114 if (!BaseSearchProvider::CanSendURL( |
170 current_page_url, suggest_url, | 115 current_page_url, |
171 template_url_service_->GetDefaultSearchProvider(), | 116 suggest_url, |
172 page_classification, profile_) || | 117 template_url_service_->GetDefaultSearchProvider(), |
| 118 page_classification, |
| 119 profile_) || |
173 !OmniboxFieldTrial::InZeroSuggestFieldTrial()) | 120 !OmniboxFieldTrial::InZeroSuggestFieldTrial()) |
174 return; | 121 return; |
175 verbatim_relevance_ = kDefaultVerbatimZeroSuggestRelevance; | 122 results_.verbatim_relevance = kDefaultVerbatimZeroSuggestRelevance; |
176 done_ = false; | 123 done_ = false; |
177 // TODO(jered): Consider adding locally-sourced zero-suggestions here too. | 124 // TODO(jered): Consider adding locally-sourced zero-suggestions here too. |
178 // These may be useful on the NTP or more relevant to the user than server | 125 // These may be useful on the NTP or more relevant to the user than server |
179 // suggestions, if based on local browsing history. | 126 // suggestions, if based on local browsing history. |
180 Run(suggest_url); | 127 Run(suggest_url); |
181 } | 128 } |
182 | 129 |
183 ZeroSuggestProvider::ZeroSuggestProvider( | 130 void ZeroSuggestProvider::StopSuggest() { |
184 AutocompleteProviderListener* listener, | 131 if (suggest_results_pending_ > 0) |
185 Profile* profile) | 132 LogOmniboxZeroSuggestRequest(ZERO_SUGGEST_REQUEST_INVALIDATED); |
186 : AutocompleteProvider(listener, profile, | 133 suggest_results_pending_ = 0; |
187 AutocompleteProvider::TYPE_ZERO_SUGGEST), | 134 fetcher_.reset(); |
188 template_url_service_(TemplateURLServiceFactory::GetForProfile(profile)), | |
189 have_pending_request_(false), | |
190 verbatim_relevance_(kDefaultVerbatimZeroSuggestRelevance), | |
191 field_trial_triggered_(false), | |
192 field_trial_triggered_in_session_(false), | |
193 weak_ptr_factory_(this) { | |
194 } | 135 } |
195 | 136 |
196 ZeroSuggestProvider::~ZeroSuggestProvider() { | 137 void ZeroSuggestProvider::ClearAllResults() { |
| 138 results_.Clear(); |
| 139 current_query_.clear(); |
| 140 matches_.clear(); |
197 } | 141 } |
198 | 142 |
199 void ZeroSuggestProvider::FillResults( | 143 ZeroSuggestProvider::ZeroSuggestProvider(AutocompleteProviderListener* listener, |
200 const base::Value& root_val, | 144 Profile* profile) |
201 int* verbatim_relevance, | 145 : BaseSearchProvider(listener, |
202 SearchProvider::SuggestResults* suggest_results, | 146 profile, |
203 SearchProvider::NavigationResults* navigation_results) { | 147 AutocompleteProvider::TYPE_ZERO_SUGGEST), |
204 base::string16 query; | 148 template_url_service_(TemplateURLServiceFactory::GetForProfile(profile)), |
205 const base::ListValue* root_list = NULL; | 149 weak_ptr_factory_(this) {} |
206 const base::ListValue* results = NULL; | |
207 const base::ListValue* relevances = NULL; | |
208 // The response includes the query, which should be empty for ZeroSuggest | |
209 // responses. | |
210 if (!root_val.GetAsList(&root_list) || !root_list->GetString(0, &query) || | |
211 (!query.empty()) || !root_list->GetList(1, &results)) | |
212 return; | |
213 | 150 |
214 // 3rd element: Description list. | 151 ZeroSuggestProvider::~ZeroSuggestProvider() {} |
215 const base::ListValue* descriptions = NULL; | |
216 root_list->GetList(2, &descriptions); | |
217 | 152 |
218 // 4th element: Disregard the query URL list for now. | 153 bool ZeroSuggestProvider::IsValidQuery(const base::string16 query, |
| 154 const net::URLFetcher* source) { |
| 155 return query.empty(); |
| 156 } |
219 | 157 |
220 // Reset suggested relevance information from the provider. | 158 const base::string16 ZeroSuggestProvider::GetInputText( |
221 *verbatim_relevance = kDefaultVerbatimZeroSuggestRelevance; | 159 const net::URLFetcher* source) { |
| 160 return base::ASCIIToUTF16(current_query_); |
| 161 } |
222 | 162 |
223 // 5th element: Optional key-value pairs from the Suggest server. | 163 int ZeroSuggestProvider::GetDefaultRelevance() { |
224 const base::ListValue* types = NULL; | 164 return kDefaultZeroSuggestRelevance; |
225 const base::DictionaryValue* extras = NULL; | 165 } |
226 if (root_list->GetDictionary(4, &extras)) { | |
227 extras->GetList("google:suggesttype", &types); | |
228 | 166 |
229 // Discard this list if its size does not match that of the suggestions. | 167 void ZeroSuggestProvider::UpdateMatches() { |
230 if (extras->GetList("google:suggestrelevance", &relevances) && | 168 done_ = true; |
231 relevances->GetSize() != results->GetSize()) | 169 ConvertResultsToAutocompleteMatches(); |
232 relevances = NULL; | 170 } |
233 extras->GetInteger("google:verbatimrelevance", verbatim_relevance); | |
234 | 171 |
235 // Check if the active suggest field trial (if any) has triggered. | 172 BaseSearchProvider::Results* ZeroSuggestProvider::GetResultsObjectToFill( |
236 bool triggered = false; | 173 const net::URLFetcher* source) { |
237 extras->GetBoolean("google:fieldtrialtriggered", &triggered); | 174 return &results_; |
238 field_trial_triggered_ |= triggered; | 175 } |
239 field_trial_triggered_in_session_ |= triggered; | |
240 } | |
241 | 176 |
242 // Clear the previous results now that new results are available. | 177 void ZeroSuggestProvider::AddSuggestResultsToMap( |
243 suggest_results->clear(); | 178 const SuggestResults& results, |
244 navigation_results->clear(); | 179 const TemplateURL* template_url, |
245 | 180 MatchMap* map) { |
246 base::string16 result, title; | 181 for (size_t i = 0; i < results.size(); ++i) { |
247 std::string type; | 182 const base::string16& query_string(results[i].suggestion()); |
248 const base::string16 current_query_string16 = | 183 const SuggestResult suggestion(query_string, |
249 base::ASCIIToUTF16(current_query_); | 184 AutocompleteMatchType::SEARCH_SUGGEST, |
250 const std::string languages( | 185 query_string, |
251 profile_->GetPrefs()->GetString(prefs::kAcceptLanguages)); | 186 base::string16(), |
252 for (size_t index = 0; results->GetString(index, &result); ++index) { | 187 std::string(), |
253 // Google search may return empty suggestions for weird input characters, | 188 std::string(), |
254 // they make no sense at all and can cause problems in our code. | 189 false, |
255 if (result.empty()) | 190 results[i].relevance(), |
256 continue; | 191 true, |
257 | 192 false, |
258 int relevance = kDefaultZeroSuggestRelevance; | 193 query_string); |
259 | 194 AddMatchToMap(suggestion, |
260 // Apply valid suggested relevance scores; discard invalid lists. | 195 AutocompleteInput(), |
261 if (relevances != NULL && !relevances->GetInteger(index, &relevance)) | 196 query_string, |
262 relevances = NULL; | 197 template_url, |
263 if (types && types->GetString(index, &type) && (type == "NAVIGATION")) { | 198 std::string(), |
264 // Do not blindly trust the URL coming from the server to be valid. | 199 i, |
265 GURL url(URLFixerUpper::FixupURL( | 200 true, |
266 base::UTF16ToUTF8(result), std::string())); | 201 map); |
267 if (url.is_valid()) { | |
268 if (descriptions != NULL) | |
269 descriptions->GetString(index, &title); | |
270 navigation_results->push_back(SearchProvider::NavigationResult( | |
271 *this, url, title, false, relevance, relevances != NULL, | |
272 current_query_string16, languages)); | |
273 } | |
274 } else { | |
275 suggest_results->push_back(SearchProvider::SuggestResult( | |
276 result, AutocompleteMatchType::SEARCH_SUGGEST, result, | |
277 base::string16(), std::string(), std::string(), false, relevance, | |
278 relevances != NULL, false, current_query_string16)); | |
279 } | |
280 } | 202 } |
281 } | 203 } |
282 | 204 |
283 void ZeroSuggestProvider::AddSuggestResultsToMap( | |
284 const SearchProvider::SuggestResults& results, | |
285 const TemplateURL* template_url, | |
286 SearchProvider::MatchMap* map) { | |
287 for (size_t i = 0; i < results.size(); ++i) { | |
288 AddMatchToMap(results[i].relevance(), AutocompleteMatchType::SEARCH_SUGGEST, | |
289 template_url, results[i].suggestion(), i, map); | |
290 } | |
291 } | |
292 | |
293 void ZeroSuggestProvider::AddMatchToMap(int relevance, | |
294 AutocompleteMatch::Type type, | |
295 const TemplateURL* template_url, | |
296 const base::string16& query_string, | |
297 int accepted_suggestion, | |
298 SearchProvider::MatchMap* map) { | |
299 // Pass in query_string as the input_text to avoid bolding. | |
300 SearchProvider::SuggestResult suggestion( | |
301 query_string, type, query_string, base::string16(), std::string(), | |
302 std::string(), false, relevance, true, false, query_string); | |
303 // TODO(samarth|melevin): use the actual omnibox margin here as well instead | |
304 // of passing in -1. | |
305 AutocompleteMatch match = SearchProvider::CreateSearchSuggestion( | |
306 this, AutocompleteInput(), query_string, suggestion, template_url, | |
307 accepted_suggestion, -1, true); | |
308 if (!match.destination_url.is_valid()) | |
309 return; | |
310 | |
311 // Try to add |match| to |map|. If a match for |query_string| is already in | |
312 // |map|, replace it if |match| is more relevant. | |
313 // NOTE: Keep this ToLower() call in sync with url_database.cc. | |
314 SearchProvider::MatchKey match_key( | |
315 std::make_pair(base::i18n::ToLower(query_string), std::string())); | |
316 const std::pair<SearchProvider::MatchMap::iterator, bool> i(map->insert( | |
317 std::make_pair(match_key, match))); | |
318 // NOTE: We purposefully do a direct relevance comparison here instead of | |
319 // using AutocompleteMatch::MoreRelevant(), so that we'll prefer "items added | |
320 // first" rather than "items alphabetically first" when the scores are equal. | |
321 // The only case this matters is when a user has results with the same score | |
322 // that differ only by capitalization; because the history system returns | |
323 // results sorted by recency, this means we'll pick the most recent such | |
324 // result even if the precision of our relevance score is too low to | |
325 // distinguish the two. | |
326 if (!i.second && (match.relevance > i.first->second.relevance)) | |
327 i.first->second = match; | |
328 } | |
329 | |
330 AutocompleteMatch ZeroSuggestProvider::NavigationToMatch( | 205 AutocompleteMatch ZeroSuggestProvider::NavigationToMatch( |
331 const SearchProvider::NavigationResult& navigation) { | 206 const NavigationResult& navigation) { |
332 AutocompleteMatch match(this, navigation.relevance(), false, | 207 AutocompleteMatch match(this, navigation.relevance(), false, |
333 AutocompleteMatchType::NAVSUGGEST); | 208 AutocompleteMatchType::NAVSUGGEST); |
334 match.destination_url = navigation.url(); | 209 match.destination_url = navigation.url(); |
335 | 210 |
336 // Zero suggest results should always omit protocols and never appear bold. | 211 // Zero suggest results should always omit protocols and never appear bold. |
337 const std::string languages( | 212 const std::string languages( |
338 profile_->GetPrefs()->GetString(prefs::kAcceptLanguages)); | 213 profile_->GetPrefs()->GetString(prefs::kAcceptLanguages)); |
339 match.contents = net::FormatUrl(navigation.url(), languages, | 214 match.contents = net::FormatUrl(navigation.url(), languages, |
340 net::kFormatUrlOmitAll, net::UnescapeRule::SPACES, NULL, NULL, NULL); | 215 net::kFormatUrlOmitAll, net::UnescapeRule::SPACES, NULL, NULL, NULL); |
341 match.fill_into_edit += | 216 match.fill_into_edit += |
342 AutocompleteInput::FormattedStringWithEquivalentMeaning(navigation.url(), | 217 AutocompleteInput::FormattedStringWithEquivalentMeaning(navigation.url(), |
343 match.contents); | 218 match.contents); |
344 | 219 |
345 AutocompleteMatch::ClassifyLocationInString(base::string16::npos, 0, | 220 AutocompleteMatch::ClassifyLocationInString(base::string16::npos, 0, |
346 match.contents.length(), ACMatchClassification::URL, | 221 match.contents.length(), ACMatchClassification::URL, |
347 &match.contents_class); | 222 &match.contents_class); |
348 | 223 |
349 match.description = | 224 match.description = |
350 AutocompleteMatch::SanitizeString(navigation.description()); | 225 AutocompleteMatch::SanitizeString(navigation.description()); |
351 AutocompleteMatch::ClassifyLocationInString(base::string16::npos, 0, | 226 AutocompleteMatch::ClassifyLocationInString(base::string16::npos, 0, |
352 match.description.length(), ACMatchClassification::NONE, | 227 match.description.length(), ACMatchClassification::NONE, |
353 &match.description_class); | 228 &match.description_class); |
354 return match; | 229 return match; |
355 } | 230 } |
356 | 231 |
357 void ZeroSuggestProvider::Run(const GURL& suggest_url) { | 232 void ZeroSuggestProvider::Run(const GURL& suggest_url) { |
358 have_pending_request_ = false; | 233 suggest_results_pending_ = 0; |
359 const int kFetcherID = 1; | 234 const int kFetcherID = 1; |
360 fetcher_.reset( | 235 fetcher_.reset( |
361 net::URLFetcher::Create(kFetcherID, | 236 net::URLFetcher::Create(kFetcherID, |
362 suggest_url, | 237 suggest_url, |
363 net::URLFetcher::GET, this)); | 238 net::URLFetcher::GET, this)); |
364 fetcher_->SetRequestContext(profile_->GetRequestContext()); | 239 fetcher_->SetRequestContext(profile_->GetRequestContext()); |
365 fetcher_->SetLoadFlags(net::LOAD_DO_NOT_SAVE_COOKIES); | 240 fetcher_->SetLoadFlags(net::LOAD_DO_NOT_SAVE_COOKIES); |
366 // Add Chrome experiment state to the request headers. | 241 // Add Chrome experiment state to the request headers. |
367 net::HttpRequestHeaders headers; | 242 net::HttpRequestHeaders headers; |
368 chrome_variations::VariationsHttpHeaderProvider::GetInstance()->AppendHeaders( | 243 chrome_variations::VariationsHttpHeaderProvider::GetInstance()->AppendHeaders( |
369 fetcher_->GetOriginalURL(), profile_->IsOffTheRecord(), false, &headers); | 244 fetcher_->GetOriginalURL(), profile_->IsOffTheRecord(), false, &headers); |
370 fetcher_->SetExtraRequestHeaders(headers.ToString()); | 245 fetcher_->SetExtraRequestHeaders(headers.ToString()); |
371 | 246 |
372 fetcher_->Start(); | 247 fetcher_->Start(); |
373 | 248 |
374 if (OmniboxFieldTrial::InZeroSuggestMostVisitedFieldTrial()) { | 249 if (OmniboxFieldTrial::InZeroSuggestMostVisitedFieldTrial()) { |
375 most_visited_urls_.clear(); | 250 most_visited_urls_.clear(); |
376 history::TopSites* ts = profile_->GetTopSites(); | 251 history::TopSites* ts = profile_->GetTopSites(); |
377 if (ts) { | 252 if (ts) { |
378 ts->GetMostVisitedURLs( | 253 ts->GetMostVisitedURLs( |
379 base::Bind(&ZeroSuggestProvider::OnMostVisitedUrlsAvailable, | 254 base::Bind(&ZeroSuggestProvider::OnMostVisitedUrlsAvailable, |
380 weak_ptr_factory_.GetWeakPtr()), false); | 255 weak_ptr_factory_.GetWeakPtr()), false); |
381 } | 256 } |
382 } | 257 } |
383 have_pending_request_ = true; | 258 suggest_results_pending_++; |
384 LogOmniboxZeroSuggestRequest(ZERO_SUGGEST_REQUEST_SENT); | 259 LogOmniboxZeroSuggestRequest(ZERO_SUGGEST_REQUEST_SENT); |
385 } | 260 } |
386 | 261 |
387 void ZeroSuggestProvider::ParseSuggestResults(const base::Value& root_val) { | 262 void ZeroSuggestProvider::RecordDeletionResult(bool success) { |
388 SearchProvider::SuggestResults suggest_results; | 263 if (success) { |
389 FillResults(root_val, &verbatim_relevance_, | 264 content::RecordAction( |
390 &suggest_results, &navigation_results_); | 265 base::UserMetricsAction("Omnibox.ServerZeroSuggestDelete.Success")); |
391 | 266 } else { |
392 query_matches_map_.clear(); | 267 content::RecordAction( |
393 AddSuggestResultsToMap(suggest_results, | 268 base::UserMetricsAction("Omnibox.ServerZeroSuggestDelete.Failure")); |
394 template_url_service_->GetDefaultSearchProvider(), | 269 } |
395 &query_matches_map_); | |
396 } | 270 } |
397 | 271 |
398 void ZeroSuggestProvider::OnMostVisitedUrlsAvailable( | 272 void ZeroSuggestProvider::OnMostVisitedUrlsAvailable( |
399 const history::MostVisitedURLList& urls) { | 273 const history::MostVisitedURLList& urls) { |
400 most_visited_urls_ = urls; | 274 most_visited_urls_ = urls; |
401 } | 275 } |
402 | 276 |
403 void ZeroSuggestProvider::ConvertResultsToAutocompleteMatches() { | 277 void ZeroSuggestProvider::ConvertResultsToAutocompleteMatches() { |
404 matches_.clear(); | 278 matches_.clear(); |
405 | 279 |
406 const TemplateURL* default_provider = | 280 const TemplateURL* default_provider = |
407 template_url_service_->GetDefaultSearchProvider(); | 281 template_url_service_->GetDefaultSearchProvider(); |
408 // Fail if we can't set the clickthrough URL for query suggestions. | 282 // Fail if we can't set the clickthrough URL for query suggestions. |
409 if (default_provider == NULL || !default_provider->SupportsReplacement()) | 283 if (default_provider == NULL || !default_provider->SupportsReplacement()) |
410 return; | 284 return; |
411 | 285 |
412 const int num_query_results = query_matches_map_.size(); | 286 const int num_query_results = results_.suggest_results.size(); |
413 const int num_nav_results = navigation_results_.size(); | 287 const int num_nav_results = results_.navigation_results.size(); |
414 const int num_results = num_query_results + num_nav_results; | 288 const int num_results = num_query_results + num_nav_results; |
415 UMA_HISTOGRAM_COUNTS("ZeroSuggest.QueryResults", num_query_results); | 289 UMA_HISTOGRAM_COUNTS("ZeroSuggest.QueryResults", num_query_results); |
416 UMA_HISTOGRAM_COUNTS("ZeroSuggest.URLResults", num_nav_results); | 290 UMA_HISTOGRAM_COUNTS("ZeroSuggest.URLResults", num_nav_results); |
417 UMA_HISTOGRAM_COUNTS("ZeroSuggest.AllResults", num_results); | 291 UMA_HISTOGRAM_COUNTS("ZeroSuggest.AllResults", num_results); |
418 | 292 |
419 // Show Most Visited results after ZeroSuggest response is received. | 293 // Show Most Visited results after ZeroSuggest response is received. |
420 if (OmniboxFieldTrial::InZeroSuggestMostVisitedFieldTrial()) { | 294 if (OmniboxFieldTrial::InZeroSuggestMostVisitedFieldTrial()) { |
421 if (!current_url_match_.destination_url.is_valid()) | 295 if (!current_url_match_.destination_url.is_valid()) |
422 return; | 296 return; |
423 matches_.push_back(current_url_match_); | 297 matches_.push_back(current_url_match_); |
424 int relevance = 600; | 298 int relevance = 600; |
425 if (num_results > 0) { | 299 if (num_results > 0) { |
426 UMA_HISTOGRAM_COUNTS( | 300 UMA_HISTOGRAM_COUNTS( |
427 "Omnibox.ZeroSuggest.MostVisitedResultsCounterfactual", | 301 "Omnibox.ZeroSuggest.MostVisitedResultsCounterfactual", |
428 most_visited_urls_.size()); | 302 most_visited_urls_.size()); |
429 } | 303 } |
430 const base::string16 current_query_string16( | 304 const base::string16 current_query_string16( |
431 base::ASCIIToUTF16(current_query_)); | 305 base::ASCIIToUTF16(current_query_)); |
432 const std::string languages( | 306 const std::string languages( |
433 profile_->GetPrefs()->GetString(prefs::kAcceptLanguages)); | 307 profile_->GetPrefs()->GetString(prefs::kAcceptLanguages)); |
434 for (size_t i = 0; i < most_visited_urls_.size(); i++) { | 308 for (size_t i = 0; i < most_visited_urls_.size(); i++) { |
435 const history::MostVisitedURL& url = most_visited_urls_[i]; | 309 const history::MostVisitedURL& url = most_visited_urls_[i]; |
436 SearchProvider::NavigationResult nav( | 310 NavigationResult nav(*this, |
437 *this, url.url, url.title, false, relevance, true, | 311 url.url, |
438 current_query_string16, languages); | 312 url.title, |
| 313 false, |
| 314 relevance, |
| 315 true, |
| 316 current_query_string16, |
| 317 languages); |
439 matches_.push_back(NavigationToMatch(nav)); | 318 matches_.push_back(NavigationToMatch(nav)); |
440 --relevance; | 319 --relevance; |
441 } | 320 } |
442 return; | 321 return; |
443 } | 322 } |
444 | 323 |
445 if (num_results == 0) | 324 if (num_results == 0) |
446 return; | 325 return; |
447 | 326 |
448 // TODO(jered): Rip this out once the first match is decoupled from the | 327 // TODO(jered): Rip this out once the first match is decoupled from the |
449 // current typing in the omnibox. | 328 // current typing in the omnibox. |
450 matches_.push_back(current_url_match_); | 329 matches_.push_back(current_url_match_); |
451 | 330 |
452 for (SearchProvider::MatchMap::const_iterator it(query_matches_map_.begin()); | 331 MatchMap query_matches_map; |
453 it != query_matches_map_.end(); ++it) | 332 AddSuggestResultsToMap(results_.suggest_results, |
| 333 template_url_service_->GetDefaultSearchProvider(), |
| 334 &query_matches_map); |
| 335 |
| 336 for (MatchMap::const_iterator it(query_matches_map.begin()); |
| 337 it != query_matches_map.end(); |
| 338 ++it) |
454 matches_.push_back(it->second); | 339 matches_.push_back(it->second); |
455 | 340 |
456 for (SearchProvider::NavigationResults::const_iterator it( | 341 for (NavigationResults::const_iterator it( |
457 navigation_results_.begin()); it != navigation_results_.end(); ++it) | 342 results_.navigation_results.begin()); |
| 343 it != results_.navigation_results.end(); |
| 344 ++it) |
458 matches_.push_back(NavigationToMatch(*it)); | 345 matches_.push_back(NavigationToMatch(*it)); |
459 } | 346 } |
460 | 347 |
461 AutocompleteMatch ZeroSuggestProvider::MatchForCurrentURL() { | 348 AutocompleteMatch ZeroSuggestProvider::MatchForCurrentURL() { |
462 AutocompleteInput input(permanent_text_, base::string16::npos, base::string16(
), | 349 AutocompleteInput input(permanent_text_, base::string16::npos, base::string16(
), |
463 GURL(current_query_), current_page_classification_, | 350 GURL(current_query_), current_page_classification_, |
464 false, false, true, AutocompleteInput::ALL_MATCHES); | 351 false, false, true, AutocompleteInput::ALL_MATCHES); |
465 | 352 |
466 AutocompleteMatch match; | 353 AutocompleteMatch match; |
467 AutocompleteClassifierFactory::GetForProfile(profile_)->Classify( | 354 AutocompleteClassifierFactory::GetForProfile(profile_)->Classify( |
468 permanent_text_, false, true, &match, NULL); | 355 permanent_text_, false, true, &match, NULL); |
469 match.is_history_what_you_typed_match = false; | 356 match.is_history_what_you_typed_match = false; |
470 match.allowed_to_be_default_match = true; | 357 match.allowed_to_be_default_match = true; |
471 | 358 |
472 // The placeholder suggestion for the current URL has high relevance so | 359 // The placeholder suggestion for the current URL has high relevance so |
473 // that it is in the first suggestion slot and inline autocompleted. It | 360 // that it is in the first suggestion slot and inline autocompleted. It |
474 // gets dropped as soon as the user types something. | 361 // gets dropped as soon as the user types something. |
475 match.relevance = verbatim_relevance_; | 362 match.relevance = results_.verbatim_relevance; |
476 | 363 |
477 return match; | 364 return match; |
478 } | 365 } |
OLD | NEW |