autofill_external_delegate.cc revision 424c4d7b64af9d0d8fd9624f381f469654d5e3d2
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_key_press_event_callback_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::RenderWidgetHost::KeyPressEventCallback* callback) {
166  if (callback && !registered_key_press_event_callback_with_) {
167    registered_key_press_event_callback_with_ =
168        web_contents_->GetRenderViewHost();
169    registered_key_press_event_callback_with_->AddKeyPressEventCallback(
170        *callback);
171  }
172
173  autofill_manager_->OnDidShowAutofillSuggestions(
174      has_autofill_suggestion_ && !has_shown_autofill_popup_for_current_edit_);
175  has_shown_autofill_popup_for_current_edit_ |= has_autofill_suggestion_;
176}
177
178void AutofillExternalDelegate::OnPopupHidden(
179    content::RenderWidgetHost::KeyPressEventCallback* callback) {
180  if (callback && (!web_contents_->IsBeingDestroyed()) &&
181      (registered_key_press_event_callback_with_ ==
182          web_contents_->GetRenderViewHost())) {
183    web_contents_->GetRenderViewHost()->RemoveKeyPressEventCallback(*callback);
184  }
185
186  registered_key_press_event_callback_with_ = NULL;
187}
188
189bool AutofillExternalDelegate::ShouldRepostEvent(const ui::MouseEvent& event) {
190  NOTREACHED();
191  return true;
192}
193
194void AutofillExternalDelegate::DidSelectSuggestion(int identifier) {
195  ClearPreviewedForm();
196
197  // Only preview the data if it is a profile.
198  if (identifier > 0)
199    FillAutofillFormData(identifier, true);
200}
201
202void AutofillExternalDelegate::DidAcceptSuggestion(const base::string16& value,
203                                                   int identifier) {
204  RenderViewHost* host = web_contents_->GetRenderViewHost();
205
206  if (identifier == WebAutofillClient::MenuItemIDAutofillOptions) {
207    // User selected 'Autofill Options'.
208    autofill_manager_->OnShowAutofillDialog();
209  } else if (identifier == WebAutofillClient::MenuItemIDClearForm) {
210    // User selected 'Clear form'.
211    autofill_driver_->RendererShouldClearFilledForm();
212  } else if (identifier == WebAutofillClient::MenuItemIDPasswordEntry) {
213    bool success = password_autofill_manager_.DidAcceptAutofillSuggestion(
214        autofill_query_field_, value);
215    DCHECK(success);
216  } else if (identifier == WebAutofillClient::MenuItemIDDataListEntry) {
217    host->Send(new AutofillMsg_AcceptDataListSuggestion(host->GetRoutingID(),
218                                                        value));
219  } else if (identifier == WebAutofillClient::MenuItemIDAutocompleteEntry) {
220    // User selected an Autocomplete, so we fill directly.
221    host->Send(new AutofillMsg_SetNodeText(host->GetRoutingID(), value));
222  } else {
223    FillAutofillFormData(identifier, false);
224  }
225
226  autofill_manager_->delegate()->HideAutofillPopup();
227}
228
229void AutofillExternalDelegate::RemoveSuggestion(const base::string16& value,
230                                                int identifier) {
231  if (identifier > 0) {
232    autofill_manager_->RemoveAutofillProfileOrCreditCard(identifier);
233  } else {
234    autofill_manager_->RemoveAutocompleteEntry(autofill_query_field_.name,
235                                               value);
236  }
237}
238
239void AutofillExternalDelegate::DidEndTextFieldEditing() {
240  autofill_manager_->delegate()->HideAutofillPopup();
241
242  has_shown_autofill_popup_for_current_edit_ = false;
243}
244
245void AutofillExternalDelegate::ClearPreviewedForm() {
246  autofill_driver_->RendererShouldClearPreviewedForm();
247}
248
249void AutofillExternalDelegate::Reset() {
250  autofill_manager_->delegate()->HideAutofillPopup();
251
252  password_autofill_manager_.Reset();
253}
254
255void AutofillExternalDelegate::AddPasswordFormMapping(
256      const FormFieldData& form,
257      const PasswordFormFillData& fill_data) {
258  password_autofill_manager_.AddPasswordFormMapping(form, fill_data);
259}
260
261base::WeakPtr<AutofillExternalDelegate> AutofillExternalDelegate::GetWeakPtr() {
262  return weak_ptr_factory_.GetWeakPtr();
263}
264
265void AutofillExternalDelegate::FillAutofillFormData(int unique_id,
266                                                    bool is_preview) {
267  // If the selected element is a warning we don't want to do anything.
268  if (unique_id == WebAutofillClient::MenuItemIDWarningMessage)
269    return;
270
271  AutofillDriver::RendererFormDataAction renderer_action = is_preview ?
272      AutofillDriver::FORM_DATA_ACTION_PREVIEW :
273      AutofillDriver::FORM_DATA_ACTION_FILL;
274
275  DCHECK(autofill_driver_->RendererIsAvailable());
276  autofill_driver_->SetRendererActionOnFormDataReception(renderer_action);
277  // Fill the values for the whole form.
278  autofill_manager_->OnFillAutofillFormData(autofill_query_id_,
279                                            autofill_query_form_,
280                                            autofill_query_field_,
281                                            unique_id);
282}
283
284void AutofillExternalDelegate::ApplyAutofillWarnings(
285    std::vector<base::string16>* autofill_values,
286    std::vector<base::string16>* autofill_labels,
287    std::vector<base::string16>* autofill_icons,
288    std::vector<int>* autofill_unique_ids) {
289  if (!autofill_query_field_.should_autocomplete) {
290    // Autofill is disabled.  If there were some profile or credit card
291    // suggestions to show, show a warning instead.  Otherwise, clear out the
292    // list of suggestions.
293    if (!autofill_unique_ids->empty() && (*autofill_unique_ids)[0] > 0) {
294      // If autofill is disabled and we had suggestions, show a warning instead.
295      autofill_values->assign(
296          1, l10n_util::GetStringUTF16(IDS_AUTOFILL_WARNING_FORM_DISABLED));
297      autofill_labels->assign(1, base::string16());
298      autofill_icons->assign(1, base::string16());
299      autofill_unique_ids->assign(1,
300                                  WebAutofillClient::MenuItemIDWarningMessage);
301    } else {
302      autofill_values->clear();
303      autofill_labels->clear();
304      autofill_icons->clear();
305      autofill_unique_ids->clear();
306    }
307  } else if (autofill_unique_ids->size() > 1 &&
308             (*autofill_unique_ids)[0] ==
309                 WebAutofillClient::MenuItemIDWarningMessage) {
310    // If we received a warning instead of suggestions from autofill but regular
311    // suggestions from autocomplete, don't show the autofill warning.
312    autofill_values->erase(autofill_values->begin());
313    autofill_labels->erase(autofill_labels->begin());
314    autofill_icons->erase(autofill_icons->begin());
315    autofill_unique_ids->erase(autofill_unique_ids->begin());
316  }
317
318  // If we were about to show a warning and we shouldn't, don't.
319  if (!autofill_unique_ids->empty() &&
320      (*autofill_unique_ids)[0] ==
321          WebAutofillClient::MenuItemIDWarningMessage &&
322      !display_warning_if_disabled_) {
323    autofill_values->clear();
324    autofill_labels->clear();
325    autofill_icons->clear();
326    autofill_unique_ids->clear();
327  }
328}
329
330void AutofillExternalDelegate::ApplyAutofillOptions(
331    std::vector<base::string16>* autofill_values,
332    std::vector<base::string16>* autofill_labels,
333    std::vector<base::string16>* autofill_icons,
334    std::vector<int>* autofill_unique_ids) {
335  // The form has been auto-filled, so give the user the chance to clear the
336  // form.  Append the 'Clear form' menu item.
337  if (autofill_query_field_.is_autofilled) {
338    autofill_values->push_back(
339        l10n_util::GetStringUTF16(IDS_AUTOFILL_CLEAR_FORM_MENU_ITEM));
340    autofill_labels->push_back(base::string16());
341    autofill_icons->push_back(base::string16());
342    autofill_unique_ids->push_back(WebAutofillClient::MenuItemIDClearForm);
343  }
344
345  // Append the 'Chrome Autofill options' menu item;
346  autofill_values->push_back(
347      l10n_util::GetStringUTF16(IDS_AUTOFILL_OPTIONS_POPUP));
348  autofill_labels->push_back(base::string16());
349  autofill_icons->push_back(base::string16());
350  autofill_unique_ids->push_back(WebAutofillClient::MenuItemIDAutofillOptions);
351}
352
353void AutofillExternalDelegate::InsertDataListValues(
354    std::vector<base::string16>* autofill_values,
355    std::vector<base::string16>* autofill_labels,
356    std::vector<base::string16>* autofill_icons,
357    std::vector<int>* autofill_unique_ids) {
358  if (data_list_values_.empty())
359    return;
360
361  // Insert the separator between the datalist and Autofill values (if there
362  // are any).
363  if (!autofill_values->empty()) {
364    autofill_values->insert(autofill_values->begin(), base::string16());
365    autofill_labels->insert(autofill_labels->begin(), base::string16());
366    autofill_icons->insert(autofill_icons->begin(), base::string16());
367    autofill_unique_ids->insert(autofill_unique_ids->begin(),
368                                WebAutofillClient::MenuItemIDSeparator);
369  }
370
371  // Insert the datalist elements.
372  autofill_values->insert(autofill_values->begin(),
373                          data_list_values_.begin(),
374                          data_list_values_.end());
375  autofill_labels->insert(autofill_labels->begin(),
376                          data_list_labels_.begin(),
377                          data_list_labels_.end());
378
379  // Set the values that all datalist elements share.
380  autofill_icons->insert(autofill_icons->begin(),
381                         data_list_values_.size(),
382                         base::string16());
383  autofill_unique_ids->insert(autofill_unique_ids->begin(),
384                              data_list_values_.size(),
385                              WebAutofillClient::MenuItemIDDataListEntry);
386}
387
388}  // namespace autofill
389