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