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