autofill_external_delegate.cc revision 7dbb3d5cf0c15f500944d211057644d6a2f37371
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  InsertDataListValues(&values, &labels, &icons, &ids);
104
105  if (values.empty()) {
106    // No suggestions, any popup currently showing is obsolete.
107    autofill_manager_->delegate()->HideAutofillPopup();
108    return;
109  }
110
111  // Send to display.
112  if (autofill_query_field_.is_focusable) {
113    autofill_manager_->delegate()->ShowAutofillPopup(
114        element_bounds_,
115        autofill_query_field_.text_direction,
116        values,
117        labels,
118        icons,
119        ids,
120        GetWeakPtr());
121  }
122}
123
124void AutofillExternalDelegate::OnShowPasswordSuggestions(
125    const std::vector<base::string16>& suggestions,
126    const std::vector<base::string16>& realms,
127    const FormFieldData& field,
128    const gfx::RectF& element_bounds) {
129  autofill_query_field_ = field;
130  element_bounds_ = element_bounds;
131
132  if (suggestions.empty()) {
133    autofill_manager_->delegate()->HideAutofillPopup();
134    return;
135  }
136
137  std::vector<base::string16> empty(suggestions.size());
138  std::vector<int> password_ids(suggestions.size(),
139                                WebAutofillClient::MenuItemIDPasswordEntry);
140  autofill_manager_->delegate()->ShowAutofillPopup(
141      element_bounds_,
142      autofill_query_field_.text_direction,
143      suggestions,
144      realms,
145      empty,
146      password_ids,
147      GetWeakPtr());
148}
149
150void AutofillExternalDelegate::SetCurrentDataListValues(
151    const std::vector<base::string16>& data_list_values,
152    const std::vector<base::string16>& data_list_labels,
153    const std::vector<base::string16>& data_list_icons,
154    const std::vector<int>& data_list_unique_ids) {
155  data_list_values_ = data_list_values;
156  data_list_labels_ = data_list_labels;
157  data_list_icons_ = data_list_icons;
158  data_list_unique_ids_ = data_list_unique_ids;
159}
160
161void AutofillExternalDelegate::OnPopupShown(
162    content::KeyboardListener* listener) {
163  if (!registered_keyboard_listener_with_) {
164    registered_keyboard_listener_with_ = web_contents_->GetRenderViewHost();
165    registered_keyboard_listener_with_->AddKeyboardListener(listener);
166  }
167
168  autofill_manager_->OnDidShowAutofillSuggestions(
169      has_autofill_suggestion_ && !has_shown_autofill_popup_for_current_edit_);
170  has_shown_autofill_popup_for_current_edit_ |= has_autofill_suggestion_;
171}
172
173void AutofillExternalDelegate::OnPopupHidden(
174    content::KeyboardListener* listener) {
175  if ((!web_contents_->IsBeingDestroyed()) &&
176      (registered_keyboard_listener_with_ ==
177          web_contents_->GetRenderViewHost())) {
178    web_contents_->GetRenderViewHost()->RemoveKeyboardListener(listener);
179  }
180
181  registered_keyboard_listener_with_ = NULL;
182}
183
184void AutofillExternalDelegate::DidSelectSuggestion(int identifier) {
185  ClearPreviewedForm();
186
187  // Only preview the data if it is a profile.
188  if (identifier > 0)
189    FillAutofillFormData(identifier, true);
190}
191
192void AutofillExternalDelegate::DidAcceptSuggestion(const base::string16& value,
193                                                   int identifier) {
194  RenderViewHost* host = web_contents_->GetRenderViewHost();
195
196  if (identifier == WebAutofillClient::MenuItemIDAutofillOptions) {
197    // User selected 'Autofill Options'.
198    autofill_manager_->OnShowAutofillDialog();
199  } else if (identifier == WebAutofillClient::MenuItemIDClearForm) {
200    // User selected 'Clear form'.
201    autofill_driver_->RendererShouldClearFilledForm();
202  } else if (identifier == WebAutofillClient::MenuItemIDPasswordEntry) {
203    bool success = password_autofill_manager_.DidAcceptAutofillSuggestion(
204        autofill_query_field_, value);
205    DCHECK(success);
206  } else if (identifier == WebAutofillClient::MenuItemIDDataListEntry) {
207    host->Send(new AutofillMsg_AcceptDataListSuggestion(host->GetRoutingID(),
208                                                        value));
209  } else if (identifier == WebAutofillClient::MenuItemIDAutocompleteEntry) {
210    // User selected an Autocomplete, so we fill directly.
211    host->Send(new AutofillMsg_SetNodeText(host->GetRoutingID(), value));
212  } else {
213    FillAutofillFormData(identifier, false);
214  }
215
216  autofill_manager_->delegate()->HideAutofillPopup();
217}
218
219void AutofillExternalDelegate::RemoveSuggestion(const base::string16& value,
220                                                int identifier) {
221  if (identifier > 0) {
222    autofill_manager_->RemoveAutofillProfileOrCreditCard(identifier);
223  } else {
224    autofill_manager_->RemoveAutocompleteEntry(autofill_query_field_.name,
225                                               value);
226  }
227}
228
229void AutofillExternalDelegate::DidEndTextFieldEditing() {
230  autofill_manager_->delegate()->HideAutofillPopup();
231
232  has_shown_autofill_popup_for_current_edit_ = false;
233}
234
235void AutofillExternalDelegate::ClearPreviewedForm() {
236  autofill_driver_->RendererShouldClearPreviewedForm();
237}
238
239void AutofillExternalDelegate::Reset() {
240  autofill_manager_->delegate()->HideAutofillPopup();
241
242  password_autofill_manager_.Reset();
243}
244
245void AutofillExternalDelegate::AddPasswordFormMapping(
246      const FormFieldData& form,
247      const PasswordFormFillData& fill_data) {
248  password_autofill_manager_.AddPasswordFormMapping(form, fill_data);
249}
250
251base::WeakPtr<AutofillExternalDelegate> AutofillExternalDelegate::GetWeakPtr() {
252  return weak_ptr_factory_.GetWeakPtr();
253}
254
255void AutofillExternalDelegate::FillAutofillFormData(int unique_id,
256                                                    bool is_preview) {
257  // If the selected element is a warning we don't want to do anything.
258  if (unique_id == WebAutofillClient::MenuItemIDWarningMessage)
259    return;
260
261  AutofillDriver::RendererFormDataAction renderer_action = is_preview ?
262      AutofillDriver::FORM_DATA_ACTION_PREVIEW :
263      AutofillDriver::FORM_DATA_ACTION_FILL;
264
265  DCHECK(autofill_driver_->RendererIsAvailable());
266  autofill_driver_->SetRendererActionOnFormDataReception(renderer_action);
267  // Fill the values for the whole form.
268  autofill_manager_->OnFillAutofillFormData(autofill_query_id_,
269                                            autofill_query_form_,
270                                            autofill_query_field_,
271                                            unique_id);
272}
273
274void AutofillExternalDelegate::ApplyAutofillWarnings(
275    std::vector<base::string16>* autofill_values,
276    std::vector<base::string16>* autofill_labels,
277    std::vector<base::string16>* autofill_icons,
278    std::vector<int>* autofill_unique_ids) {
279  if (!autofill_query_field_.should_autocomplete) {
280    // Autofill is disabled.  If there were some profile or credit card
281    // suggestions to show, show a warning instead.  Otherwise, clear out the
282    // list of suggestions.
283    if (!autofill_unique_ids->empty() && (*autofill_unique_ids)[0] > 0) {
284      // If autofill is disabled and we had suggestions, show a warning instead.
285      autofill_values->assign(
286          1, l10n_util::GetStringUTF16(IDS_AUTOFILL_WARNING_FORM_DISABLED));
287      autofill_labels->assign(1, base::string16());
288      autofill_icons->assign(1, base::string16());
289      autofill_unique_ids->assign(1,
290                                  WebAutofillClient::MenuItemIDWarningMessage);
291    } else {
292      autofill_values->clear();
293      autofill_labels->clear();
294      autofill_icons->clear();
295      autofill_unique_ids->clear();
296    }
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
320void 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
343void 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}  // namespace autofill
377