autofill_external_delegate.cc revision 558790d6acca3451cf3a6b497803a5f07d0bec58
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  // TODO(csharp): Remove once Autofill test flakiness is fixed.
52  LOG(INFO) << "AutofillExternalDelegate::OnQuery";
53
54  autofill_query_form_ = form;
55  autofill_query_field_ = field;
56  display_warning_if_disabled_ = display_warning_if_disabled;
57  autofill_query_id_ = query_id;
58  element_bounds_ = element_bounds;
59}
60
61void AutofillExternalDelegate::OnSuggestionsReturned(
62    int query_id,
63    const std::vector<base::string16>& autofill_values,
64    const std::vector<base::string16>& autofill_labels,
65    const std::vector<base::string16>& autofill_icons,
66    const std::vector<int>& autofill_unique_ids) {
67  // TODO(csharp): Remove once Autofill test flakiness is fixed.
68  LOG(INFO) << "AutofillExternalDelegate::OnSuggestionsReturned";
69
70  if (query_id != autofill_query_id_)
71    return;
72
73  std::vector<base::string16> values(autofill_values);
74  std::vector<base::string16> labels(autofill_labels);
75  std::vector<base::string16> icons(autofill_icons);
76  std::vector<int> ids(autofill_unique_ids);
77
78  // Add or hide warnings as appropriate.
79  ApplyAutofillWarnings(&values, &labels, &icons, &ids);
80
81  // Add a separator to go between the values and menu items.
82  values.push_back(base::string16());
83  labels.push_back(base::string16());
84  icons.push_back(base::string16());
85  ids.push_back(WebAutofillClient::MenuItemIDSeparator);
86
87  // Only include "Autofill Options" special menu item if we have Autofill
88  // suggestions.
89  has_autofill_suggestion_ = false;
90  for (size_t i = 0; i < ids.size(); ++i) {
91    if (ids[i] > 0) {
92      has_autofill_suggestion_ = true;
93      break;
94    }
95  }
96
97  if (has_autofill_suggestion_)
98    ApplyAutofillOptions(&values, &labels, &icons, &ids);
99
100  // Remove the separator if it is the last element.
101  DCHECK_GT(ids.size(), 0U);
102  if (ids.back() == WebAutofillClient::MenuItemIDSeparator) {
103    values.pop_back();
104    labels.pop_back();
105    icons.pop_back();
106    ids.pop_back();
107  }
108
109  // If anything else is added to modify the values after inserting the data
110  // list, AutofillPopupControllerImpl::UpdateDataListValues will need to be
111  // updated to match.
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
133void AutofillExternalDelegate::OnShowPasswordSuggestions(
134    const std::vector<base::string16>& suggestions,
135    const std::vector<base::string16>& realms,
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      realms,
154      empty,
155      password_ids,
156      GetWeakPtr());
157}
158
159void AutofillExternalDelegate::SetCurrentDataListValues(
160    const std::vector<base::string16>& data_list_values,
161    const std::vector<base::string16>& data_list_labels) {
162  data_list_values_ = data_list_values;
163  data_list_labels_ = data_list_labels;
164
165  autofill_manager_->delegate()->UpdateAutofillPopupDataListValues(
166      data_list_values,
167      data_list_labels);
168}
169
170void 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
182void AutofillExternalDelegate::OnPopupHidden(
183    content::KeyboardListener* listener) {
184  if ((!web_contents_->IsBeingDestroyed()) &&
185      (registered_keyboard_listener_with_ ==
186          web_contents_->GetRenderViewHost())) {
187    web_contents_->GetRenderViewHost()->RemoveKeyboardListener(listener);
188  }
189
190  registered_keyboard_listener_with_ = NULL;
191}
192
193void AutofillExternalDelegate::DidSelectSuggestion(int identifier) {
194  ClearPreviewedForm();
195
196  // Only preview the data if it is a profile.
197  if (identifier > 0)
198    FillAutofillFormData(identifier, true);
199}
200
201void AutofillExternalDelegate::DidAcceptSuggestion(const base::string16& value,
202                                                   int identifier) {
203  RenderViewHost* host = web_contents_->GetRenderViewHost();
204
205  if (identifier == WebAutofillClient::MenuItemIDAutofillOptions) {
206    // User selected 'Autofill Options'.
207    autofill_manager_->OnShowAutofillDialog();
208  } else if (identifier == WebAutofillClient::MenuItemIDClearForm) {
209    // User selected 'Clear form'.
210    autofill_driver_->RendererShouldClearFilledForm();
211  } else if (identifier == WebAutofillClient::MenuItemIDPasswordEntry) {
212    bool success = password_autofill_manager_.DidAcceptAutofillSuggestion(
213        autofill_query_field_, value);
214    DCHECK(success);
215  } else if (identifier == WebAutofillClient::MenuItemIDDataListEntry) {
216    host->Send(new AutofillMsg_AcceptDataListSuggestion(host->GetRoutingID(),
217                                                        value));
218  } else if (identifier == WebAutofillClient::MenuItemIDAutocompleteEntry) {
219    // User selected an Autocomplete, so we fill directly.
220    host->Send(new AutofillMsg_SetNodeText(host->GetRoutingID(), value));
221  } else {
222    FillAutofillFormData(identifier, false);
223  }
224
225  autofill_manager_->delegate()->HideAutofillPopup();
226}
227
228void AutofillExternalDelegate::RemoveSuggestion(const base::string16& value,
229                                                int identifier) {
230  if (identifier > 0) {
231    autofill_manager_->RemoveAutofillProfileOrCreditCard(identifier);
232  } else {
233    autofill_manager_->RemoveAutocompleteEntry(autofill_query_field_.name,
234                                               value);
235  }
236}
237
238void AutofillExternalDelegate::DidEndTextFieldEditing() {
239  autofill_manager_->delegate()->HideAutofillPopup();
240
241  has_shown_autofill_popup_for_current_edit_ = false;
242}
243
244void AutofillExternalDelegate::ClearPreviewedForm() {
245  autofill_driver_->RendererShouldClearPreviewedForm();
246}
247
248void AutofillExternalDelegate::Reset() {
249  autofill_manager_->delegate()->HideAutofillPopup();
250
251  password_autofill_manager_.Reset();
252}
253
254void AutofillExternalDelegate::AddPasswordFormMapping(
255      const FormFieldData& form,
256      const PasswordFormFillData& fill_data) {
257  password_autofill_manager_.AddPasswordFormMapping(form, fill_data);
258}
259
260base::WeakPtr<AutofillExternalDelegate> AutofillExternalDelegate::GetWeakPtr() {
261  return weak_ptr_factory_.GetWeakPtr();
262}
263
264void AutofillExternalDelegate::FillAutofillFormData(int unique_id,
265                                                    bool is_preview) {
266  // If the selected element is a warning we don't want to do anything.
267  if (unique_id == WebAutofillClient::MenuItemIDWarningMessage)
268    return;
269
270  AutofillDriver::RendererFormDataAction renderer_action = is_preview ?
271      AutofillDriver::FORM_DATA_ACTION_PREVIEW :
272      AutofillDriver::FORM_DATA_ACTION_FILL;
273
274  DCHECK(autofill_driver_->RendererIsAvailable());
275  autofill_driver_->SetRendererActionOnFormDataReception(renderer_action);
276  // Fill the values for the whole form.
277  autofill_manager_->OnFillAutofillFormData(autofill_query_id_,
278                                            autofill_query_form_,
279                                            autofill_query_field_,
280                                            unique_id);
281}
282
283void AutofillExternalDelegate::ApplyAutofillWarnings(
284    std::vector<base::string16>* autofill_values,
285    std::vector<base::string16>* autofill_labels,
286    std::vector<base::string16>* autofill_icons,
287    std::vector<int>* autofill_unique_ids) {
288  if (!autofill_query_field_.should_autocomplete) {
289    // Autofill is disabled.  If there were some profile or credit card
290    // suggestions to show, show a warning instead.  Otherwise, clear out the
291    // list of suggestions.
292    if (!autofill_unique_ids->empty() && (*autofill_unique_ids)[0] > 0) {
293      // If autofill is disabled and we had suggestions, show a warning instead.
294      autofill_values->assign(
295          1, l10n_util::GetStringUTF16(IDS_AUTOFILL_WARNING_FORM_DISABLED));
296      autofill_labels->assign(1, base::string16());
297      autofill_icons->assign(1, base::string16());
298      autofill_unique_ids->assign(1,
299                                  WebAutofillClient::MenuItemIDWarningMessage);
300    } else {
301      autofill_values->clear();
302      autofill_labels->clear();
303      autofill_icons->clear();
304      autofill_unique_ids->clear();
305    }
306  } else if (autofill_unique_ids->size() > 1 &&
307             (*autofill_unique_ids)[0] ==
308                 WebAutofillClient::MenuItemIDWarningMessage) {
309    // If we received a warning instead of suggestions from autofill but regular
310    // suggestions from autocomplete, don't show the autofill warning.
311    autofill_values->erase(autofill_values->begin());
312    autofill_labels->erase(autofill_labels->begin());
313    autofill_icons->erase(autofill_icons->begin());
314    autofill_unique_ids->erase(autofill_unique_ids->begin());
315  }
316
317  // If we were about to show a warning and we shouldn't, don't.
318  if (!autofill_unique_ids->empty() &&
319      (*autofill_unique_ids)[0] ==
320          WebAutofillClient::MenuItemIDWarningMessage &&
321      !display_warning_if_disabled_) {
322    autofill_values->clear();
323    autofill_labels->clear();
324    autofill_icons->clear();
325    autofill_unique_ids->clear();
326  }
327}
328
329void AutofillExternalDelegate::ApplyAutofillOptions(
330    std::vector<base::string16>* autofill_values,
331    std::vector<base::string16>* autofill_labels,
332    std::vector<base::string16>* autofill_icons,
333    std::vector<int>* autofill_unique_ids) {
334  // The form has been auto-filled, so give the user the chance to clear the
335  // form.  Append the 'Clear form' menu item.
336  if (autofill_query_field_.is_autofilled) {
337    autofill_values->push_back(
338        l10n_util::GetStringUTF16(IDS_AUTOFILL_CLEAR_FORM_MENU_ITEM));
339    autofill_labels->push_back(base::string16());
340    autofill_icons->push_back(base::string16());
341    autofill_unique_ids->push_back(WebAutofillClient::MenuItemIDClearForm);
342  }
343
344  // Append the 'Chrome Autofill options' menu item;
345  autofill_values->push_back(
346      l10n_util::GetStringUTF16(IDS_AUTOFILL_OPTIONS_POPUP));
347  autofill_labels->push_back(base::string16());
348  autofill_icons->push_back(base::string16());
349  autofill_unique_ids->push_back(WebAutofillClient::MenuItemIDAutofillOptions);
350}
351
352void AutofillExternalDelegate::InsertDataListValues(
353    std::vector<base::string16>* autofill_values,
354    std::vector<base::string16>* autofill_labels,
355    std::vector<base::string16>* autofill_icons,
356    std::vector<int>* autofill_unique_ids) {
357  if (data_list_values_.empty())
358    return;
359
360  // Insert the separator between the datalist and Autofill values (if there
361  // are any).
362  if (!autofill_values->empty()) {
363    autofill_values->insert(autofill_values->begin(), base::string16());
364    autofill_labels->insert(autofill_labels->begin(), base::string16());
365    autofill_icons->insert(autofill_icons->begin(), base::string16());
366    autofill_unique_ids->insert(autofill_unique_ids->begin(),
367                                WebAutofillClient::MenuItemIDSeparator);
368  }
369
370  // Insert the datalist elements.
371  autofill_values->insert(autofill_values->begin(),
372                          data_list_values_.begin(),
373                          data_list_values_.end());
374  autofill_labels->insert(autofill_labels->begin(),
375                          data_list_labels_.begin(),
376                          data_list_labels_.end());
377
378  // Set the values that all datalist elements share.
379  autofill_icons->insert(autofill_icons->begin(),
380                         data_list_values_.size(),
381                         base::string16());
382  autofill_unique_ids->insert(autofill_unique_ids->begin(),
383                              data_list_values_.size(),
384                              WebAutofillClient::MenuItemIDDataListEntry);
385}
386
387}  // namespace autofill
388