blob: 3feaae3fbcf6257b60ad7a09518d12f5fb2e472d [file] [log] [blame]
[email protected]6ce7f612012-09-05 23:53:071// 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
3// found in the LICENSE file.
4
5#include "chrome/browser/autocomplete/zero_suggest_provider.h"
6
7#include "base/callback.h"
[email protected]bb1fb2b2013-05-31 00:21:018#include "base/i18n/case_conversion.h"
[email protected]6ce7f612012-09-05 23:53:079#include "base/json/json_string_value_serializer.h"
[email protected]bb1fb2b2013-05-31 00:21:0110#include "base/metrics/histogram.h"
[email protected]f7f41c0e2014-08-11 04:22:2311#include "base/metrics/user_metrics.h"
[email protected]3853a4c2013-02-11 17:15:5712#include "base/prefs/pref_service.h"
[email protected]98570e12013-06-10 19:54:2213#include "base/strings/string16.h"
14#include "base/strings/string_util.h"
[email protected]135cb802013-06-09 16:44:2015#include "base/strings/utf_string_conversions.h"
[email protected]4dcb7972013-06-28 15:15:4116#include "base/time/time.h"
[email protected]2d915782013-08-29 09:50:2117#include "chrome/browser/autocomplete/autocomplete_classifier.h"
18#include "chrome/browser/autocomplete/autocomplete_classifier_factory.h"
Ryo Hashimoto884ad192014-08-28 05:54:3019#include "chrome/browser/autocomplete/chrome_autocomplete_provider_client.h"
[email protected]a817ed392014-06-27 05:03:0020#include "chrome/browser/autocomplete/chrome_autocomplete_scheme_classifier.h"
[email protected]bb1fb2b2013-05-31 00:21:0121#include "chrome/browser/autocomplete/history_url_provider.h"
[email protected]8f064e52013-09-18 01:17:1422#include "chrome/browser/history/top_sites.h"
[email protected]6ce7f612012-09-05 23:53:0723#include "chrome/browser/profiles/profile.h"
mariakhomenkobfc3a2a2014-10-24 00:48:2224#include "chrome/browser/search_engines/template_url_service_factory.h"
[email protected]a00008d42012-09-15 05:07:5825#include "chrome/common/pref_names.h"
sdefresnebc766ef2014-09-25 09:28:1326#include "components/history/core/browser/history_types.h"
[email protected]3dc75b12014-06-08 00:02:2227#include "components/metrics/proto/omnibox_input_type.pb.h"
[email protected]b1c5ab682014-08-07 11:53:1728#include "components/omnibox/autocomplete_input.h"
29#include "components/omnibox/autocomplete_match.h"
30#include "components/omnibox/autocomplete_provider_listener.h"
[email protected]4c583b62014-08-08 10:37:2331#include "components/omnibox/omnibox_field_trial.h"
hashimoto5f7db4b2014-08-27 02:46:2032#include "components/omnibox/search_provider.h"
[email protected]f0c8c4992014-05-15 17:37:2633#include "components/pref_registry/pref_registry_syncable.h"
[email protected]bf5c532d2014-07-05 00:29:5334#include "components/search_engines/template_url_service.h"
isherman3be67db2014-10-24 05:57:4435#include "components/variations/net/variations_http_header_provider.h"
[email protected]bb1fb2b2013-05-31 00:21:0136#include "net/base/escape.h"
[email protected]6ce7f612012-09-05 23:53:0737#include "net/base/load_flags.h"
[email protected]bb1fb2b2013-05-31 00:21:0138#include "net/base/net_util.h"
39#include "net/http/http_request_headers.h"
[email protected]6ce7f612012-09-05 23:53:0740#include "net/url_request/url_fetcher.h"
41#include "net/url_request/url_request_status.h"
[email protected]761fa4702013-07-02 15:25:1542#include "url/gurl.h"
[email protected]6ce7f612012-09-05 23:53:0743
44namespace {
[email protected]bb1fb2b2013-05-31 00:21:0145
46// TODO(hfung): The histogram code was copied and modified from
47// search_provider.cc. Refactor and consolidate the code.
48// 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
50// another character), and how many replies we receive.
51// *** ADD NEW ENUMS AFTER ALL PREVIOUSLY DEFINED ONES! ***
52// (excluding the end-of-list enum value)
53// We do not want values of existing enums to change or else it screws
54// up the statistics.
55enum ZeroSuggestRequestsHistogramValue {
56 ZERO_SUGGEST_REQUEST_SENT = 1,
57 ZERO_SUGGEST_REQUEST_INVALIDATED,
58 ZERO_SUGGEST_REPLY_RECEIVED,
59 ZERO_SUGGEST_MAX_REQUEST_HISTOGRAM_VALUE
60};
61
62void LogOmniboxZeroSuggestRequest(
63 ZeroSuggestRequestsHistogramValue request_value) {
64 UMA_HISTOGRAM_ENUMERATION("Omnibox.ZeroSuggestRequests", request_value,
65 ZERO_SUGGEST_MAX_REQUEST_HISTOGRAM_VALUE);
66}
67
68// The maximum relevance of the top match from this provider.
69const int kDefaultVerbatimZeroSuggestRelevance = 1300;
70
71// Relevance value to use if it was not set explicitly by the server.
72const int kDefaultZeroSuggestRelevance = 100;
73
[email protected]6ce7f612012-09-05 23:53:0774} // namespace
75
[email protected]a00008d42012-09-15 05:07:5876// static
77ZeroSuggestProvider* ZeroSuggestProvider::Create(
78 AutocompleteProviderListener* listener,
[email protected]e6477f12014-08-05 07:59:5479 TemplateURLService* template_url_service,
[email protected]a00008d42012-09-15 05:07:5880 Profile* profile) {
[email protected]e6477f12014-08-05 07:59:5481 return new ZeroSuggestProvider(listener, template_url_service, profile);
[email protected]6ce7f612012-09-05 23:53:0782}
83
[email protected]855ebff2014-05-09 07:14:3884// static
85void ZeroSuggestProvider::RegisterProfilePrefs(
86 user_prefs::PrefRegistrySyncable* registry) {
87 registry->RegisterStringPref(
88 prefs::kZeroSuggestCachedResults,
89 std::string(),
90 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
91}
92
[email protected]6ce7f612012-09-05 23:53:0793void ZeroSuggestProvider::Start(const AutocompleteInput& input,
mariakhomenko3ef531d72015-01-10 00:03:4394 bool minimal_changes,
95 bool called_due_to_focus) {
[email protected]f030c4d2014-03-25 01:05:5496 matches_.clear();
mariakhomenko3ef531d72015-01-10 00:03:4397 if (!called_due_to_focus ||
98 input.type() == metrics::OmniboxInputType::INVALID)
[email protected]f030c4d2014-03-25 01:05:5499 return;
[email protected]bb1fb2b2013-05-31 00:21:01100
[email protected]bb1fb2b2013-05-31 00:21:01101 Stop(true);
102 field_trial_triggered_ = false;
103 field_trial_triggered_in_session_ = false;
[email protected]855ebff2014-05-09 07:14:38104 results_from_cache_ = false;
[email protected]f030c4d2014-03-25 01:05:54105 permanent_text_ = input.text();
106 current_query_ = input.current_url().spec();
107 current_page_classification_ = input.current_page_classification();
[email protected]9b9fa672013-11-07 06:04:52108 current_url_match_ = MatchForCurrentURL();
109
110 const TemplateURL* default_provider =
111 template_url_service_->GetDefaultSearchProvider();
112 if (default_provider == NULL)
113 return;
[email protected]162c8d9fa2014-03-18 20:25:41114
[email protected]96920152013-12-04 21:00:16115 base::string16 prefix;
[email protected]9b9fa672013-11-07 06:04:52116 TemplateURLRef::SearchTermsArgs search_term_args(prefix);
[email protected]162c8d9fa2014-03-18 20:25:41117 GURL suggest_url(default_provider->suggestions_url_ref().ReplaceSearchTerms(
[email protected]ce7ee5f2014-06-16 23:41:19118 search_term_args, template_url_service_->search_terms_data()));
[email protected]162c8d9fa2014-03-18 20:25:41119 if (!suggest_url.is_valid())
[email protected]6ce7f612012-09-05 23:53:07120 return;
[email protected]162c8d9fa2014-03-18 20:25:41121
mariakhomenkobfc3a2a2014-10-24 00:48:22122 // No need to send the current page URL in personalized suggest or
123 // most visited field trials.
[email protected]f030c4d2014-03-25 01:05:54124 if (CanSendURL(input.current_url(), suggest_url, default_provider,
[email protected]e6477f12014-08-05 07:59:54125 current_page_classification_,
Ryo Hashimoto884ad192014-08-28 05:54:30126 template_url_service_->search_terms_data(), client_.get()) &&
mariakhomenkobfc3a2a2014-10-24 00:48:22127 !OmniboxFieldTrial::InZeroSuggestPersonalizedFieldTrial() &&
128 !OmniboxFieldTrial::InZeroSuggestMostVisitedFieldTrial()) {
[email protected]162c8d9fa2014-03-18 20:25:41129 // Update suggest_url to include the current_page_url.
130 search_term_args.current_page_url = current_query_;
131 suggest_url = GURL(default_provider->suggestions_url_ref().
[email protected]ce7ee5f2014-06-16 23:41:19132 ReplaceSearchTerms(
133 search_term_args,
134 template_url_service_->search_terms_data()));
mariakhomenkobfc3a2a2014-10-24 00:48:22135 } else if (!ShouldShowNonContextualZeroSuggest(suggest_url,
136 input.current_url())) {
[email protected]162c8d9fa2014-03-18 20:25:41137 return;
138 }
139
[email protected]6ce7f612012-09-05 23:53:07140 done_ = false;
[email protected]6ce7f612012-09-05 23:53:07141 // TODO(jered): Consider adding locally-sourced zero-suggestions here too.
142 // These may be useful on the NTP or more relevant to the user than server
143 // suggestions, if based on local browsing history.
[email protected]855ebff2014-05-09 07:14:38144 MaybeUseCachedSuggestions();
[email protected]9b9fa672013-11-07 06:04:52145 Run(suggest_url);
[email protected]6ce7f612012-09-05 23:53:07146}
147
[email protected]ec3f679b2014-08-18 07:45:13148void ZeroSuggestProvider::Stop(bool clear_cached_results) {
149 if (fetcher_)
150 LogOmniboxZeroSuggestRequest(ZERO_SUGGEST_REQUEST_INVALIDATED);
151 fetcher_.reset();
mariakhomenkobfc3a2a2014-10-24 00:48:22152 waiting_for_most_visited_urls_request_ = false;
[email protected]ec3f679b2014-08-18 07:45:13153 done_ = true;
154
155 if (clear_cached_results) {
156 // We do not call Clear() on |results_| to retain |verbatim_relevance|
157 // value in the |results_| object. |verbatim_relevance| is used at the
jif28e51b0582015-01-06 14:12:21158 // beginning of the next OnOmniboxFocused() call to determine the current
[email protected]ec3f679b2014-08-18 07:45:13159 // url match relevance.
160 results_.suggest_results.clear();
161 results_.navigation_results.clear();
162 current_query_.clear();
163 }
164}
165
[email protected]855ebff2014-05-09 07:14:38166void ZeroSuggestProvider::DeleteMatch(const AutocompleteMatch& match) {
167 if (OmniboxFieldTrial::InZeroSuggestPersonalizedFieldTrial()) {
168 // Remove the deleted match from the cache, so it is not shown to the user
169 // again. Since we cannot remove just one result, blow away the cache.
170 profile_->GetPrefs()->SetString(prefs::kZeroSuggestCachedResults,
171 std::string());
172 }
173 BaseSearchProvider::DeleteMatch(match);
174}
175
[email protected]ec3f679b2014-08-18 07:45:13176void ZeroSuggestProvider::AddProviderInfo(ProvidersInfo* provider_info) const {
177 BaseSearchProvider::AddProviderInfo(provider_info);
178 if (!results_.suggest_results.empty() || !results_.navigation_results.empty())
179 provider_info->back().set_times_returned_results_in_session(1);
180}
181
[email protected]f030c4d2014-03-25 01:05:54182void ZeroSuggestProvider::ResetSession() {
183 // The user has started editing in the omnibox, so leave
184 // |field_trial_triggered_in_session_| unchanged and set
185 // |field_trial_triggered_| to false since zero suggest is inactive now.
186 field_trial_triggered_ = false;
187}
188
[email protected]bb1fb2b2013-05-31 00:21:01189ZeroSuggestProvider::ZeroSuggestProvider(
190 AutocompleteProviderListener* listener,
[email protected]e6477f12014-08-05 07:59:54191 TemplateURLService* template_url_service,
[email protected]bb1fb2b2013-05-31 00:21:01192 Profile* profile)
hashimoto663b9f42014-08-26 04:29:20193 : BaseSearchProvider(template_url_service,
Ryo Hashimoto884ad192014-08-28 05:54:30194 scoped_ptr<AutocompleteProviderClient>(
195 new ChromeAutocompleteProviderClient(profile)),
[email protected]02346202014-02-05 05:18:30196 AutocompleteProvider::TYPE_ZERO_SUGGEST),
[email protected]776ee5902014-08-11 09:15:19197 listener_(listener),
hashimoto663b9f42014-08-26 04:29:20198 profile_(profile),
[email protected]855ebff2014-05-09 07:14:38199 results_from_cache_(false),
mariakhomenkobfc3a2a2014-10-24 00:48:22200 waiting_for_most_visited_urls_request_(false),
[email protected]8f064e52013-09-18 01:17:14201 weak_ptr_factory_(this) {
[email protected]6ce7f612012-09-05 23:53:07202}
203
204ZeroSuggestProvider::~ZeroSuggestProvider() {
205}
206
[email protected]776ee5902014-08-11 09:15:19207const TemplateURL* ZeroSuggestProvider::GetTemplateURL(bool is_keyword) const {
208 // Zero suggest provider should not receive keyword results.
209 DCHECK(!is_keyword);
210 return template_url_service_->GetDefaultSearchProvider();
211}
212
213const AutocompleteInput ZeroSuggestProvider::GetInput(bool is_keyword) const {
214 return AutocompleteInput(
pkastingd932779e2014-10-07 22:38:35215 base::string16(), base::string16::npos, std::string(),
[email protected]776ee5902014-08-11 09:15:19216 GURL(current_query_), current_page_classification_, true, false, false,
217 true, ChromeAutocompleteSchemeClassifier(profile_));
218}
219
220bool ZeroSuggestProvider::ShouldAppendExtraParams(
221 const SearchSuggestionParser::SuggestResult& result) const {
222 // We always use the default provider for search, so append the params.
223 return true;
224}
225
[email protected]776ee5902014-08-11 09:15:19226void ZeroSuggestProvider::RecordDeletionResult(bool success) {
227 if (success) {
228 base::RecordAction(
229 base::UserMetricsAction("Omnibox.ZeroSuggestDelete.Success"));
230 } else {
231 base::RecordAction(
232 base::UserMetricsAction("Omnibox.ZeroSuggestDelete.Failure"));
233 }
234}
235
236void ZeroSuggestProvider::OnURLFetchComplete(const net::URLFetcher* source) {
237 DCHECK(!done_);
238 DCHECK_EQ(fetcher_.get(), source);
239
240 LogOmniboxZeroSuggestRequest(ZERO_SUGGEST_REPLY_RECEIVED);
241
242 bool results_updated = false;
243 if (source->GetStatus().is_success() && source->GetResponseCode() == 200) {
244 std::string json_data = SearchSuggestionParser::ExtractJsonData(source);
245 scoped_ptr<base::Value> data(
246 SearchSuggestionParser::DeserializeJsonData(json_data));
247 if (data) {
248 if (StoreSuggestionResponse(json_data, *data))
249 return;
250 results_updated = ParseSuggestResults(
251 *data, kDefaultZeroSuggestRelevance, false, &results_);
252 }
253 }
254 fetcher_.reset();
255 done_ = true;
256 ConvertResultsToAutocompleteMatches();
257 listener_->OnProviderUpdate(results_updated);
258}
259
[email protected]855ebff2014-05-09 07:14:38260bool ZeroSuggestProvider::StoreSuggestionResponse(
261 const std::string& json_data,
262 const base::Value& parsed_data) {
263 if (!OmniboxFieldTrial::InZeroSuggestPersonalizedFieldTrial() ||
264 json_data.empty())
265 return false;
266 profile_->GetPrefs()->SetString(prefs::kZeroSuggestCachedResults, json_data);
267
268 // If we received an empty result list, we should update the display, as it
269 // may be showing cached results that should not be shown.
270 const base::ListValue* root_list = NULL;
271 const base::ListValue* results_list = NULL;
272 if (parsed_data.GetAsList(&root_list) &&
273 root_list->GetList(1, &results_list) &&
274 results_list->empty())
275 return false;
276
277 // We are finished with the request and want to bail early.
278 if (results_from_cache_)
279 done_ = true;
280
281 return results_from_cache_;
282}
283
[email protected]bb1fb2b2013-05-31 00:21:01284void ZeroSuggestProvider::AddSuggestResultsToMap(
[email protected]0b9575f2014-07-30 11:58:37285 const SearchSuggestionParser::SuggestResults& results,
[email protected]02346202014-02-05 05:18:30286 MatchMap* map) {
[email protected]d4a94b92014-03-04 01:35:22287 for (size_t i = 0; i < results.size(); ++i)
[email protected]7bc5e162014-08-15 19:41:11288 AddMatchToMap(results[i], std::string(), i, false, false, map);
[email protected]bb1fb2b2013-05-31 00:21:01289}
290
[email protected]bb1fb2b2013-05-31 00:21:01291AutocompleteMatch ZeroSuggestProvider::NavigationToMatch(
[email protected]0b9575f2014-07-30 11:58:37292 const SearchSuggestionParser::NavigationResult& navigation) {
[email protected]bb1fb2b2013-05-31 00:21:01293 AutocompleteMatch match(this, navigation.relevance(), false,
[email protected]78981d8c2014-05-09 15:05:47294 navigation.type());
[email protected]bb1fb2b2013-05-31 00:21:01295 match.destination_url = navigation.url();
296
[email protected]23db6492014-01-16 02:35:30297 // Zero suggest results should always omit protocols and never appear bold.
[email protected]bb1fb2b2013-05-31 00:21:01298 const std::string languages(
299 profile_->GetPrefs()->GetString(prefs::kAcceptLanguages));
300 match.contents = net::FormatUrl(navigation.url(), languages,
301 net::kFormatUrlOmitAll, net::UnescapeRule::SPACES, NULL, NULL, NULL);
302 match.fill_into_edit +=
303 AutocompleteInput::FormattedStringWithEquivalentMeaning(navigation.url(),
[email protected]a817ed392014-06-27 05:03:00304 match.contents, ChromeAutocompleteSchemeClassifier(profile_));
[email protected]bb1fb2b2013-05-31 00:21:01305
[email protected]b959d7d42013-12-13 17:26:37306 AutocompleteMatch::ClassifyLocationInString(base::string16::npos, 0,
[email protected]bb1fb2b2013-05-31 00:21:01307 match.contents.length(), ACMatchClassification::URL,
308 &match.contents_class);
[email protected]9c97f89c2013-06-25 03:12:16309
310 match.description =
311 AutocompleteMatch::SanitizeString(navigation.description());
[email protected]b959d7d42013-12-13 17:26:37312 AutocompleteMatch::ClassifyLocationInString(base::string16::npos, 0,
[email protected]9c97f89c2013-06-25 03:12:16313 match.description.length(), ACMatchClassification::NONE,
314 &match.description_class);
[email protected]bb1fb2b2013-05-31 00:21:01315 return match;
316}
317
[email protected]9b9fa672013-11-07 06:04:52318void ZeroSuggestProvider::Run(const GURL& suggest_url) {
[email protected]8f064e52013-09-18 01:17:14319 if (OmniboxFieldTrial::InZeroSuggestMostVisitedFieldTrial()) {
320 most_visited_urls_.clear();
321 history::TopSites* ts = profile_->GetTopSites();
322 if (ts) {
mariakhomenkobfc3a2a2014-10-24 00:48:22323 waiting_for_most_visited_urls_request_ = true;
[email protected]8f064e52013-09-18 01:17:14324 ts->GetMostVisitedURLs(
325 base::Bind(&ZeroSuggestProvider::OnMostVisitedUrlsAvailable,
[email protected]ce767ab22013-11-12 03:50:09326 weak_ptr_factory_.GetWeakPtr()), false);
[email protected]8f064e52013-09-18 01:17:14327 }
mariakhomenkobfc3a2a2014-10-24 00:48:22328 } else {
329 const int kFetcherID = 1;
330 fetcher_.reset(
331 net::URLFetcher::Create(kFetcherID,
332 suggest_url,
333 net::URLFetcher::GET, this));
334 fetcher_->SetRequestContext(profile_->GetRequestContext());
335 fetcher_->SetLoadFlags(net::LOAD_DO_NOT_SAVE_COOKIES);
336 // Add Chrome experiment state to the request headers.
337 net::HttpRequestHeaders headers;
338 variations::VariationsHttpHeaderProvider::GetInstance()->AppendHeaders(
339 fetcher_->GetOriginalURL(), profile_->IsOffTheRecord(), false,
340 &headers);
341 fetcher_->SetExtraRequestHeaders(headers.ToString());
342 fetcher_->Start();
343 LogOmniboxZeroSuggestRequest(ZERO_SUGGEST_REQUEST_SENT);
[email protected]8f064e52013-09-18 01:17:14344 }
[email protected]bb1fb2b2013-05-31 00:21:01345}
346
[email protected]8f064e52013-09-18 01:17:14347void ZeroSuggestProvider::OnMostVisitedUrlsAvailable(
348 const history::MostVisitedURLList& urls) {
mariakhomenkobfc3a2a2014-10-24 00:48:22349 if (!waiting_for_most_visited_urls_request_) return;
[email protected]8f064e52013-09-18 01:17:14350 most_visited_urls_ = urls;
mariakhomenkobfc3a2a2014-10-24 00:48:22351 waiting_for_most_visited_urls_request_ = false;
352 done_ = true;
353 ConvertResultsToAutocompleteMatches();
354 listener_->OnProviderUpdate(true);
[email protected]8f064e52013-09-18 01:17:14355}
356
[email protected]9c97f89c2013-06-25 03:12:16357void ZeroSuggestProvider::ConvertResultsToAutocompleteMatches() {
[email protected]bb1fb2b2013-05-31 00:21:01358 matches_.clear();
359
360 const TemplateURL* default_provider =
[email protected]6ce7f612012-09-05 23:53:07361 template_url_service_->GetDefaultSearchProvider();
362 // Fail if we can't set the clickthrough URL for query suggestions.
[email protected]ce7ee5f2014-06-16 23:41:19363 if (default_provider == NULL || !default_provider->SupportsReplacement(
364 template_url_service_->search_terms_data()))
[email protected]6ce7f612012-09-05 23:53:07365 return;
[email protected]6ce7f612012-09-05 23:53:07366
[email protected]00404742014-02-20 13:09:05367 MatchMap map;
368 AddSuggestResultsToMap(results_.suggest_results, &map);
369
370 const int num_query_results = map.size();
371 const int num_nav_results = results_.navigation_results.size();
[email protected]bb1fb2b2013-05-31 00:21:01372 const int num_results = num_query_results + num_nav_results;
[email protected]9c97f89c2013-06-25 03:12:16373 UMA_HISTOGRAM_COUNTS("ZeroSuggest.QueryResults", num_query_results);
[email protected]78981d8c2014-05-09 15:05:47374 UMA_HISTOGRAM_COUNTS("ZeroSuggest.URLResults", num_nav_results);
[email protected]9c97f89c2013-06-25 03:12:16375 UMA_HISTOGRAM_COUNTS("ZeroSuggest.AllResults", num_results);
[email protected]bb1fb2b2013-05-31 00:21:01376
[email protected]8f064e52013-09-18 01:17:14377 // Show Most Visited results after ZeroSuggest response is received.
378 if (OmniboxFieldTrial::InZeroSuggestMostVisitedFieldTrial()) {
[email protected]3feb8b002013-10-14 23:50:13379 if (!current_url_match_.destination_url.is_valid())
380 return;
[email protected]8f064e52013-09-18 01:17:14381 matches_.push_back(current_url_match_);
382 int relevance = 600;
383 if (num_results > 0) {
384 UMA_HISTOGRAM_COUNTS(
385 "Omnibox.ZeroSuggest.MostVisitedResultsCounterfactual",
386 most_visited_urls_.size());
387 }
[email protected]23db6492014-01-16 02:35:30388 const base::string16 current_query_string16(
389 base::ASCIIToUTF16(current_query_));
390 const std::string languages(
391 profile_->GetPrefs()->GetString(prefs::kAcceptLanguages));
[email protected]8f064e52013-09-18 01:17:14392 for (size_t i = 0; i < most_visited_urls_.size(); i++) {
393 const history::MostVisitedURL& url = most_visited_urls_[i];
[email protected]0b9575f2014-07-30 11:58:37394 SearchSuggestionParser::NavigationResult nav(
[email protected]7720fc32014-07-09 06:10:05395 ChromeAutocompleteSchemeClassifier(profile_), url.url,
396 AutocompleteMatchType::NAVSUGGEST, url.title, std::string(), false,
397 relevance, true, current_query_string16, languages);
[email protected]8f064e52013-09-18 01:17:14398 matches_.push_back(NavigationToMatch(nav));
399 --relevance;
400 }
401 return;
402 }
403
[email protected]9c97f89c2013-06-25 03:12:16404 if (num_results == 0)
[email protected]bb1fb2b2013-05-31 00:21:01405 return;
406
407 // TODO(jered): Rip this out once the first match is decoupled from the
408 // current typing in the omnibox.
[email protected]bb1fb2b2013-05-31 00:21:01409 matches_.push_back(current_url_match_);
410
[email protected]00404742014-02-20 13:09:05411 for (MatchMap::const_iterator it(map.begin()); it != map.end(); ++it)
[email protected]bb1fb2b2013-05-31 00:21:01412 matches_.push_back(it->second);
[email protected]bb1fb2b2013-05-31 00:21:01413
[email protected]0b9575f2014-07-30 11:58:37414 const SearchSuggestionParser::NavigationResults& nav_results(
415 results_.navigation_results);
416 for (SearchSuggestionParser::NavigationResults::const_iterator it(
417 nav_results.begin()); it != nav_results.end(); ++it)
[email protected]bb1fb2b2013-05-31 00:21:01418 matches_.push_back(NavigationToMatch(*it));
[email protected]6ce7f612012-09-05 23:53:07419}
420
[email protected]bb1fb2b2013-05-31 00:21:01421AutocompleteMatch ZeroSuggestProvider::MatchForCurrentURL() {
[email protected]2d915782013-08-29 09:50:21422 AutocompleteMatch match;
423 AutocompleteClassifierFactory::GetForProfile(profile_)->Classify(
[email protected]51abb7b2014-02-09 23:00:08424 permanent_text_, false, true, current_page_classification_, &match, NULL);
[email protected]bb1fb2b2013-05-31 00:21:01425 match.is_history_what_you_typed_match = false;
[email protected]45f89a92013-08-12 13:41:36426 match.allowed_to_be_default_match = true;
[email protected]6ce7f612012-09-05 23:53:07427
[email protected]bb1fb2b2013-05-31 00:21:01428 // The placeholder suggestion for the current URL has high relevance so
429 // that it is in the first suggestion slot and inline autocompleted. It
430 // gets dropped as soon as the user types something.
[email protected]00404742014-02-20 13:09:05431 match.relevance = GetVerbatimRelevance();
[email protected]6ce7f612012-09-05 23:53:07432
[email protected]bb1fb2b2013-05-31 00:21:01433 return match;
[email protected]6ce7f612012-09-05 23:53:07434}
[email protected]00404742014-02-20 13:09:05435
436int ZeroSuggestProvider::GetVerbatimRelevance() const {
437 return results_.verbatim_relevance >= 0 ?
438 results_.verbatim_relevance : kDefaultVerbatimZeroSuggestRelevance;
439}
[email protected]162c8d9fa2014-03-18 20:25:41440
mariakhomenkobfc3a2a2014-10-24 00:48:22441bool ZeroSuggestProvider::ShouldShowNonContextualZeroSuggest(
[email protected]162c8d9fa2014-03-18 20:25:41442 const GURL& suggest_url,
443 const GURL& current_page_url) const {
444 if (!ZeroSuggestEnabled(suggest_url,
445 template_url_service_->GetDefaultSearchProvider(),
[email protected]e6477f12014-08-05 07:59:54446 current_page_classification_,
hashimoto663b9f42014-08-26 04:29:20447 template_url_service_->search_terms_data(),
Ryo Hashimoto884ad192014-08-28 05:54:30448 client_.get()))
[email protected]162c8d9fa2014-03-18 20:25:41449 return false;
450
451 // If we cannot send URLs, then only the MostVisited and Personalized
452 // variations can be shown.
453 if (!OmniboxFieldTrial::InZeroSuggestMostVisitedFieldTrial() &&
454 !OmniboxFieldTrial::InZeroSuggestPersonalizedFieldTrial())
455 return false;
456
457 // Only show zero suggest for HTTP[S] pages.
458 // TODO(mariakhomenko): We may be able to expand this set to include pages
459 // with other schemes (e.g. chrome://). That may require improvements to
460 // the formatting of the verbatim result returned by MatchForCurrentURL().
461 if (!current_page_url.is_valid() ||
[email protected]e8ca69c2014-05-07 15:31:19462 ((current_page_url.scheme() != url::kHttpScheme) &&
463 (current_page_url.scheme() != url::kHttpsScheme)))
[email protected]162c8d9fa2014-03-18 20:25:41464 return false;
465
mariakhomenkobfc3a2a2014-10-24 00:48:22466 if (OmniboxFieldTrial::InZeroSuggestMostVisitedWithoutSerpFieldTrial() &&
467 template_url_service_->
468 IsSearchResultsPageFromDefaultSearchProvider(current_page_url))
469 return false;
470
[email protected]162c8d9fa2014-03-18 20:25:41471 return true;
472}
[email protected]855ebff2014-05-09 07:14:38473
474void ZeroSuggestProvider::MaybeUseCachedSuggestions() {
475 if (!OmniboxFieldTrial::InZeroSuggestPersonalizedFieldTrial())
476 return;
477
478 std::string json_data = profile_->GetPrefs()->GetString(
479 prefs::kZeroSuggestCachedResults);
480 if (!json_data.empty()) {
[email protected]2c802d12014-07-31 12:57:14481 scoped_ptr<base::Value> data(
482 SearchSuggestionParser::DeserializeJsonData(json_data));
[email protected]776ee5902014-08-11 09:15:19483 if (data && ParseSuggestResults(
484 *data, kDefaultZeroSuggestRelevance, false, &results_)) {
[email protected]855ebff2014-05-09 07:14:38485 ConvertResultsToAutocompleteMatches();
486 results_from_cache_ = !matches_.empty();
487 }
488 }
489}