OLD | NEW |
| (Empty) |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include "components/autofill/browser/autofill_external_delegate.h" | |
6 | |
7 #include "base/strings/utf_string_conversions.h" | |
8 #include "components/autofill/browser/autocomplete_history_manager.h" | |
9 #include "components/autofill/browser/autofill_manager.h" | |
10 #include "components/autofill/core/common/autofill_messages.h" | |
11 #include "content/public/browser/navigation_controller.h" | |
12 #include "content/public/browser/notification_service.h" | |
13 #include "content/public/browser/notification_source.h" | |
14 #include "content/public/browser/notification_types.h" | |
15 #include "content/public/browser/render_view_host.h" | |
16 #include "content/public/browser/web_contents.h" | |
17 #include "grit/component_strings.h" | |
18 #include "third_party/WebKit/Source/WebKit/chromium/public/WebAutofillClient.h" | |
19 #include "ui/base/l10n/l10n_util.h" | |
20 | |
21 #if defined(OS_ANDROID) | |
22 #include "content/public/browser/android/content_view_core.h" | |
23 #endif | |
24 | |
25 using content::RenderViewHost; | |
26 using WebKit::WebAutofillClient; | |
27 | |
28 namespace autofill { | |
29 | |
30 AutofillExternalDelegate::AutofillExternalDelegate( | |
31 content::WebContents* web_contents, | |
32 AutofillManager* autofill_manager) | |
33 : web_contents_(web_contents), | |
34 autofill_manager_(autofill_manager), | |
35 password_autofill_manager_(web_contents), | |
36 autofill_query_id_(0), | |
37 display_warning_if_disabled_(false), | |
38 has_autofill_suggestion_(false), | |
39 has_shown_autofill_popup_for_current_edit_(false), | |
40 registered_keyboard_listener_with_(NULL), | |
41 weak_ptr_factory_(this) { | |
42 DCHECK(autofill_manager); | |
43 | |
44 registrar_.Add(this, | |
45 content::NOTIFICATION_WEB_CONTENTS_VISIBILITY_CHANGED, | |
46 content::Source<content::WebContents>(web_contents)); | |
47 registrar_.Add( | |
48 this, | |
49 content::NOTIFICATION_NAV_ENTRY_COMMITTED, | |
50 content::Source<content::NavigationController>( | |
51 &(web_contents->GetController()))); | |
52 } | |
53 | |
54 AutofillExternalDelegate::~AutofillExternalDelegate() {} | |
55 | |
56 void AutofillExternalDelegate::OnQuery(int query_id, | |
57 const FormData& form, | |
58 const FormFieldData& field, | |
59 const gfx::RectF& element_bounds, | |
60 bool display_warning_if_disabled) { | |
61 autofill_query_form_ = form; | |
62 autofill_query_field_ = field; | |
63 display_warning_if_disabled_ = display_warning_if_disabled; | |
64 autofill_query_id_ = query_id; | |
65 element_bounds_ = element_bounds; | |
66 } | |
67 | |
68 void AutofillExternalDelegate::OnSuggestionsReturned( | |
69 int query_id, | |
70 const std::vector<base::string16>& autofill_values, | |
71 const std::vector<base::string16>& autofill_labels, | |
72 const std::vector<base::string16>& autofill_icons, | |
73 const std::vector<int>& autofill_unique_ids) { | |
74 if (query_id != autofill_query_id_) | |
75 return; | |
76 | |
77 std::vector<base::string16> values(autofill_values); | |
78 std::vector<base::string16> labels(autofill_labels); | |
79 std::vector<base::string16> icons(autofill_icons); | |
80 std::vector<int> ids(autofill_unique_ids); | |
81 | |
82 // Add or hide warnings as appropriate. | |
83 ApplyAutofillWarnings(&values, &labels, &icons, &ids); | |
84 | |
85 // Add a separator to go between the values and menu items. | |
86 values.push_back(base::string16()); | |
87 labels.push_back(base::string16()); | |
88 icons.push_back(base::string16()); | |
89 ids.push_back(WebAutofillClient::MenuItemIDSeparator); | |
90 | |
91 // Only include "Autofill Options" special menu item if we have Autofill | |
92 // suggestions. | |
93 has_autofill_suggestion_ = false; | |
94 for (size_t i = 0; i < ids.size(); ++i) { | |
95 if (ids[i] > 0) { | |
96 has_autofill_suggestion_ = true; | |
97 break; | |
98 } | |
99 } | |
100 | |
101 if (has_autofill_suggestion_) | |
102 ApplyAutofillOptions(&values, &labels, &icons, &ids); | |
103 | |
104 // Remove the separator if it is the last element. | |
105 DCHECK_GT(ids.size(), 0U); | |
106 if (ids.back() == WebAutofillClient::MenuItemIDSeparator) { | |
107 values.pop_back(); | |
108 labels.pop_back(); | |
109 icons.pop_back(); | |
110 ids.pop_back(); | |
111 } | |
112 | |
113 InsertDataListValues(&values, &labels, &icons, &ids); | |
114 | |
115 if (values.empty()) { | |
116 // No suggestions, any popup currently showing is obsolete. | |
117 autofill_manager_->delegate()->HideAutofillPopup(); | |
118 return; | |
119 } | |
120 | |
121 // Send to display. | |
122 if (autofill_query_field_.is_focusable) { | |
123 autofill_manager_->delegate()->ShowAutofillPopup( | |
124 element_bounds_, | |
125 autofill_query_field_.text_direction, | |
126 values, | |
127 labels, | |
128 icons, | |
129 ids, | |
130 GetWeakPtr()); | |
131 } | |
132 } | |
133 | |
134 void AutofillExternalDelegate::OnShowPasswordSuggestions( | |
135 const std::vector<base::string16>& suggestions, | |
136 const FormFieldData& field, | |
137 const gfx::RectF& element_bounds) { | |
138 autofill_query_field_ = field; | |
139 element_bounds_ = element_bounds; | |
140 | |
141 if (suggestions.empty()) { | |
142 autofill_manager_->delegate()->HideAutofillPopup(); | |
143 return; | |
144 } | |
145 | |
146 std::vector<base::string16> empty(suggestions.size()); | |
147 std::vector<int> password_ids(suggestions.size(), | |
148 WebAutofillClient::MenuItemIDPasswordEntry); | |
149 autofill_manager_->delegate()->ShowAutofillPopup( | |
150 element_bounds_, | |
151 autofill_query_field_.text_direction, | |
152 suggestions, | |
153 empty, | |
154 empty, | |
155 password_ids, | |
156 GetWeakPtr()); | |
157 } | |
158 | |
159 void AutofillExternalDelegate::SetCurrentDataListValues( | |
160 const std::vector<base::string16>& data_list_values, | |
161 const std::vector<base::string16>& data_list_labels, | |
162 const std::vector<base::string16>& data_list_icons, | |
163 const std::vector<int>& data_list_unique_ids) { | |
164 data_list_values_ = data_list_values; | |
165 data_list_labels_ = data_list_labels; | |
166 data_list_icons_ = data_list_icons; | |
167 data_list_unique_ids_ = data_list_unique_ids; | |
168 } | |
169 | |
170 void AutofillExternalDelegate::OnPopupShown( | |
171 content::KeyboardListener* listener) { | |
172 if (!registered_keyboard_listener_with_) { | |
173 registered_keyboard_listener_with_ = web_contents_->GetRenderViewHost(); | |
174 registered_keyboard_listener_with_->AddKeyboardListener(listener); | |
175 } | |
176 | |
177 autofill_manager_->OnDidShowAutofillSuggestions( | |
178 has_autofill_suggestion_ && !has_shown_autofill_popup_for_current_edit_); | |
179 has_shown_autofill_popup_for_current_edit_ |= has_autofill_suggestion_; | |
180 } | |
181 | |
182 void AutofillExternalDelegate::OnPopupHidden( | |
183 content::KeyboardListener* listener) { | |
184 if (registered_keyboard_listener_with_ == web_contents_->GetRenderViewHost()) | |
185 web_contents_->GetRenderViewHost()->RemoveKeyboardListener(listener); | |
186 | |
187 registered_keyboard_listener_with_ = NULL; | |
188 } | |
189 | |
190 void AutofillExternalDelegate::DidSelectSuggestion(int identifier) { | |
191 ClearPreviewedForm(); | |
192 | |
193 // Only preview the data if it is a profile. | |
194 if (identifier > 0) | |
195 FillAutofillFormData(identifier, true); | |
196 } | |
197 | |
198 void AutofillExternalDelegate::DidAcceptSuggestion(const base::string16& value, | |
199 int identifier) { | |
200 RenderViewHost* host = web_contents_->GetRenderViewHost(); | |
201 | |
202 if (identifier == WebAutofillClient::MenuItemIDAutofillOptions) { | |
203 // User selected 'Autofill Options'. | |
204 autofill_manager_->OnShowAutofillDialog(); | |
205 } else if (identifier == WebAutofillClient::MenuItemIDClearForm) { | |
206 // User selected 'Clear form'. | |
207 host->Send(new AutofillMsg_ClearForm(host->GetRoutingID())); | |
208 } else if (identifier == WebAutofillClient::MenuItemIDPasswordEntry) { | |
209 bool success = password_autofill_manager_.DidAcceptAutofillSuggestion( | |
210 autofill_query_field_, value); | |
211 DCHECK(success); | |
212 } else if (identifier == WebAutofillClient::MenuItemIDDataListEntry) { | |
213 host->Send(new AutofillMsg_AcceptDataListSuggestion(host->GetRoutingID(), | |
214 value)); | |
215 } else if (identifier == WebAutofillClient::MenuItemIDAutocompleteEntry) { | |
216 // User selected an Autocomplete, so we fill directly. | |
217 host->Send(new AutofillMsg_SetNodeText(host->GetRoutingID(), value)); | |
218 } else { | |
219 FillAutofillFormData(identifier, false); | |
220 } | |
221 | |
222 autofill_manager_->delegate()->HideAutofillPopup(); | |
223 } | |
224 | |
225 void AutofillExternalDelegate::RemoveSuggestion(const base::string16& value, | |
226 int identifier) { | |
227 if (identifier > 0) { | |
228 autofill_manager_->RemoveAutofillProfileOrCreditCard(identifier); | |
229 } else { | |
230 autofill_manager_->RemoveAutocompleteEntry(autofill_query_field_.name, | |
231 value); | |
232 } | |
233 } | |
234 | |
235 void AutofillExternalDelegate::DidEndTextFieldEditing() { | |
236 autofill_manager_->delegate()->HideAutofillPopup(); | |
237 | |
238 has_shown_autofill_popup_for_current_edit_ = false; | |
239 } | |
240 | |
241 void AutofillExternalDelegate::ClearPreviewedForm() { | |
242 RenderViewHost* host = web_contents_->GetRenderViewHost(); | |
243 if (host) | |
244 host->Send(new AutofillMsg_ClearPreviewedForm(host->GetRoutingID())); | |
245 } | |
246 | |
247 void AutofillExternalDelegate::Reset() { | |
248 autofill_manager_->delegate()->HideAutofillPopup(); | |
249 | |
250 password_autofill_manager_.Reset(); | |
251 } | |
252 | |
253 void AutofillExternalDelegate::AddPasswordFormMapping( | |
254 const FormFieldData& form, | |
255 const PasswordFormFillData& fill_data) { | |
256 password_autofill_manager_.AddPasswordFormMapping(form, fill_data); | |
257 } | |
258 | |
259 base::WeakPtr<AutofillExternalDelegate> AutofillExternalDelegate::GetWeakPtr() { | |
260 return weak_ptr_factory_.GetWeakPtr(); | |
261 } | |
262 | |
263 void AutofillExternalDelegate::FillAutofillFormData(int unique_id, | |
264 bool is_preview) { | |
265 // If the selected element is a warning we don't want to do anything. | |
266 if (unique_id == WebAutofillClient::MenuItemIDWarningMessage) | |
267 return; | |
268 | |
269 RenderViewHost* host = web_contents_->GetRenderViewHost(); | |
270 | |
271 if (is_preview) { | |
272 host->Send(new AutofillMsg_SetAutofillActionPreview( | |
273 host->GetRoutingID())); | |
274 } else { | |
275 host->Send(new AutofillMsg_SetAutofillActionFill( | |
276 host->GetRoutingID())); | |
277 } | |
278 | |
279 // Fill the values for the whole form. | |
280 autofill_manager_->OnFillAutofillFormData(autofill_query_id_, | |
281 autofill_query_form_, | |
282 autofill_query_field_, | |
283 unique_id); | |
284 } | |
285 | |
286 void AutofillExternalDelegate::ApplyAutofillWarnings( | |
287 std::vector<base::string16>* autofill_values, | |
288 std::vector<base::string16>* autofill_labels, | |
289 std::vector<base::string16>* autofill_icons, | |
290 std::vector<int>* autofill_unique_ids) { | |
291 if (!autofill_query_field_.should_autocomplete) { | |
292 // If autofill is disabled and we had suggestions, show a warning instead. | |
293 autofill_values->assign( | |
294 1, l10n_util::GetStringUTF16(IDS_AUTOFILL_WARNING_FORM_DISABLED)); | |
295 autofill_labels->assign(1, base::string16()); | |
296 autofill_icons->assign(1, base::string16()); | |
297 autofill_unique_ids->assign(1, WebAutofillClient::MenuItemIDWarningMessage); | |
298 } else if (autofill_unique_ids->size() > 1 && | |
299 (*autofill_unique_ids)[0] == | |
300 WebAutofillClient::MenuItemIDWarningMessage) { | |
301 // If we received a warning instead of suggestions from autofill but regular | |
302 // suggestions from autocomplete, don't show the autofill warning. | |
303 autofill_values->erase(autofill_values->begin()); | |
304 autofill_labels->erase(autofill_labels->begin()); | |
305 autofill_icons->erase(autofill_icons->begin()); | |
306 autofill_unique_ids->erase(autofill_unique_ids->begin()); | |
307 } | |
308 | |
309 // If we were about to show a warning and we shouldn't, don't. | |
310 if (!autofill_unique_ids->empty() && | |
311 (*autofill_unique_ids)[0] == | |
312 WebAutofillClient::MenuItemIDWarningMessage && | |
313 !display_warning_if_disabled_) { | |
314 autofill_values->clear(); | |
315 autofill_labels->clear(); | |
316 autofill_icons->clear(); | |
317 autofill_unique_ids->clear(); | |
318 } | |
319 } | |
320 | |
321 void AutofillExternalDelegate::ApplyAutofillOptions( | |
322 std::vector<base::string16>* autofill_values, | |
323 std::vector<base::string16>* autofill_labels, | |
324 std::vector<base::string16>* autofill_icons, | |
325 std::vector<int>* autofill_unique_ids) { | |
326 // The form has been auto-filled, so give the user the chance to clear the | |
327 // form. Append the 'Clear form' menu item. | |
328 if (autofill_query_field_.is_autofilled) { | |
329 autofill_values->push_back( | |
330 l10n_util::GetStringUTF16(IDS_AUTOFILL_CLEAR_FORM_MENU_ITEM)); | |
331 autofill_labels->push_back(base::string16()); | |
332 autofill_icons->push_back(base::string16()); | |
333 autofill_unique_ids->push_back(WebAutofillClient::MenuItemIDClearForm); | |
334 } | |
335 | |
336 // Append the 'Chrome Autofill options' menu item; | |
337 autofill_values->push_back( | |
338 l10n_util::GetStringUTF16(IDS_AUTOFILL_OPTIONS_POPUP)); | |
339 autofill_labels->push_back(base::string16()); | |
340 autofill_icons->push_back(base::string16()); | |
341 autofill_unique_ids->push_back(WebAutofillClient::MenuItemIDAutofillOptions); | |
342 } | |
343 | |
344 void AutofillExternalDelegate::InsertDataListValues( | |
345 std::vector<base::string16>* autofill_values, | |
346 std::vector<base::string16>* autofill_labels, | |
347 std::vector<base::string16>* autofill_icons, | |
348 std::vector<int>* autofill_unique_ids) { | |
349 if (data_list_values_.empty()) | |
350 return; | |
351 | |
352 // Insert the separator between the datalist and Autofill values (if there | |
353 // are any). | |
354 if (!autofill_values->empty()) { | |
355 autofill_values->insert(autofill_values->begin(), base::string16()); | |
356 autofill_labels->insert(autofill_labels->begin(), base::string16()); | |
357 autofill_icons->insert(autofill_icons->begin(), base::string16()); | |
358 autofill_unique_ids->insert(autofill_unique_ids->begin(), | |
359 WebAutofillClient::MenuItemIDSeparator); | |
360 } | |
361 | |
362 // Insert the datalist elements. | |
363 autofill_values->insert(autofill_values->begin(), | |
364 data_list_values_.begin(), | |
365 data_list_values_.end()); | |
366 autofill_labels->insert(autofill_labels->begin(), | |
367 data_list_labels_.begin(), | |
368 data_list_labels_.end()); | |
369 autofill_icons->insert(autofill_icons->begin(), | |
370 data_list_icons_.begin(), | |
371 data_list_icons_.end()); | |
372 autofill_unique_ids->insert(autofill_unique_ids->begin(), | |
373 data_list_unique_ids_.begin(), | |
374 data_list_unique_ids_.end()); | |
375 } | |
376 | |
377 void AutofillExternalDelegate::Observe( | |
378 int type, | |
379 const content::NotificationSource& source, | |
380 const content::NotificationDetails& details) { | |
381 if (type == content::NOTIFICATION_WEB_CONTENTS_VISIBILITY_CHANGED) { | |
382 if (!*content::Details<bool>(details).ptr()) | |
383 autofill_manager_->delegate()->HideAutofillPopup(); | |
384 } else if (type == content::NOTIFICATION_NAV_ENTRY_COMMITTED) { | |
385 autofill_manager_->delegate()->HideAutofillPopup(); | |
386 } else { | |
387 NOTREACHED(); | |
388 } | |
389 } | |
390 | |
391 } // namespace autofill | |
OLD | NEW |