OLD | NEW |
---|---|
1 // Copyright (c) 2016 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2016 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 "components/omnibox/browser/physical_web_provider.h" | |
6 | |
5 #include "base/memory/ptr_util.h" | 7 #include "base/memory/ptr_util.h" |
6 #include "base/metrics/histogram_macros.h" | 8 #include "base/metrics/histogram_macros.h" |
9 #include "base/strings/string_util.h" | |
7 #include "base/strings/utf_string_conversions.h" | 10 #include "base/strings/utf_string_conversions.h" |
8 #include "base/values.h" | 11 #include "base/values.h" |
12 #include "components/bookmarks/browser/titled_url_index.h" | |
13 #include "components/bookmarks/browser/titled_url_node_sorter.h" | |
9 #include "components/omnibox/browser/autocomplete_provider_client.h" | 14 #include "components/omnibox/browser/autocomplete_provider_client.h" |
10 #include "components/omnibox/browser/autocomplete_provider_listener.h" | 15 #include "components/omnibox/browser/autocomplete_provider_listener.h" |
11 #include "components/omnibox/browser/history_url_provider.h" | 16 #include "components/omnibox/browser/history_url_provider.h" |
12 #include "components/omnibox/browser/physical_web_provider.h" | 17 #include "components/omnibox/browser/omnibox_field_trial.h" |
18 #include "components/omnibox/browser/physical_web_node.h" | |
19 #include "components/omnibox/browser/titled_url_match_utils.h" | |
20 #include "components/omnibox/browser/url_prefix.h" | |
13 #include "components/omnibox/browser/verbatim_match.h" | 21 #include "components/omnibox/browser/verbatim_match.h" |
14 #include "components/physical_web/data_source/physical_web_data_source.h" | 22 #include "components/physical_web/data_source/physical_web_data_source.h" |
15 #include "components/url_formatter/url_formatter.h" | 23 #include "components/url_formatter/url_formatter.h" |
16 #include "grit/components_strings.h" | 24 #include "grit/components_strings.h" |
17 #include "ui/base/l10n/l10n_util.h" | 25 #include "ui/base/l10n/l10n_util.h" |
18 #include "ui/gfx/text_elider.h" | 26 #include "ui/gfx/text_elider.h" |
19 #include "url/gurl.h" | 27 #include "url/gurl.h" |
20 | 28 |
21 namespace { | 29 namespace { |
22 | 30 |
23 // Relevance score of the first Physical Web URL autocomplete match. This score | |
24 // is intended to be between ClipboardURLProvider and ZeroSuggestProvider. | |
25 // Subsequent matches should decrease in relevance to preserve the ordering | |
26 // in the metadata list. | |
27 static const int kPhysicalWebUrlBaseRelevance = 700; | |
28 | |
29 // The maximum length of the page title's part of the overflow item's | 31 // The maximum length of the page title's part of the overflow item's |
30 // description. Longer titles will be truncated to this length. In a normal | 32 // description. Longer titles will be truncated to this length. In a normal |
31 // Physical Web match item (non-overflow item) we allow the omnibox display to | 33 // Physical Web match item (non-overflow item) we allow the omnibox display to |
32 // truncate the title instead. | 34 // truncate the title instead. |
33 static const size_t kMaxTitleLengthInOverflow = 15; | 35 static const size_t kMaxTitleLengthInOverflow = 15; |
36 | |
37 // The maximum number of Physical Web URLs to retrieve from the index. | |
38 static const size_t kPhysicalWebIndexMaxMatches = 50; | |
34 } | 39 } |
mattreynolds
2017/01/06 18:50:42
git cl format ate the newline I added here, so I t
Mark P
2017/01/06 19:55:03
Acknowledged.
| |
35 | 40 |
36 // static | 41 // static |
37 const size_t PhysicalWebProvider::kPhysicalWebMaxMatches = 1; | 42 const size_t PhysicalWebProvider::kPhysicalWebMaxMatches = 1; |
38 | 43 |
39 // static | 44 // static |
40 PhysicalWebProvider* PhysicalWebProvider::Create( | 45 PhysicalWebProvider* PhysicalWebProvider::Create( |
41 AutocompleteProviderClient* client, | 46 AutocompleteProviderClient* client, |
42 HistoryURLProvider* history_url_provider) { | 47 HistoryURLProvider* history_url_provider) { |
43 return new PhysicalWebProvider(client, history_url_provider); | 48 return new PhysicalWebProvider(client, history_url_provider); |
44 } | 49 } |
45 | 50 |
46 void PhysicalWebProvider::Start(const AutocompleteInput& input, | 51 void PhysicalWebProvider::Start(const AutocompleteInput& input, |
47 bool minimal_changes) { | 52 bool minimal_changes) { |
48 DCHECK(kPhysicalWebMaxMatches < kMaxMatches); | 53 DCHECK(kPhysicalWebMaxMatches < kMaxMatches); |
49 | 54 |
50 Stop(false, false); | 55 Stop(false, false); |
51 | 56 |
52 done_ = false; | 57 done_ = false; |
53 matches_.clear(); | 58 matches_.clear(); |
54 | 59 |
55 // Stop providing suggestions when the user enters text into the omnibox. | 60 had_physical_web_suggestions_ = false; |
56 if (!input.from_omnibox_focus()) { | 61 if (input.from_omnibox_focus()) |
57 done_ = true; | 62 had_physical_web_suggestions_at_focus_or_later_ = false; |
58 return; | |
59 } | |
60 | 63 |
61 // Don't provide suggestions in incognito mode. | 64 // Don't provide suggestions in incognito mode. |
62 if (client_->IsOffTheRecord()) { | 65 if (client_->IsOffTheRecord()) { |
63 done_ = true; | 66 done_ = true; |
64 nearby_url_count_ = 0; | 67 nearby_url_count_ = 0; |
65 return; | 68 return; |
66 } | 69 } |
67 | 70 |
68 physical_web::PhysicalWebDataSource* data_source = | 71 physical_web::PhysicalWebDataSource* data_source = |
69 client_->GetPhysicalWebDataSource(); | 72 client_->GetPhysicalWebDataSource(); |
70 if (!data_source) { | 73 if (!data_source) { |
71 done_ = true; | 74 done_ = true; |
72 nearby_url_count_ = 0; | 75 nearby_url_count_ = 0; |
73 return; | 76 return; |
74 } | 77 } |
75 | 78 |
76 ConstructMatches(data_source->GetMetadata().get()); | 79 if (input.from_omnibox_focus()) { |
80 ConstructZeroSuggestMatches(data_source->GetMetadata()); | |
77 | 81 |
78 // Physical Web matches should never be default. If the omnibox input is | 82 if (!matches_.empty()) { |
79 // non-empty and we have at least one Physical Web match, add the current URL | 83 had_physical_web_suggestions_ = true; |
80 // as the default so that hitting enter after focusing the omnibox causes the | 84 had_physical_web_suggestions_at_focus_or_later_ = true; |
81 // current page to reload. If the input field is empty, no default match is | 85 } |
82 // required. | 86 |
83 if (!matches_.empty() && !input.text().empty()) { | 87 if (!zero_suggest_enabled_) { |
84 matches_.push_back(VerbatimMatchForURL(client_, input, input.current_url(), | 88 matches_.clear(); |
85 history_url_provider_, -1)); | 89 } |
90 | |
91 // In zero-suggest, Physical Web matches should never be default. If the | |
92 // omnibox input is non-empty and we have at least one Physical Web match, | |
93 // add the current URL as the default so that hitting enter after focusing | |
94 // the omnibox causes the current page to reload. If the input field is | |
95 // empty, no default match is required. | |
96 if (!matches_.empty() && !input.text().empty()) { | |
97 matches_.push_back(VerbatimMatchForURL( | |
98 client_, input, input.current_url(), history_url_provider_, -1)); | |
99 } | |
100 } else { | |
101 ConstructQuerySuggestMatches(data_source->GetMetadata(), input); | |
102 | |
103 if (!matches_.empty()) { | |
104 had_physical_web_suggestions_ = true; | |
105 had_physical_web_suggestions_at_focus_or_later_ = true; | |
106 } | |
107 | |
108 if (!after_typing_enabled_) { | |
109 matches_.clear(); | |
110 } | |
86 } | 111 } |
87 | 112 |
88 done_ = true; | 113 done_ = true; |
89 } | 114 } |
90 | 115 |
91 void PhysicalWebProvider::Stop(bool clear_cached_results, | 116 void PhysicalWebProvider::Stop(bool clear_cached_results, |
92 bool due_to_user_inactivity) { | 117 bool due_to_user_inactivity) { |
93 done_ = true; | 118 done_ = true; |
94 } | 119 } |
95 | 120 |
96 void PhysicalWebProvider::AddProviderInfo(ProvidersInfo* provider_info) const { | 121 void PhysicalWebProvider::AddProviderInfo(ProvidersInfo* provider_info) const { |
97 // AddProviderInfo is called for each autocomplete provider to allow | 122 // Record whether the provider could have provided a Physical Web suggestion, |
98 // provider-specific diagnostic info to be added to the omnibox log entry. | 123 // even if the suggestion could not be displayed due to the current field |
99 // In this case we do not append any diagnostic info and are taking advantage | 124 // trial. |
100 // of the fact that this method is only called when the user has accepted an | 125 provider_info->push_back(metrics::OmniboxEventProto_ProviderInfo()); |
101 // autocomplete suggestion. | 126 metrics::OmniboxEventProto_ProviderInfo& new_entry = provider_info->back(); |
127 new_entry.set_provider(AsOmniboxEventProviderType()); | |
128 new_entry.set_provider_done(done_); | |
129 std::vector<uint32_t> field_trial_hashes; | |
130 OmniboxFieldTrial::GetActiveSuggestFieldTrialHashes(&field_trial_hashes); | |
131 for (size_t i = 0; i < field_trial_hashes.size(); ++i) { | |
132 if (had_physical_web_suggestions_) | |
133 new_entry.mutable_field_trial_triggered()->Add(field_trial_hashes[i]); | |
134 if (had_physical_web_suggestions_at_focus_or_later_) { | |
135 new_entry.mutable_field_trial_triggered_in_session()->Add( | |
136 field_trial_hashes[i]); | |
137 } | |
138 } | |
102 | 139 |
103 // When the user accepts an autocomplete suggestion, record the number of | 140 // When the user accepts an autocomplete suggestion, record the number of |
104 // nearby Physical Web URLs at the time the provider last constructed matches. | 141 // nearby Physical Web URLs at the time the provider last constructed matches. |
105 UMA_HISTOGRAM_EXACT_LINEAR("Omnibox.SuggestionUsed.NearbyURLCount", | 142 UMA_HISTOGRAM_EXACT_LINEAR("Omnibox.SuggestionUsed.NearbyURLCount", |
106 nearby_url_count_, 50); | 143 nearby_url_count_, 50); |
107 } | 144 } |
108 | 145 |
109 PhysicalWebProvider::PhysicalWebProvider( | 146 PhysicalWebProvider::PhysicalWebProvider( |
110 AutocompleteProviderClient* client, | 147 AutocompleteProviderClient* client, |
111 HistoryURLProvider* history_url_provider) | 148 HistoryURLProvider* history_url_provider) |
112 : AutocompleteProvider(AutocompleteProvider::TYPE_PHYSICAL_WEB), | 149 : AutocompleteProvider(AutocompleteProvider::TYPE_PHYSICAL_WEB), |
113 client_(client), | 150 client_(client), |
114 history_url_provider_(history_url_provider) {} | 151 history_url_provider_(history_url_provider), |
152 zero_suggest_enabled_( | |
153 OmniboxFieldTrial::InPhysicalWebZeroSuggestFieldTrial()), | |
154 after_typing_enabled_( | |
155 OmniboxFieldTrial::InPhysicalWebAfterTypingFieldTrial()), | |
156 zero_suggest_base_relevance_( | |
157 OmniboxFieldTrial::GetPhysicalWebZeroSuggestBaseRelevance()), | |
158 after_typing_base_relevance_( | |
159 OmniboxFieldTrial::GetPhysicalWebAfterTypingBaseRelevance()) {} | |
115 | 160 |
116 PhysicalWebProvider::~PhysicalWebProvider() { | 161 PhysicalWebProvider::~PhysicalWebProvider() { |
117 } | 162 } |
118 | 163 |
119 void PhysicalWebProvider::ConstructMatches(base::ListValue* metadata_list) { | 164 void PhysicalWebProvider::ConstructZeroSuggestMatches( |
165 std::unique_ptr<base::ListValue> metadata_list) { | |
120 nearby_url_count_ = metadata_list->GetSize(); | 166 nearby_url_count_ = metadata_list->GetSize(); |
121 size_t used_slots = 0; | 167 size_t used_slots = 0; |
122 | 168 |
123 for (size_t i = 0; i < nearby_url_count_; ++i) { | 169 for (size_t i = 0; i < nearby_url_count_; ++i) { |
124 base::DictionaryValue* metadata_item = NULL; | 170 base::DictionaryValue* metadata_item = NULL; |
125 if (!metadata_list->GetDictionary(i, &metadata_item)) { | 171 if (!metadata_list->GetDictionary(i, &metadata_item)) { |
126 continue; | 172 continue; |
127 } | 173 } |
128 | 174 |
129 std::string url_string; | 175 std::string url_string; |
130 std::string title_string; | 176 std::string title_string; |
131 if (!metadata_item->GetString(physical_web::kResolvedUrlKey, &url_string) || | 177 if (!metadata_item->GetString(physical_web::kResolvedUrlKey, &url_string) || |
132 !metadata_item->GetString(physical_web::kTitleKey, &title_string)) { | 178 !metadata_item->GetString(physical_web::kTitleKey, &title_string)) { |
133 continue; | 179 continue; |
134 } | 180 } |
135 base::string16 title = | 181 base::string16 title = |
136 AutocompleteMatch::SanitizeString(base::UTF8ToUTF16(title_string)); | 182 AutocompleteMatch::SanitizeString(base::UTF8ToUTF16(title_string)); |
137 | 183 |
138 // Add match items with decreasing relevance to preserve the ordering in | 184 // Add match items with decreasing relevance to preserve the ordering in |
139 // the metadata list. | 185 // the metadata list. |
140 int relevance = kPhysicalWebUrlBaseRelevance - used_slots; | 186 int relevance = zero_suggest_base_relevance_ - used_slots; |
141 | 187 |
142 // Append an overflow item if creating a match for each metadata item would | 188 // Append an overflow item if creating a match for each metadata item would |
143 // exceed the match limit. | 189 // exceed the match limit. |
144 const size_t remaining_slots = kPhysicalWebMaxMatches - used_slots; | 190 const size_t remaining_slots = kPhysicalWebMaxMatches - used_slots; |
145 const size_t remaining_metadata = nearby_url_count_ - i; | 191 const size_t remaining_metadata = nearby_url_count_ - i; |
146 if ((remaining_slots == 1) && (remaining_metadata > remaining_slots)) { | 192 if ((remaining_slots == 1) && (remaining_metadata > remaining_slots)) { |
147 AppendOverflowItem(remaining_metadata, relevance, title); | 193 AppendOverflowItem(remaining_metadata, relevance, title); |
148 break; | 194 break; |
149 } | 195 } |
150 | 196 |
(...skipping 20 matching lines...) Expand all Loading... | |
171 ACMatchClassification(0, ACMatchClassification::NONE)); | 217 ACMatchClassification(0, ACMatchClassification::NONE)); |
172 | 218 |
173 matches_.push_back(match); | 219 matches_.push_back(match); |
174 ++used_slots; | 220 ++used_slots; |
175 } | 221 } |
176 | 222 |
177 UMA_HISTOGRAM_EXACT_LINEAR( | 223 UMA_HISTOGRAM_EXACT_LINEAR( |
178 "Omnibox.PhysicalWebProviderMatches", matches_.size(), kMaxMatches); | 224 "Omnibox.PhysicalWebProviderMatches", matches_.size(), kMaxMatches); |
179 } | 225 } |
180 | 226 |
227 void PhysicalWebProvider::ConstructQuerySuggestMatches( | |
228 std::unique_ptr<base::ListValue> metadata_list, | |
229 const AutocompleteInput& input) { | |
230 // Passing nullptr for the TitledUrlNodeSorter will cause the returned match | |
231 // list to be unsorted. | |
232 bookmarks::TitledUrlIndex index(nullptr); | |
233 std::vector<std::unique_ptr<PhysicalWebNode>> nodes; | |
234 const size_t metadata_count = metadata_list->GetSize(); | |
235 for (size_t i = 0; i < metadata_count; ++i) { | |
236 base::DictionaryValue* metadata_item = NULL; | |
237 if (metadata_list->GetDictionary(i, &metadata_item)) { | |
238 nodes.push_back(base::MakeUnique<PhysicalWebNode>(*metadata_item)); | |
239 index.Add(nodes.back().get()); | |
240 } | |
241 } | |
242 | |
243 std::vector<bookmarks::TitledUrlMatch> titled_url_matches; | |
244 index.GetResultsMatching(input.text(), kPhysicalWebIndexMaxMatches, | |
245 query_parser::MatchingAlgorithm::DEFAULT, | |
246 &titled_url_matches); | |
247 | |
248 size_t used_slots = 0; | |
249 const base::string16 fixed_up_input(FixupUserInput(input).second); | |
250 for (auto titled_url_match : titled_url_matches) { | |
251 const int relevance = after_typing_base_relevance_ - used_slots; | |
252 matches_.push_back(bookmarks::TitledUrlMatchToAutocompleteMatch( | |
253 titled_url_match, AutocompleteMatchType::PHYSICAL_WEB, relevance, this, | |
254 client_->GetSchemeClassifier(), input, fixed_up_input)); | |
255 ++used_slots; | |
256 if (matches_.size() >= kPhysicalWebMaxMatches) { | |
257 break; | |
258 } | |
259 } | |
260 } | |
261 | |
181 void PhysicalWebProvider::AppendOverflowItem(int additional_url_count, | 262 void PhysicalWebProvider::AppendOverflowItem(int additional_url_count, |
182 int relevance, | 263 int relevance, |
183 const base::string16& title) { | 264 const base::string16& title) { |
184 std::string url_string = "chrome://physical-web"; | 265 std::string url_string = "chrome://physical-web"; |
185 GURL url(url_string); | 266 GURL url(url_string); |
186 | 267 |
187 AutocompleteMatch match(this, relevance, false, | 268 AutocompleteMatch match(this, relevance, false, |
188 AutocompleteMatchType::PHYSICAL_WEB_OVERFLOW); | 269 AutocompleteMatchType::PHYSICAL_WEB_OVERFLOW); |
189 match.destination_url = url; | 270 match.destination_url = url; |
190 | 271 |
(...skipping 14 matching lines...) Expand all Loading... | |
205 AutocompleteInput::FormattedStringWithEquivalentMeaning( | 286 AutocompleteInput::FormattedStringWithEquivalentMeaning( |
206 url, match.contents, client_->GetSchemeClassifier()); | 287 url, match.contents, client_->GetSchemeClassifier()); |
207 | 288 |
208 match.description = | 289 match.description = |
209 l10n_util::GetStringUTF16(IDS_PHYSICAL_WEB_OVERFLOW_DESCRIPTION); | 290 l10n_util::GetStringUTF16(IDS_PHYSICAL_WEB_OVERFLOW_DESCRIPTION); |
210 match.description_class.push_back( | 291 match.description_class.push_back( |
211 ACMatchClassification(0, ACMatchClassification::NONE)); | 292 ACMatchClassification(0, ACMatchClassification::NONE)); |
212 | 293 |
213 matches_.push_back(match); | 294 matches_.push_back(match); |
214 } | 295 } |
OLD | NEW |