blob: 4323f046c02285be108d2560c9653a1bb97bc999 [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
blundell2102f7c2015-07-09 10:00:535#include "components/omnibox/browser/zero_suggest_provider.h"
[email protected]6ce7f612012-09-05 23:53:076
avif57136c12015-12-25 23:27:457#include <stddef.h>
8
Kevin Bailey1e2a90e2017-10-27 21:02:059#include <string>
10#include <utility>
11
[email protected]6ce7f612012-09-05 23:53:0712#include "base/callback.h"
gcomanici8cabc77f2017-04-27 20:04:5413#include "base/feature_list.h"
[email protected]bb1fb2b2013-05-31 00:21:0114#include "base/i18n/case_conversion.h"
[email protected]6ce7f612012-09-05 23:53:0715#include "base/json/json_string_value_serializer.h"
asvitkine30330812016-08-30 04:01:0816#include "base/metrics/histogram_macros.h"
[email protected]f7f41c0e2014-08-11 04:22:2317#include "base/metrics/user_metrics.h"
[email protected]98570e12013-06-10 19:54:2218#include "base/strings/string16.h"
19#include "base/strings/string_util.h"
[email protected]135cb802013-06-09 16:44:2020#include "base/strings/utf_string_conversions.h"
[email protected]4dcb7972013-06-28 15:15:4121#include "base/time/time.h"
a-v-ydd768d52016-03-25 21:07:4622#include "base/trace_event/trace_event.h"
amohammadkhanf76ae112015-09-14 17:34:4323#include "components/data_use_measurement/core/data_use_user_data.h"
sdefresnebc766ef2014-09-25 09:28:1324#include "components/history/core/browser/history_types.h"
sdefresne0da3bc02015-01-29 18:26:3525#include "components/history/core/browser/top_sites.h"
blundell2102f7c2015-07-09 10:00:5326#include "components/omnibox/browser/autocomplete_classifier.h"
27#include "components/omnibox/browser/autocomplete_input.h"
28#include "components/omnibox/browser/autocomplete_match.h"
29#include "components/omnibox/browser/autocomplete_provider_listener.h"
Daniel Kenji Toyamaf1e4b572017-08-03 16:31:1130#include "components/omnibox/browser/contextual_suggestions_service.h"
blundell2102f7c2015-07-09 10:00:5331#include "components/omnibox/browser/history_url_provider.h"
32#include "components/omnibox/browser/omnibox_field_trial.h"
33#include "components/omnibox/browser/omnibox_pref_names.h"
34#include "components/omnibox/browser/search_provider.h"
sdefresne70948d62015-08-11 10:46:3535#include "components/omnibox/browser/verbatim_match.h"
[email protected]f0c8c4992014-05-15 17:37:2636#include "components/pref_registry/pref_registry_syncable.h"
brettwf00b9b42016-02-01 22:11:3837#include "components/prefs/pref_service.h"
[email protected]bf5c532d2014-07-05 00:29:5338#include "components/search_engines/template_url_service.h"
rsleevi24f64dc22015-08-07 21:39:2139#include "components/url_formatter/url_formatter.h"
asvitkine9a279832015-12-18 02:35:5040#include "components/variations/net/variations_http_headers.h"
[email protected]bb1fb2b2013-05-31 00:21:0141#include "net/base/escape.h"
[email protected]6ce7f612012-09-05 23:53:0742#include "net/url_request/url_fetcher.h"
43#include "net/url_request/url_request_status.h"
Steven Holtef9d5ed62017-10-21 02:02:3044#include "third_party/metrics_proto/omnibox_event.pb.h"
45#include "third_party/metrics_proto/omnibox_input_type.pb.h"
[email protected]761fa4702013-07-02 15:25:1546#include "url/gurl.h"
[email protected]6ce7f612012-09-05 23:53:0747
48namespace {
[email protected]bb1fb2b2013-05-31 00:21:0149
mpearson3d89cdc2017-03-03 21:15:4550// Represents whether ZeroSuggestProvider is allowed to display contextual
51// suggestions on focus, and if not, why not.
52// These values are written to logs. New enum values can be added, but existing
53// enums must never be renumbered or deleted and reused.
54enum class ZeroSuggestEligibility {
55 ELIGIBLE = 0,
56 // URL_INELIGIBLE would be ELIGIBLE except some property of the current URL
57 // itself prevents ZeroSuggest from triggering.
58 URL_INELIGIBLE = 1,
59 GENERALLY_INELIGIBLE = 2,
60 ELIGIBLE_MAX_VALUE
61};
62
[email protected]bb1fb2b2013-05-31 00:21:0163// TODO(hfung): The histogram code was copied and modified from
64// search_provider.cc. Refactor and consolidate the code.
65// We keep track in a histogram how many suggest requests we send, how
66// many suggest requests we invalidate (e.g., due to a user typing
67// another character), and how many replies we receive.
mpearson3d89cdc2017-03-03 21:15:4568// These values are written to logs. New enum values can be added, but existing
69// enums must never be renumbered or deleted and reused.
[email protected]bb1fb2b2013-05-31 00:21:0170enum ZeroSuggestRequestsHistogramValue {
71 ZERO_SUGGEST_REQUEST_SENT = 1,
mpearson3d89cdc2017-03-03 21:15:4572 ZERO_SUGGEST_REQUEST_INVALIDATED = 2,
73 ZERO_SUGGEST_REPLY_RECEIVED = 3,
[email protected]bb1fb2b2013-05-31 00:21:0174 ZERO_SUGGEST_MAX_REQUEST_HISTOGRAM_VALUE
75};
76
77void LogOmniboxZeroSuggestRequest(
78 ZeroSuggestRequestsHistogramValue request_value) {
79 UMA_HISTOGRAM_ENUMERATION("Omnibox.ZeroSuggestRequests", request_value,
80 ZERO_SUGGEST_MAX_REQUEST_HISTOGRAM_VALUE);
81}
82
[email protected]bb1fb2b2013-05-31 00:21:0183// Relevance value to use if it was not set explicitly by the server.
84const int kDefaultZeroSuggestRelevance = 100;
85
mpearson3d89cdc2017-03-03 21:15:4586// Used for testing whether zero suggest is ever available.
mpearsonc90c24b2017-03-04 00:11:2687constexpr char kArbitraryInsecureUrlString[] = "http://www.google.com/";
mpearson3d89cdc2017-03-03 21:15:4588
[email protected]6ce7f612012-09-05 23:53:0789} // namespace
90
[email protected]a00008d42012-09-15 05:07:5891// static
92ZeroSuggestProvider* ZeroSuggestProvider::Create(
blundell55e35e82015-06-16 08:46:1893 AutocompleteProviderClient* client,
mpearson931028c2016-07-01 18:55:1194 HistoryURLProvider* history_url_provider,
blundelld130d592015-06-21 19:29:1395 AutocompleteProviderListener* listener) {
mpearson931028c2016-07-01 18:55:1196 return new ZeroSuggestProvider(client, history_url_provider, listener);
[email protected]6ce7f612012-09-05 23:53:0797}
98
[email protected]855ebff2014-05-09 07:14:3899// static
100void ZeroSuggestProvider::RegisterProfilePrefs(
101 user_prefs::PrefRegistrySyncable* registry) {
blundelld130d592015-06-21 19:29:13102 registry->RegisterStringPref(omnibox::kZeroSuggestCachedResults,
103 std::string());
[email protected]855ebff2014-05-09 07:14:38104}
105
[email protected]6ce7f612012-09-05 23:53:07106void ZeroSuggestProvider::Start(const AutocompleteInput& input,
jifcf322cd2015-06-17 11:01:18107 bool minimal_changes) {
a-v-ydd768d52016-03-25 21:07:46108 TRACE_EVENT0("omnibox", "ZeroSuggestProvider::Start");
[email protected]f030c4d2014-03-25 01:05:54109 matches_.clear();
mpearson6eaf7fc2017-04-11 04:09:57110 if (!input.from_omnibox_focus() || client()->IsOffTheRecord() ||
mariakhomenko3ef531d72015-01-10 00:03:43111 input.type() == metrics::OmniboxInputType::INVALID)
[email protected]f030c4d2014-03-25 01:05:54112 return;
[email protected]bb1fb2b2013-05-31 00:21:01113
mpearson8a37c382015-03-07 05:58:57114 Stop(true, false);
blundelld130d592015-06-21 19:29:13115 set_field_trial_triggered(false);
116 set_field_trial_triggered_in_session(false);
[email protected]855ebff2014-05-09 07:14:38117 results_from_cache_ = false;
[email protected]f030c4d2014-03-25 01:05:54118 permanent_text_ = input.text();
119 current_query_ = input.current_url().spec();
gcomanici8cabc77f2017-04-27 20:04:54120 current_title_ = input.current_title();
[email protected]f030c4d2014-03-25 01:05:54121 current_page_classification_ = input.current_page_classification();
[email protected]9b9fa672013-11-07 06:04:52122 current_url_match_ = MatchForCurrentURL();
123
Daniel Kenji Toyamaf1e4b572017-08-03 16:31:11124 GURL suggest_url = ContextualSuggestionsService::ContextualSuggestionsUrl(
125 /*current_url=*/"", client()->GetTemplateURLService());
[email protected]162c8d9fa2014-03-18 20:25:41126 if (!suggest_url.is_valid())
[email protected]6ce7f612012-09-05 23:53:07127 return;
[email protected]162c8d9fa2014-03-18 20:25:41128
mariakhomenkobfc3a2a2014-10-24 00:48:22129 // No need to send the current page URL in personalized suggest or
130 // most visited field trials.
mpearson3d89cdc2017-03-03 21:15:45131 const TemplateURLService* template_url_service =
132 client()->GetTemplateURLService();
133 const TemplateURL* default_provider =
134 template_url_service->GetDefaultSearchProvider();
135 const bool can_send_current_url =
136 CanSendURL(input.current_url(), suggest_url, default_provider,
[email protected]e6477f12014-08-05 07:59:54137 current_page_classification_,
mpearson3d89cdc2017-03-03 21:15:45138 template_url_service->search_terms_data(), client());
139 GURL arbitrary_insecure_url(kArbitraryInsecureUrlString);
140 ZeroSuggestEligibility eligibility = ZeroSuggestEligibility::ELIGIBLE;
141 if (!can_send_current_url) {
142 const bool can_send_ordinary_url =
143 CanSendURL(arbitrary_insecure_url, suggest_url, default_provider,
144 current_page_classification_,
145 template_url_service->search_terms_data(), client());
146 eligibility = can_send_ordinary_url
147 ? ZeroSuggestEligibility::URL_INELIGIBLE
148 : ZeroSuggestEligibility::GENERALLY_INELIGIBLE;
149 }
150 UMA_HISTOGRAM_ENUMERATION(
151 "Omnibox.ZeroSuggest.Eligible.OnFocus", static_cast<int>(eligibility),
152 static_cast<int>(ZeroSuggestEligibility::ELIGIBLE_MAX_VALUE));
Daniel Kenji Toyamaf1e4b572017-08-03 16:31:11153
154 bool can_attach_current_url =
155 can_send_current_url &&
Theresa Wellingtondd71c5c2017-10-02 15:50:38156 !OmniboxFieldTrial::InZeroSuggestPersonalizedFieldTrial(
157 client()->GetPrefs()) &&
158 !OmniboxFieldTrial::InZeroSuggestMostVisitedFieldTrial(
159 client()->GetPrefs());
Daniel Kenji Toyamaf1e4b572017-08-03 16:31:11160
161 if (!can_attach_current_url &&
162 !ShouldShowNonContextualZeroSuggest(input.current_url())) {
[email protected]162c8d9fa2014-03-18 20:25:41163 return;
164 }
165
[email protected]6ce7f612012-09-05 23:53:07166 done_ = false;
Daniel Kenji Toyamaf1e4b572017-08-03 16:31:11167
[email protected]6ce7f612012-09-05 23:53:07168 // TODO(jered): Consider adding locally-sourced zero-suggestions here too.
169 // These may be useful on the NTP or more relevant to the user than server
170 // suggestions, if based on local browsing history.
[email protected]855ebff2014-05-09 07:14:38171 MaybeUseCachedSuggestions();
Daniel Kenji Toyamaf1e4b572017-08-03 16:31:11172
Theresa Wellingtondd71c5c2017-10-02 15:50:38173 if (OmniboxFieldTrial::InZeroSuggestMostVisitedFieldTrial(
174 client()->GetPrefs())) {
Daniel Kenji Toyamaf1e4b572017-08-03 16:31:11175 most_visited_urls_.clear();
176 scoped_refptr<history::TopSites> ts = client()->GetTopSites();
177 if (ts) {
178 waiting_for_most_visited_urls_request_ = true;
179 ts->GetMostVisitedURLs(
180 base::Bind(&ZeroSuggestProvider::OnMostVisitedUrlsAvailable,
181 weak_ptr_factory_.GetWeakPtr()),
182 false);
183 }
184 return;
185 }
186
187 // Create a request for suggestions with |this| as the fetcher delegate.
188 client()
Gheorghe Comanici86bbdf62017-08-28 17:20:33189 ->GetContextualSuggestionsService(/*create_if_necessary=*/true)
Daniel Kenji Toyamaf1e4b572017-08-03 16:31:11190 ->CreateContextualSuggestionsRequest(
191 can_attach_current_url ? current_query_ : std::string(),
192 client()->GetTemplateURLService(),
193 /*fetcher_delegate=*/this,
194 base::BindOnce(
195 &ZeroSuggestProvider::OnContextualSuggestionsFetcherAvailable,
196 weak_ptr_factory_.GetWeakPtr()));
[email protected]6ce7f612012-09-05 23:53:07197}
198
mpearson8a37c382015-03-07 05:58:57199void ZeroSuggestProvider::Stop(bool clear_cached_results,
200 bool due_to_user_inactivity) {
[email protected]ec3f679b2014-08-18 07:45:13201 if (fetcher_)
202 LogOmniboxZeroSuggestRequest(ZERO_SUGGEST_REQUEST_INVALIDATED);
203 fetcher_.reset();
mariakhomenkobfc3a2a2014-10-24 00:48:22204 waiting_for_most_visited_urls_request_ = false;
Gheorghe Comanici86bbdf62017-08-28 17:20:33205 auto* contextual_suggestions_service =
206 client()->GetContextualSuggestionsService(/*create_if_necessary=*/false);
207 // contextual_suggestions_service can be null if in incognito mode.
208 if (contextual_suggestions_service != nullptr) {
209 contextual_suggestions_service->StopCreatingContextualSuggestionsRequest();
210 }
[email protected]ec3f679b2014-08-18 07:45:13211 done_ = true;
212
213 if (clear_cached_results) {
214 // We do not call Clear() on |results_| to retain |verbatim_relevance|
215 // value in the |results_| object. |verbatim_relevance| is used at the
jifcf322cd2015-06-17 11:01:18216 // beginning of the next call to Start() to determine the current url
217 // match relevance.
[email protected]ec3f679b2014-08-18 07:45:13218 results_.suggest_results.clear();
219 results_.navigation_results.clear();
220 current_query_.clear();
gcomanici8cabc77f2017-04-27 20:04:54221 current_title_.clear();
mariakhomenko1535e6a2015-03-20 07:48:45222 most_visited_urls_.clear();
[email protected]ec3f679b2014-08-18 07:45:13223 }
224}
225
[email protected]855ebff2014-05-09 07:14:38226void ZeroSuggestProvider::DeleteMatch(const AutocompleteMatch& match) {
Theresa Wellingtondd71c5c2017-10-02 15:50:38227 if (OmniboxFieldTrial::InZeroSuggestPersonalizedFieldTrial(
228 client()->GetPrefs())) {
[email protected]855ebff2014-05-09 07:14:38229 // Remove the deleted match from the cache, so it is not shown to the user
230 // again. Since we cannot remove just one result, blow away the cache.
blundelld130d592015-06-21 19:29:13231 client()->GetPrefs()->SetString(omnibox::kZeroSuggestCachedResults,
[email protected]855ebff2014-05-09 07:14:38232 std::string());
233 }
234 BaseSearchProvider::DeleteMatch(match);
235}
236
[email protected]ec3f679b2014-08-18 07:45:13237void ZeroSuggestProvider::AddProviderInfo(ProvidersInfo* provider_info) const {
238 BaseSearchProvider::AddProviderInfo(provider_info);
mariakhomenko1535e6a2015-03-20 07:48:45239 if (!results_.suggest_results.empty() ||
240 !results_.navigation_results.empty() ||
241 !most_visited_urls_.empty())
[email protected]ec3f679b2014-08-18 07:45:13242 provider_info->back().set_times_returned_results_in_session(1);
243}
244
[email protected]f030c4d2014-03-25 01:05:54245void ZeroSuggestProvider::ResetSession() {
246 // The user has started editing in the omnibox, so leave
blundelld130d592015-06-21 19:29:13247 // |field_trial_triggered_in_session| unchanged and set
248 // |field_trial_triggered| to false since zero suggest is inactive now.
249 set_field_trial_triggered(false);
[email protected]f030c4d2014-03-25 01:05:54250}
251
mpearson931028c2016-07-01 18:55:11252ZeroSuggestProvider::ZeroSuggestProvider(
253 AutocompleteProviderClient* client,
254 HistoryURLProvider* history_url_provider,
255 AutocompleteProviderListener* listener)
blundelld130d592015-06-21 19:29:13256 : BaseSearchProvider(AutocompleteProvider::TYPE_ZERO_SUGGEST, client),
mpearson931028c2016-07-01 18:55:11257 history_url_provider_(history_url_provider),
[email protected]776ee5902014-08-11 09:15:19258 listener_(listener),
[email protected]855ebff2014-05-09 07:14:38259 results_from_cache_(false),
mariakhomenkobfc3a2a2014-10-24 00:48:22260 waiting_for_most_visited_urls_request_(false),
[email protected]8f064e52013-09-18 01:17:14261 weak_ptr_factory_(this) {
mpearson3d89cdc2017-03-03 21:15:45262 // Record whether contextual zero suggest is possible for this user / profile.
263 const TemplateURLService* template_url_service =
264 client->GetTemplateURLService();
265 // Template URL service can be null in tests.
266 if (template_url_service != nullptr) {
Daniel Kenji Toyamaf1e4b572017-08-03 16:31:11267 GURL suggest_url = ContextualSuggestionsService::ContextualSuggestionsUrl(
268 /*current_url=*/"", template_url_service);
mpearson3d89cdc2017-03-03 21:15:45269 // To check whether this is allowed, use an arbitrary insecure (http) URL
270 // as the URL we'd want suggestions for. The value of OTHER as the current
271 // page classification is to correspond with that URL.
272 UMA_HISTOGRAM_BOOLEAN(
273 "Omnibox.ZeroSuggest.Eligible.OnProfileOpen",
274 suggest_url.is_valid() &&
275 CanSendURL(GURL(kArbitraryInsecureUrlString), suggest_url,
276 template_url_service->GetDefaultSearchProvider(),
277 metrics::OmniboxEventProto::OTHER,
278 template_url_service->search_terms_data(), client));
279 }
[email protected]6ce7f612012-09-05 23:53:07280}
281
282ZeroSuggestProvider::~ZeroSuggestProvider() {
283}
284
[email protected]776ee5902014-08-11 09:15:19285const TemplateURL* ZeroSuggestProvider::GetTemplateURL(bool is_keyword) const {
286 // Zero suggest provider should not receive keyword results.
287 DCHECK(!is_keyword);
blundelld130d592015-06-21 19:29:13288 return client()->GetTemplateURLService()->GetDefaultSearchProvider();
[email protected]776ee5902014-08-11 09:15:19289}
290
291const AutocompleteInput ZeroSuggestProvider::GetInput(bool is_keyword) const {
jifcf322cd2015-06-17 11:01:18292 // The callers of this method won't look at the AutocompleteInput's
293 // |from_omnibox_focus| member, so we can set its value to false.
Kevin Baileybcc319e2017-10-01 21:53:02294 AutocompleteInput input(base::string16(), current_page_classification_,
295 client()->GetSchemeClassifier());
296 input.set_current_url(GURL(current_query_));
297 input.set_current_title(current_title_);
298 input.set_prevent_inline_autocomplete(true);
299 input.set_allow_exact_keyword_match(false);
300 return input;
[email protected]776ee5902014-08-11 09:15:19301}
302
303bool ZeroSuggestProvider::ShouldAppendExtraParams(
304 const SearchSuggestionParser::SuggestResult& result) const {
305 // We always use the default provider for search, so append the params.
306 return true;
307}
308
[email protected]776ee5902014-08-11 09:15:19309void ZeroSuggestProvider::RecordDeletionResult(bool success) {
310 if (success) {
311 base::RecordAction(
312 base::UserMetricsAction("Omnibox.ZeroSuggestDelete.Success"));
313 } else {
314 base::RecordAction(
315 base::UserMetricsAction("Omnibox.ZeroSuggestDelete.Failure"));
316 }
317}
318
319void ZeroSuggestProvider::OnURLFetchComplete(const net::URLFetcher* source) {
320 DCHECK(!done_);
321 DCHECK_EQ(fetcher_.get(), source);
322
323 LogOmniboxZeroSuggestRequest(ZERO_SUGGEST_REPLY_RECEIVED);
324
325 bool results_updated = false;
326 if (source->GetStatus().is_success() && source->GetResponseCode() == 200) {
327 std::string json_data = SearchSuggestionParser::ExtractJsonData(source);
dcheng259570c2016-04-22 00:45:57328 std::unique_ptr<base::Value> data(
[email protected]776ee5902014-08-11 09:15:19329 SearchSuggestionParser::DeserializeJsonData(json_data));
330 if (data) {
331 if (StoreSuggestionResponse(json_data, *data))
332 return;
333 results_updated = ParseSuggestResults(
334 *data, kDefaultZeroSuggestRelevance, false, &results_);
335 }
336 }
337 fetcher_.reset();
338 done_ = true;
339 ConvertResultsToAutocompleteMatches();
340 listener_->OnProviderUpdate(results_updated);
341}
342
[email protected]855ebff2014-05-09 07:14:38343bool ZeroSuggestProvider::StoreSuggestionResponse(
344 const std::string& json_data,
345 const base::Value& parsed_data) {
Theresa Wellingtondd71c5c2017-10-02 15:50:38346 if (!OmniboxFieldTrial::InZeroSuggestPersonalizedFieldTrial(
347 client()->GetPrefs()) ||
[email protected]855ebff2014-05-09 07:14:38348 json_data.empty())
349 return false;
blundelld130d592015-06-21 19:29:13350 client()->GetPrefs()->SetString(omnibox::kZeroSuggestCachedResults,
351 json_data);
[email protected]855ebff2014-05-09 07:14:38352
353 // If we received an empty result list, we should update the display, as it
354 // may be showing cached results that should not be shown.
Ivan Kotenkov75b1c3a2017-10-24 14:47:24355 const base::ListValue* root_list = nullptr;
356 const base::ListValue* results_list = nullptr;
[email protected]855ebff2014-05-09 07:14:38357 if (parsed_data.GetAsList(&root_list) &&
358 root_list->GetList(1, &results_list) &&
359 results_list->empty())
360 return false;
361
362 // We are finished with the request and want to bail early.
363 if (results_from_cache_)
364 done_ = true;
365
366 return results_from_cache_;
367}
368
[email protected]bb1fb2b2013-05-31 00:21:01369void ZeroSuggestProvider::AddSuggestResultsToMap(
[email protected]0b9575f2014-07-30 11:58:37370 const SearchSuggestionParser::SuggestResults& results,
[email protected]02346202014-02-05 05:18:30371 MatchMap* map) {
[email protected]d4a94b92014-03-04 01:35:22372 for (size_t i = 0; i < results.size(); ++i)
[email protected]7bc5e162014-08-15 19:41:11373 AddMatchToMap(results[i], std::string(), i, false, false, map);
[email protected]bb1fb2b2013-05-31 00:21:01374}
375
[email protected]bb1fb2b2013-05-31 00:21:01376AutocompleteMatch ZeroSuggestProvider::NavigationToMatch(
[email protected]0b9575f2014-07-30 11:58:37377 const SearchSuggestionParser::NavigationResult& navigation) {
[email protected]bb1fb2b2013-05-31 00:21:01378 AutocompleteMatch match(this, navigation.relevance(), false,
[email protected]78981d8c2014-05-09 15:05:47379 navigation.type());
[email protected]bb1fb2b2013-05-31 00:21:01380 match.destination_url = navigation.url();
381
[email protected]23db6492014-01-16 02:35:30382 // Zero suggest results should always omit protocols and never appear bold.
Tommy C. Lia46e6382017-08-01 23:26:27383 auto format_types = AutocompleteMatch::GetFormatTypes(false, false, false);
tommycli72014f62017-06-29 21:42:16384 match.contents = url_formatter::FormatUrl(navigation.url(), format_types,
385 net::UnescapeRule::SPACES, nullptr,
386 nullptr, nullptr);
[email protected]bb1fb2b2013-05-31 00:21:01387 match.fill_into_edit +=
blundelld130d592015-06-21 19:29:13388 AutocompleteInput::FormattedStringWithEquivalentMeaning(
Tommy C. Li0beb8152017-08-25 18:30:26389 navigation.url(), url_formatter::FormatUrl(navigation.url()),
390 client()->GetSchemeClassifier());
[email protected]bb1fb2b2013-05-31 00:21:01391
[email protected]b959d7d42013-12-13 17:26:37392 AutocompleteMatch::ClassifyLocationInString(base::string16::npos, 0,
[email protected]bb1fb2b2013-05-31 00:21:01393 match.contents.length(), ACMatchClassification::URL,
394 &match.contents_class);
[email protected]9c97f89c2013-06-25 03:12:16395
396 match.description =
397 AutocompleteMatch::SanitizeString(navigation.description());
[email protected]b959d7d42013-12-13 17:26:37398 AutocompleteMatch::ClassifyLocationInString(base::string16::npos, 0,
[email protected]9c97f89c2013-06-25 03:12:16399 match.description.length(), ACMatchClassification::NONE,
400 &match.description_class);
gcomanici67d53ac2017-04-01 17:07:19401 match.subtype_identifier = navigation.subtype_identifier();
[email protected]bb1fb2b2013-05-31 00:21:01402 return match;
403}
404
[email protected]8f064e52013-09-18 01:17:14405void ZeroSuggestProvider::OnMostVisitedUrlsAvailable(
406 const history::MostVisitedURLList& urls) {
mariakhomenkobfc3a2a2014-10-24 00:48:22407 if (!waiting_for_most_visited_urls_request_) return;
[email protected]8f064e52013-09-18 01:17:14408 most_visited_urls_ = urls;
mariakhomenkobfc3a2a2014-10-24 00:48:22409 waiting_for_most_visited_urls_request_ = false;
410 done_ = true;
411 ConvertResultsToAutocompleteMatches();
412 listener_->OnProviderUpdate(true);
[email protected]8f064e52013-09-18 01:17:14413}
414
Daniel Kenji Toyamaf1e4b572017-08-03 16:31:11415void ZeroSuggestProvider::OnContextualSuggestionsFetcherAvailable(
416 std::unique_ptr<net::URLFetcher> fetcher) {
417 fetcher_ = std::move(fetcher);
418 fetcher_->Start();
419 LogOmniboxZeroSuggestRequest(ZERO_SUGGEST_REQUEST_SENT);
420}
421
[email protected]9c97f89c2013-06-25 03:12:16422void ZeroSuggestProvider::ConvertResultsToAutocompleteMatches() {
[email protected]bb1fb2b2013-05-31 00:21:01423 matches_.clear();
424
blundelld130d592015-06-21 19:29:13425 TemplateURLService* template_url_service = client()->GetTemplateURLService();
[email protected]bb1fb2b2013-05-31 00:21:01426 const TemplateURL* default_provider =
blundelld130d592015-06-21 19:29:13427 template_url_service->GetDefaultSearchProvider();
[email protected]6ce7f612012-09-05 23:53:07428 // Fail if we can't set the clickthrough URL for query suggestions.
Ivan Kotenkov75b1c3a2017-10-24 14:47:24429 if (default_provider == nullptr ||
blundelld130d592015-06-21 19:29:13430 !default_provider->SupportsReplacement(
431 template_url_service->search_terms_data()))
[email protected]6ce7f612012-09-05 23:53:07432 return;
[email protected]6ce7f612012-09-05 23:53:07433
[email protected]00404742014-02-20 13:09:05434 MatchMap map;
435 AddSuggestResultsToMap(results_.suggest_results, &map);
436
437 const int num_query_results = map.size();
438 const int num_nav_results = results_.navigation_results.size();
[email protected]bb1fb2b2013-05-31 00:21:01439 const int num_results = num_query_results + num_nav_results;
[email protected]9c97f89c2013-06-25 03:12:16440 UMA_HISTOGRAM_COUNTS("ZeroSuggest.QueryResults", num_query_results);
[email protected]78981d8c2014-05-09 15:05:47441 UMA_HISTOGRAM_COUNTS("ZeroSuggest.URLResults", num_nav_results);
[email protected]9c97f89c2013-06-25 03:12:16442 UMA_HISTOGRAM_COUNTS("ZeroSuggest.AllResults", num_results);
[email protected]bb1fb2b2013-05-31 00:21:01443
[email protected]8f064e52013-09-18 01:17:14444 // Show Most Visited results after ZeroSuggest response is received.
Theresa Wellingtondd71c5c2017-10-02 15:50:38445 if (OmniboxFieldTrial::InZeroSuggestMostVisitedFieldTrial(
446 client()->GetPrefs())) {
[email protected]3feb8b002013-10-14 23:50:13447 if (!current_url_match_.destination_url.is_valid())
448 return;
[email protected]8f064e52013-09-18 01:17:14449 matches_.push_back(current_url_match_);
450 int relevance = 600;
451 if (num_results > 0) {
452 UMA_HISTOGRAM_COUNTS(
453 "Omnibox.ZeroSuggest.MostVisitedResultsCounterfactual",
454 most_visited_urls_.size());
455 }
[email protected]23db6492014-01-16 02:35:30456 const base::string16 current_query_string16(
457 base::ASCIIToUTF16(current_query_));
[email protected]8f064e52013-09-18 01:17:14458 for (size_t i = 0; i < most_visited_urls_.size(); i++) {
459 const history::MostVisitedURL& url = most_visited_urls_[i];
[email protected]0b9575f2014-07-30 11:58:37460 SearchSuggestionParser::NavigationResult nav(
blundelld130d592015-06-21 19:29:13461 client()->GetSchemeClassifier(), url.url,
gcomanici67d53ac2017-04-01 17:07:19462 AutocompleteMatchType::NAVSUGGEST, 0, url.title, std::string(), false,
jshin1fb76462016-04-05 22:13:03463 relevance, true, current_query_string16);
[email protected]8f064e52013-09-18 01:17:14464 matches_.push_back(NavigationToMatch(nav));
465 --relevance;
466 }
467 return;
468 }
469
[email protected]9c97f89c2013-06-25 03:12:16470 if (num_results == 0)
[email protected]bb1fb2b2013-05-31 00:21:01471 return;
472
473 // TODO(jered): Rip this out once the first match is decoupled from the
474 // current typing in the omnibox.
[email protected]bb1fb2b2013-05-31 00:21:01475 matches_.push_back(current_url_match_);
476
[email protected]00404742014-02-20 13:09:05477 for (MatchMap::const_iterator it(map.begin()); it != map.end(); ++it)
[email protected]bb1fb2b2013-05-31 00:21:01478 matches_.push_back(it->second);
[email protected]bb1fb2b2013-05-31 00:21:01479
[email protected]0b9575f2014-07-30 11:58:37480 const SearchSuggestionParser::NavigationResults& nav_results(
481 results_.navigation_results);
482 for (SearchSuggestionParser::NavigationResults::const_iterator it(
gcomanici67d53ac2017-04-01 17:07:19483 nav_results.begin());
484 it != nav_results.end(); ++it) {
[email protected]bb1fb2b2013-05-31 00:21:01485 matches_.push_back(NavigationToMatch(*it));
gcomanici67d53ac2017-04-01 17:07:19486 }
[email protected]6ce7f612012-09-05 23:53:07487}
488
[email protected]bb1fb2b2013-05-31 00:21:01489AutocompleteMatch ZeroSuggestProvider::MatchForCurrentURL() {
[email protected]bb1fb2b2013-05-31 00:21:01490 // The placeholder suggestion for the current URL has high relevance so
491 // that it is in the first suggestion slot and inline autocompleted. It
492 // gets dropped as soon as the user types something.
mpearson931028c2016-07-01 18:55:11493 AutocompleteInput tmp(GetInput(false));
494 tmp.UpdateText(permanent_text_, base::string16::npos, tmp.parts());
gcomanici8cabc77f2017-04-27 20:04:54495 const base::string16 description =
496 (base::FeatureList::IsEnabled(omnibox::kDisplayTitleForCurrentUrl))
497 ? current_title_
498 : base::string16();
499 return VerbatimMatchForURL(client(), tmp, GURL(current_query_), description,
mpearson931028c2016-07-01 18:55:11500 history_url_provider_,
sdefresne70948d62015-08-11 10:46:35501 results_.verbatim_relevance);
[email protected]00404742014-02-20 13:09:05502}
[email protected]162c8d9fa2014-03-18 20:25:41503
mariakhomenkobfc3a2a2014-10-24 00:48:22504bool ZeroSuggestProvider::ShouldShowNonContextualZeroSuggest(
[email protected]162c8d9fa2014-03-18 20:25:41505 const GURL& current_page_url) const {
gcomanicide29a4362017-06-02 15:44:08506 if (!ZeroSuggestEnabled(current_page_classification_, client()))
[email protected]162c8d9fa2014-03-18 20:25:41507 return false;
508
509 // If we cannot send URLs, then only the MostVisited and Personalized
510 // variations can be shown.
Theresa Wellingtondd71c5c2017-10-02 15:50:38511 // The const-cast allows the non-const AutocompleteProviderClient::GetPrefs()
512 // function to be called. OmniboxFieldTrial does not modify prefs, so the
513 // cast is safe in this application.
514 if (!OmniboxFieldTrial::InZeroSuggestMostVisitedFieldTrial(
515 const_cast<AutocompleteProviderClient*>(client())->GetPrefs()) &&
516 !OmniboxFieldTrial::InZeroSuggestPersonalizedFieldTrial(
517 const_cast<AutocompleteProviderClient*>(client())->GetPrefs()))
[email protected]162c8d9fa2014-03-18 20:25:41518 return false;
519
520 // Only show zero suggest for HTTP[S] pages.
521 // TODO(mariakhomenko): We may be able to expand this set to include pages
522 // with other schemes (e.g. chrome://). That may require improvements to
523 // the formatting of the verbatim result returned by MatchForCurrentURL().
524 if (!current_page_url.is_valid() ||
[email protected]e8ca69c2014-05-07 15:31:19525 ((current_page_url.scheme() != url::kHttpScheme) &&
526 (current_page_url.scheme() != url::kHttpsScheme)))
[email protected]162c8d9fa2014-03-18 20:25:41527 return false;
528
Theresa Wellingtondd71c5c2017-10-02 15:50:38529 if (OmniboxFieldTrial::InZeroSuggestMostVisitedWithoutSerpFieldTrial(
530 const_cast<AutocompleteProviderClient*>(client())->GetPrefs()) &&
blundelld130d592015-06-21 19:29:13531 client()
532 ->GetTemplateURLService()
533 ->IsSearchResultsPageFromDefaultSearchProvider(current_page_url))
mariakhomenkobfc3a2a2014-10-24 00:48:22534 return false;
535
[email protected]162c8d9fa2014-03-18 20:25:41536 return true;
537}
[email protected]855ebff2014-05-09 07:14:38538
539void ZeroSuggestProvider::MaybeUseCachedSuggestions() {
Theresa Wellingtondd71c5c2017-10-02 15:50:38540 if (!OmniboxFieldTrial::InZeroSuggestPersonalizedFieldTrial(
541 client()->GetPrefs()))
[email protected]855ebff2014-05-09 07:14:38542 return;
543
blundelld130d592015-06-21 19:29:13544 std::string json_data =
545 client()->GetPrefs()->GetString(omnibox::kZeroSuggestCachedResults);
[email protected]855ebff2014-05-09 07:14:38546 if (!json_data.empty()) {
dcheng259570c2016-04-22 00:45:57547 std::unique_ptr<base::Value> data(
[email protected]2c802d12014-07-31 12:57:14548 SearchSuggestionParser::DeserializeJsonData(json_data));
[email protected]776ee5902014-08-11 09:15:19549 if (data && ParseSuggestResults(
550 *data, kDefaultZeroSuggestRelevance, false, &results_)) {
[email protected]855ebff2014-05-09 07:14:38551 ConvertResultsToAutocompleteMatches();
552 results_from_cache_ = !matches_.empty();
553 }
554 }
555}