Index: chrome/browser/autocomplete/zero_suggest_provider.cc |
diff --git a/chrome/browser/autocomplete/zero_suggest_provider.cc b/chrome/browser/autocomplete/zero_suggest_provider.cc |
index 62db13a0f99d8cc07c310794245ce2ee35a70796..a299b006806ed4fa50f3e5c3036b2505491a6dc6 100644 |
--- a/chrome/browser/autocomplete/zero_suggest_provider.cc |
+++ b/chrome/browser/autocomplete/zero_suggest_provider.cc |
@@ -4,41 +4,33 @@ |
#include "chrome/browser/autocomplete/zero_suggest_provider.h" |
-#include "base/callback.h" |
-#include "base/i18n/case_conversion.h" |
-#include "base/json/json_string_value_serializer.h" |
+#include "base/bind.h" |
#include "base/metrics/histogram.h" |
+#include "base/metrics/user_metrics_action.h" |
#include "base/prefs/pref_service.h" |
#include "base/strings/string16.h" |
-#include "base/strings/string_util.h" |
#include "base/strings/utf_string_conversions.h" |
-#include "base/time/time.h" |
#include "chrome/browser/autocomplete/autocomplete_classifier.h" |
#include "chrome/browser/autocomplete/autocomplete_classifier_factory.h" |
#include "chrome/browser/autocomplete/autocomplete_input.h" |
#include "chrome/browser/autocomplete/autocomplete_match.h" |
+#include "chrome/browser/autocomplete/autocomplete_provider.h" |
#include "chrome/browser/autocomplete/autocomplete_provider_listener.h" |
-#include "chrome/browser/autocomplete/history_url_provider.h" |
-#include "chrome/browser/autocomplete/search_provider.h" |
-#include "chrome/browser/autocomplete/url_prefix.h" |
-#include "chrome/browser/history/history_types.h" |
+#include "chrome/browser/autocomplete/base_search_provider.h" |
#include "chrome/browser/history/top_sites.h" |
#include "chrome/browser/metrics/variations/variations_http_header_provider.h" |
#include "chrome/browser/omnibox/omnibox_field_trial.h" |
#include "chrome/browser/profiles/profile.h" |
-#include "chrome/browser/search/search.h" |
+#include "chrome/browser/search_engines/template_url.h" |
#include "chrome/browser/search_engines/template_url_service.h" |
#include "chrome/browser/search_engines/template_url_service_factory.h" |
-#include "chrome/common/net/url_fixer_upper.h" |
#include "chrome/common/pref_names.h" |
-#include "chrome/common/url_constants.h" |
+#include "content/public/browser/user_metrics.h" |
#include "net/base/escape.h" |
#include "net/base/load_flags.h" |
#include "net/base/net_util.h" |
#include "net/http/http_request_headers.h" |
-#include "net/http/http_response_headers.h" |
#include "net/url_request/url_fetcher.h" |
-#include "net/url_request/url_request_status.h" |
#include "url/gurl.h" |
namespace { |
@@ -80,41 +72,6 @@ ZeroSuggestProvider* ZeroSuggestProvider::Create( |
return new ZeroSuggestProvider(listener, profile); |
} |
-void ZeroSuggestProvider::Start(const AutocompleteInput& input, |
- bool /*minimal_changes*/) { |
-} |
- |
-void ZeroSuggestProvider::Stop(bool clear_cached_results) { |
- if (have_pending_request_) |
- LogOmniboxZeroSuggestRequest(ZERO_SUGGEST_REQUEST_INVALIDATED); |
- have_pending_request_ = false; |
- fetcher_.reset(); |
- done_ = true; |
- if (clear_cached_results) { |
- query_matches_map_.clear(); |
- navigation_results_.clear(); |
- current_query_.clear(); |
- matches_.clear(); |
- } |
-} |
- |
-void ZeroSuggestProvider::AddProviderInfo(ProvidersInfo* provider_info) const { |
- provider_info->push_back(metrics::OmniboxEventProto_ProviderInfo()); |
- metrics::OmniboxEventProto_ProviderInfo& new_entry = provider_info->back(); |
- new_entry.set_provider(AsOmniboxEventProviderType()); |
- new_entry.set_provider_done(done_); |
- std::vector<uint32> field_trial_hashes; |
- OmniboxFieldTrial::GetActiveSuggestFieldTrialHashes(&field_trial_hashes); |
- for (size_t i = 0; i < field_trial_hashes.size(); ++i) { |
- if (field_trial_triggered_) |
- new_entry.mutable_field_trial_triggered()->Add(field_trial_hashes[i]); |
- if (field_trial_triggered_in_session_) { |
- new_entry.mutable_field_trial_triggered_in_session()->Add( |
- field_trial_hashes[i]); |
- } |
- } |
-} |
- |
void ZeroSuggestProvider::ResetSession() { |
// The user has started editing in the omnibox, so leave |
// |field_trial_triggered_in_session_| unchanged and set |
@@ -123,26 +80,14 @@ void ZeroSuggestProvider::ResetSession() { |
Stop(true); |
} |
-void ZeroSuggestProvider::OnURLFetchComplete(const net::URLFetcher* source) { |
- have_pending_request_ = false; |
+void ZeroSuggestProvider::LogFetchComplete(const net::URLFetcher* source) { |
LogOmniboxZeroSuggestRequest(ZERO_SUGGEST_REPLY_RECEIVED); |
+} |
- std::string json_data; |
- source->GetResponseAsString(&json_data); |
- const bool request_succeeded = |
- source->GetStatus().is_success() && source->GetResponseCode() == 200; |
- |
- if (request_succeeded) { |
- scoped_ptr<base::Value> data( |
- SearchProvider::DeserializeJsonData(json_data)); |
- if (data.get()) |
- ParseSuggestResults(*data.get()); |
- } |
- done_ = true; |
- |
- ConvertResultsToAutocompleteMatches(); |
- if (!matches_.empty()) |
- listener_->OnProviderUpdate(true); |
+bool ZeroSuggestProvider::ShouldSendProviderUpdate(bool results_updated) { |
+ // If we have matches, the results must have successfully parsed. |
+ DCHECK(!matches_.empty() ? results_updated : true); |
+ return !matches_.empty(); |
} |
void ZeroSuggestProvider::StartZeroSuggest( |
@@ -166,13 +111,15 @@ void ZeroSuggestProvider::StartZeroSuggest( |
search_term_args.current_page_url = current_query_; |
GURL suggest_url(default_provider->suggestions_url_ref(). |
ReplaceSearchTerms(search_term_args)); |
- if (!SearchProvider::CanSendURL( |
- current_page_url, suggest_url, |
- template_url_service_->GetDefaultSearchProvider(), |
- page_classification, profile_) || |
+ if (!BaseSearchProvider::CanSendURL( |
+ current_page_url, |
+ suggest_url, |
+ template_url_service_->GetDefaultSearchProvider(), |
+ page_classification, |
+ profile_) || |
!OmniboxFieldTrial::InZeroSuggestFieldTrial()) |
return; |
- verbatim_relevance_ = kDefaultVerbatimZeroSuggestRelevance; |
+ results_.verbatim_relevance = kDefaultVerbatimZeroSuggestRelevance; |
done_ = false; |
// TODO(jered): Consider adding locally-sourced zero-suggestions here too. |
// These may be useful on the NTP or more relevant to the user than server |
@@ -180,155 +127,83 @@ void ZeroSuggestProvider::StartZeroSuggest( |
Run(suggest_url); |
} |
-ZeroSuggestProvider::ZeroSuggestProvider( |
- AutocompleteProviderListener* listener, |
- Profile* profile) |
- : AutocompleteProvider(listener, profile, |
- AutocompleteProvider::TYPE_ZERO_SUGGEST), |
- template_url_service_(TemplateURLServiceFactory::GetForProfile(profile)), |
- have_pending_request_(false), |
- verbatim_relevance_(kDefaultVerbatimZeroSuggestRelevance), |
- field_trial_triggered_(false), |
- field_trial_triggered_in_session_(false), |
- weak_ptr_factory_(this) { |
+void ZeroSuggestProvider::StopSuggest() { |
+ if (suggest_results_pending_ > 0) |
+ LogOmniboxZeroSuggestRequest(ZERO_SUGGEST_REQUEST_INVALIDATED); |
+ suggest_results_pending_ = 0; |
+ fetcher_.reset(); |
} |
-ZeroSuggestProvider::~ZeroSuggestProvider() { |
+void ZeroSuggestProvider::ClearAllResults() { |
+ results_.Clear(); |
+ current_query_.clear(); |
+ matches_.clear(); |
} |
-void ZeroSuggestProvider::FillResults( |
- const base::Value& root_val, |
- int* verbatim_relevance, |
- SearchProvider::SuggestResults* suggest_results, |
- SearchProvider::NavigationResults* navigation_results) { |
- base::string16 query; |
- const base::ListValue* root_list = NULL; |
- const base::ListValue* results = NULL; |
- const base::ListValue* relevances = NULL; |
- // The response includes the query, which should be empty for ZeroSuggest |
- // responses. |
- if (!root_val.GetAsList(&root_list) || !root_list->GetString(0, &query) || |
- (!query.empty()) || !root_list->GetList(1, &results)) |
- return; |
- |
- // 3rd element: Description list. |
- const base::ListValue* descriptions = NULL; |
- root_list->GetList(2, &descriptions); |
- |
- // 4th element: Disregard the query URL list for now. |
+ZeroSuggestProvider::ZeroSuggestProvider(AutocompleteProviderListener* listener, |
+ Profile* profile) |
+ : BaseSearchProvider(listener, |
+ profile, |
+ AutocompleteProvider::TYPE_ZERO_SUGGEST), |
+ template_url_service_(TemplateURLServiceFactory::GetForProfile(profile)), |
+ weak_ptr_factory_(this) {} |
- // Reset suggested relevance information from the provider. |
- *verbatim_relevance = kDefaultVerbatimZeroSuggestRelevance; |
+ZeroSuggestProvider::~ZeroSuggestProvider() {} |
- // 5th element: Optional key-value pairs from the Suggest server. |
- const base::ListValue* types = NULL; |
- const base::DictionaryValue* extras = NULL; |
- if (root_list->GetDictionary(4, &extras)) { |
- extras->GetList("google:suggesttype", &types); |
+bool ZeroSuggestProvider::IsValidQuery(const base::string16 query, |
+ const net::URLFetcher* source) { |
+ return query.empty(); |
+} |
- // Discard this list if its size does not match that of the suggestions. |
- if (extras->GetList("google:suggestrelevance", &relevances) && |
- relevances->GetSize() != results->GetSize()) |
- relevances = NULL; |
- extras->GetInteger("google:verbatimrelevance", verbatim_relevance); |
+const base::string16 ZeroSuggestProvider::GetInputText( |
+ const net::URLFetcher* source) { |
+ return base::ASCIIToUTF16(current_query_); |
+} |
- // Check if the active suggest field trial (if any) has triggered. |
- bool triggered = false; |
- extras->GetBoolean("google:fieldtrialtriggered", &triggered); |
- field_trial_triggered_ |= triggered; |
- field_trial_triggered_in_session_ |= triggered; |
- } |
+int ZeroSuggestProvider::GetDefaultRelevance() { |
+ return kDefaultZeroSuggestRelevance; |
+} |
- // Clear the previous results now that new results are available. |
- suggest_results->clear(); |
- navigation_results->clear(); |
+void ZeroSuggestProvider::UpdateMatches() { |
+ done_ = true; |
+ ConvertResultsToAutocompleteMatches(); |
+} |
- base::string16 result, title; |
- std::string type; |
- const base::string16 current_query_string16 = |
- base::ASCIIToUTF16(current_query_); |
- const std::string languages( |
- profile_->GetPrefs()->GetString(prefs::kAcceptLanguages)); |
- for (size_t index = 0; results->GetString(index, &result); ++index) { |
- // Google search may return empty suggestions for weird input characters, |
- // they make no sense at all and can cause problems in our code. |
- if (result.empty()) |
- continue; |
- |
- int relevance = kDefaultZeroSuggestRelevance; |
- |
- // Apply valid suggested relevance scores; discard invalid lists. |
- if (relevances != NULL && !relevances->GetInteger(index, &relevance)) |
- relevances = NULL; |
- if (types && types->GetString(index, &type) && (type == "NAVIGATION")) { |
- // Do not blindly trust the URL coming from the server to be valid. |
- GURL url(URLFixerUpper::FixupURL( |
- base::UTF16ToUTF8(result), std::string())); |
- if (url.is_valid()) { |
- if (descriptions != NULL) |
- descriptions->GetString(index, &title); |
- navigation_results->push_back(SearchProvider::NavigationResult( |
- *this, url, title, false, relevance, relevances != NULL, |
- current_query_string16, languages)); |
- } |
- } else { |
- suggest_results->push_back(SearchProvider::SuggestResult( |
- result, AutocompleteMatchType::SEARCH_SUGGEST, result, |
- base::string16(), std::string(), std::string(), false, relevance, |
- relevances != NULL, false, current_query_string16)); |
- } |
- } |
+BaseSearchProvider::Results* ZeroSuggestProvider::GetResultsObjectToFill( |
+ const net::URLFetcher* source) { |
+ return &results_; |
} |
void ZeroSuggestProvider::AddSuggestResultsToMap( |
- const SearchProvider::SuggestResults& results, |
+ const SuggestResults& results, |
const TemplateURL* template_url, |
- SearchProvider::MatchMap* map) { |
+ MatchMap* map) { |
for (size_t i = 0; i < results.size(); ++i) { |
- AddMatchToMap(results[i].relevance(), AutocompleteMatchType::SEARCH_SUGGEST, |
- template_url, results[i].suggestion(), i, map); |
+ const base::string16& query_string(results[i].suggestion()); |
+ const SuggestResult suggestion(query_string, |
+ AutocompleteMatchType::SEARCH_SUGGEST, |
+ query_string, |
+ base::string16(), |
+ std::string(), |
+ std::string(), |
+ false, |
+ results[i].relevance(), |
+ true, |
+ false, |
+ query_string); |
+ AddMatchToMap(suggestion, |
+ AutocompleteInput(), |
+ query_string, |
+ template_url, |
+ std::string(), |
+ i, |
+ true, |
+ map); |
} |
} |
-void ZeroSuggestProvider::AddMatchToMap(int relevance, |
- AutocompleteMatch::Type type, |
- const TemplateURL* template_url, |
- const base::string16& query_string, |
- int accepted_suggestion, |
- SearchProvider::MatchMap* map) { |
- // Pass in query_string as the input_text to avoid bolding. |
- SearchProvider::SuggestResult suggestion( |
- query_string, type, query_string, base::string16(), std::string(), |
- std::string(), false, relevance, true, false, query_string); |
- // TODO(samarth|melevin): use the actual omnibox margin here as well instead |
- // of passing in -1. |
- AutocompleteMatch match = SearchProvider::CreateSearchSuggestion( |
- this, AutocompleteInput(), query_string, suggestion, template_url, |
- accepted_suggestion, -1, true); |
- if (!match.destination_url.is_valid()) |
- return; |
- |
- // Try to add |match| to |map|. If a match for |query_string| is already in |
- // |map|, replace it if |match| is more relevant. |
- // NOTE: Keep this ToLower() call in sync with url_database.cc. |
- SearchProvider::MatchKey match_key( |
- std::make_pair(base::i18n::ToLower(query_string), std::string())); |
- const std::pair<SearchProvider::MatchMap::iterator, bool> i(map->insert( |
- std::make_pair(match_key, match))); |
- // NOTE: We purposefully do a direct relevance comparison here instead of |
- // using AutocompleteMatch::MoreRelevant(), so that we'll prefer "items added |
- // first" rather than "items alphabetically first" when the scores are equal. |
- // The only case this matters is when a user has results with the same score |
- // that differ only by capitalization; because the history system returns |
- // results sorted by recency, this means we'll pick the most recent such |
- // result even if the precision of our relevance score is too low to |
- // distinguish the two. |
- if (!i.second && (match.relevance > i.first->second.relevance)) |
- i.first->second = match; |
-} |
- |
AutocompleteMatch ZeroSuggestProvider::NavigationToMatch( |
- const SearchProvider::NavigationResult& navigation) { |
+ const NavigationResult& navigation) { |
AutocompleteMatch match(this, navigation.relevance(), false, |
AutocompleteMatchType::NAVSUGGEST); |
match.destination_url = navigation.url(); |
@@ -355,7 +230,7 @@ AutocompleteMatch ZeroSuggestProvider::NavigationToMatch( |
} |
void ZeroSuggestProvider::Run(const GURL& suggest_url) { |
- have_pending_request_ = false; |
+ suggest_results_pending_ = 0; |
const int kFetcherID = 1; |
fetcher_.reset( |
net::URLFetcher::Create(kFetcherID, |
@@ -380,19 +255,18 @@ void ZeroSuggestProvider::Run(const GURL& suggest_url) { |
weak_ptr_factory_.GetWeakPtr()), false); |
} |
} |
- have_pending_request_ = true; |
+ suggest_results_pending_++; |
LogOmniboxZeroSuggestRequest(ZERO_SUGGEST_REQUEST_SENT); |
} |
-void ZeroSuggestProvider::ParseSuggestResults(const base::Value& root_val) { |
- SearchProvider::SuggestResults suggest_results; |
- FillResults(root_val, &verbatim_relevance_, |
- &suggest_results, &navigation_results_); |
- |
- query_matches_map_.clear(); |
- AddSuggestResultsToMap(suggest_results, |
- template_url_service_->GetDefaultSearchProvider(), |
- &query_matches_map_); |
+void ZeroSuggestProvider::RecordDeletionResult(bool success) { |
+ if (success) { |
+ content::RecordAction( |
+ base::UserMetricsAction("Omnibox.ServerZeroSuggestDelete.Success")); |
+ } else { |
+ content::RecordAction( |
+ base::UserMetricsAction("Omnibox.ServerZeroSuggestDelete.Failure")); |
+ } |
} |
void ZeroSuggestProvider::OnMostVisitedUrlsAvailable( |
@@ -409,8 +283,8 @@ void ZeroSuggestProvider::ConvertResultsToAutocompleteMatches() { |
if (default_provider == NULL || !default_provider->SupportsReplacement()) |
return; |
- const int num_query_results = query_matches_map_.size(); |
- const int num_nav_results = navigation_results_.size(); |
+ const int num_query_results = results_.suggest_results.size(); |
+ const int num_nav_results = results_.navigation_results.size(); |
const int num_results = num_query_results + num_nav_results; |
UMA_HISTOGRAM_COUNTS("ZeroSuggest.QueryResults", num_query_results); |
UMA_HISTOGRAM_COUNTS("ZeroSuggest.URLResults", num_nav_results); |
@@ -433,9 +307,14 @@ void ZeroSuggestProvider::ConvertResultsToAutocompleteMatches() { |
profile_->GetPrefs()->GetString(prefs::kAcceptLanguages)); |
for (size_t i = 0; i < most_visited_urls_.size(); i++) { |
const history::MostVisitedURL& url = most_visited_urls_[i]; |
- SearchProvider::NavigationResult nav( |
- *this, url.url, url.title, false, relevance, true, |
- current_query_string16, languages); |
+ NavigationResult nav(*this, |
+ url.url, |
+ url.title, |
+ false, |
+ relevance, |
+ true, |
+ current_query_string16, |
+ languages); |
matches_.push_back(NavigationToMatch(nav)); |
--relevance; |
} |
@@ -449,12 +328,20 @@ void ZeroSuggestProvider::ConvertResultsToAutocompleteMatches() { |
// current typing in the omnibox. |
matches_.push_back(current_url_match_); |
- for (SearchProvider::MatchMap::const_iterator it(query_matches_map_.begin()); |
- it != query_matches_map_.end(); ++it) |
+ MatchMap query_matches_map; |
+ AddSuggestResultsToMap(results_.suggest_results, |
+ template_url_service_->GetDefaultSearchProvider(), |
+ &query_matches_map); |
+ |
+ for (MatchMap::const_iterator it(query_matches_map.begin()); |
+ it != query_matches_map.end(); |
+ ++it) |
matches_.push_back(it->second); |
- for (SearchProvider::NavigationResults::const_iterator it( |
- navigation_results_.begin()); it != navigation_results_.end(); ++it) |
+ for (NavigationResults::const_iterator it( |
+ results_.navigation_results.begin()); |
+ it != results_.navigation_results.end(); |
+ ++it) |
matches_.push_back(NavigationToMatch(*it)); |
} |
@@ -472,7 +359,7 @@ AutocompleteMatch ZeroSuggestProvider::MatchForCurrentURL() { |
// The placeholder suggestion for the current URL has high relevance so |
// that it is in the first suggestion slot and inline autocompleted. It |
// gets dropped as soon as the user types something. |
- match.relevance = verbatim_relevance_; |
+ match.relevance = results_.verbatim_relevance; |
return match; |
} |