autofill_external_delegate.cc revision eb525c5499e34cc9c4b825d6d9e75bb07cc06ace
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_manager.h"
10#include "components/autofill/core/common/autofill_messages.h"
11#include "content/public/browser/render_view_host.h"
12#include "content/public/browser/web_contents.h"
13#include "grit/component_strings.h"
14#include "third_party/WebKit/public/web/WebAutofillClient.h"
15#include "ui/base/l10n/l10n_util.h"
16
17#if defined(OS_ANDROID)
18#include "content/public/browser/android/content_view_core.h"
19#endif
20
21using content::RenderViewHost;
22using WebKit::WebAutofillClient;
23
24namespace autofill {
25
26AutofillExternalDelegate::AutofillExternalDelegate(
27    content::WebContents* web_contents,
28    AutofillManager* autofill_manager)
29    : web_contents_(web_contents),
30      autofill_manager_(autofill_manager),
31      password_autofill_manager_(web_contents),
32      autofill_query_id_(0),
33      display_warning_if_disabled_(false),
34      has_autofill_suggestion_(false),
35      has_shown_autofill_popup_for_current_edit_(false),
36      registered_keyboard_listener_with_(NULL),
37      weak_ptr_factory_(this) {
38  DCHECK(autofill_manager);
39}
40
41AutofillExternalDelegate::~AutofillExternalDelegate() {}
42
43void AutofillExternalDelegate::OnQuery(int query_id,
44                                       const FormData& form,
45                                       const FormFieldData& field,
46                                       const gfx::RectF& element_bounds,
47                                       bool display_warning_if_disabled) {
48  autofill_query_form_ = form;
49  autofill_query_field_ = field;
50  display_warning_if_disabled_ = display_warning_if_disabled;
51  autofill_query_id_ = query_id;
52  element_bounds_ = element_bounds;
53}
54
55void AutofillExternalDelegate::OnSuggestionsReturned(
56    int query_id,
57    const std::vector<base::string16>& autofill_values,
58    const std::vector<base::string16>& autofill_labels,
59    const std::vector<base::string16>& autofill_icons,
60    const std::vector<int>& autofill_unique_ids) {
61  if (query_id != autofill_query_id_)
62    return;
63
64  std::vector<base::string16> values(autofill_values);
65  std::vector<base::string16> labels(autofill_labels);
66  std::vector<base::string16> icons(autofill_icons);
67  std::vector<int> ids(autofill_unique_ids);
68
69  // Add or hide warnings as appropriate.
70  ApplyAutofillWarnings(&values, &labels, &icons, &ids);
71
72  // Add a separator to go between the values and menu items.
73  values.push_back(base::string16());
74  labels.push_back(base::string16());
75  icons.push_back(base::string16());
76  ids.push_back(WebAutofillClient::MenuItemIDSeparator);
77
78  // Only include "Autofill Options" special menu item if we have Autofill
79  // suggestions.
80  has_autofill_suggestion_ = false;
81  for (size_t i = 0; i < ids.size(); ++i) {
82    if (ids[i] > 0) {
83      has_autofill_suggestion_ = true;
84      break;
85    }
86  }
87
88  if (has_autofill_suggestion_)
89    ApplyAutofillOptions(&values, &labels, &icons, &ids);
90
91  // Remove the separator if it is the last element.
92  DCHECK_GT(ids.size(), 0U);
93  if (ids.back() == WebAutofillClient::MenuItemIDSeparator) {
94    values.pop_back();
95    labels.pop_back();
96    icons.pop_back();
97    ids.pop_back();
98  }
99
100  InsertDataListValues(&values, &labels, &icons, &ids);
101
102  if (values.empty()) {
103    // No suggestions, any popup currently showing is obsolete.
104    autofill_manager_->delegate()->HideAutofillPopup();
105    return;
106  }
107
108  // Send to display.
109  if (autofill_query_field_.is_focusable) {
110    autofill_manager_->delegate()->ShowAutofillPopup(
111        element_bounds_,
112        autofill_query_field_.text_direction,
113        values,
114        labels,
115        icons,
116        ids,
117        GetWeakPtr());
118  }
119}
120
121void AutofillExternalDelegate::OnShowPasswordSuggestions(
122    const std::vector<base::string16>& suggestions,
123    const std::vector<base::string16>& realms,
124    const FormFieldData& field,
125    const gfx::RectF& element_bounds) {
126  autofill_query_field_ = field;
127  element_bounds_ = element_bounds;
128
129  if (suggestions.empty()) {
130    autofill_manager_->delegate()->HideAutofillPopup();
131    return;
132  }
133
134  std::vector<base::string16> empty(suggestions.size());
135  std::vector<int> password_ids(suggestions.size(),
136                                WebAutofillClient::MenuItemIDPasswordEntry);
137  autofill_manager_->delegate()->ShowAutofillPopup(
138      element_bounds_,
139      autofill_query_field_.text_direction,
140      suggestions,
141      realms,
142      empty,
143      password_ids,
144      GetWeakPtr());
145}
146
147void AutofillExternalDelegate::SetCurrentDataListValues(
148    const std::vector<base::string16>& data_list_values,
149    const std::vector<base::string16>& data_list_labels,
150    const std::vector<base::string16>& data_list_icons,
151    const std::vector<int>& data_list_unique_ids) {
152  data_list_values_ = data_list_values;
153  data_list_labels_ = data_list_labels;
154  data_list_icons_ = data_list_icons;
155  data_list_unique_ids_ = data_list_unique_ids;
156}
157
158void AutofillExternalDelegate::OnPopupShown(
159    content::KeyboardListener* listener) {
160  if (!registered_keyboard_listener_with_) {
161    registered_keyboard_listener_with_ = web_contents_->GetRenderViewHost();
162    registered_keyboard_listener_with_->AddKeyboardListener(listener);
163  }
164
165  autofill_manager_->OnDidShowAutofillSuggestions(
166      has_autofill_suggestion_ && !has_shown_autofill_popup_for_current_edit_);
167  has_shown_autofill_popup_for_current_edit_ |= has_autofill_suggestion_;
168}
169
170void AutofillExternalDelegate::OnPopupHidden(
171    content::KeyboardListener* listener) {
172  if (registered_keyboard_listener_with_ == web_contents_->GetRenderViewHost())
173    web_contents_->GetRenderViewHost()->RemoveKeyboardListener(listener);
174
175  registered_keyboard_listener_with_ = NULL;
176}
177
178void AutofillExternalDelegate::DidSelectSuggestion(int identifier) {
179  ClearPreviewedForm();
180
181  // Only preview the data if it is a profile.
182  if (identifier > 0)
183    FillAutofillFormData(identifier, true);
184}
185
186void AutofillExternalDelegate::DidAcceptSuggestion(const base::string16& value,
187                                                   int identifier) {
188  RenderViewHost* host = web_contents_->GetRenderViewHost();
189
190  if (identifier == WebAutofillClient::MenuItemIDAutofillOptions) {
191    // User selected 'Autofill Options'.
192    autofill_manager_->OnShowAutofillDialog();
193  } else if (identifier == WebAutofillClient::MenuItemIDClearForm) {
194    // User selected 'Clear form'.
195    host->Send(new AutofillMsg_ClearForm(host->GetRoutingID()));
196  } else if (identifier == WebAutofillClient::MenuItemIDPasswordEntry) {
197    bool success = password_autofill_manager_.DidAcceptAutofillSuggestion(
198        autofill_query_field_, value);
199    DCHECK(success);
200  } else if (identifier == WebAutofillClient::MenuItemIDDataListEntry) {
201    host->Send(new AutofillMsg_AcceptDataListSuggestion(host->GetRoutingID(),
202                                                        value));
203  } else if (identifier == WebAutofillClient::MenuItemIDAutocompleteEntry) {
204    // User selected an Autocomplete, so we fill directly.
205    host->Send(new AutofillMsg_SetNodeText(host->GetRoutingID(), value));
206  } else {
207    FillAutofillFormData(identifier, false);
208  }
209
210  autofill_manager_->delegate()->HideAutofillPopup();
211}
212
213void AutofillExternalDelegate::RemoveSuggestion(const base::string16& value,
214                                                int identifier) {
215  if (identifier > 0) {
216    autofill_manager_->RemoveAutofillProfileOrCreditCard(identifier);
217  } else {
218    autofill_manager_->RemoveAutocompleteEntry(autofill_query_field_.name,
219                                               value);
220  }
221}
222
223void AutofillExternalDelegate::DidEndTextFieldEditing() {
224  autofill_manager_->delegate()->HideAutofillPopup();
225
226  has_shown_autofill_popup_for_current_edit_ = false;
227}
228
229void AutofillExternalDelegate::ClearPreviewedForm() {
230  RenderViewHost* host = web_contents_->GetRenderViewHost();
231  if (host)
232    host->Send(new AutofillMsg_ClearPreviewedForm(host->GetRoutingID()));
233}
234
235void AutofillExternalDelegate::Reset() {
236  autofill_manager_->delegate()->HideAutofillPopup();
237
238  password_autofill_manager_.Reset();
239}
240
241void AutofillExternalDelegate::AddPasswordFormMapping(
242      const FormFieldData& form,
243      const PasswordFormFillData& fill_data) {
244  password_autofill_manager_.AddPasswordFormMapping(form, fill_data);
245}
246
247base::WeakPtr<AutofillExternalDelegate> AutofillExternalDelegate::GetWeakPtr() {
248  return weak_ptr_factory_.GetWeakPtr();
249}
250
251void AutofillExternalDelegate::FillAutofillFormData(int unique_id,
252                                                    bool is_preview) {
253  // If the selected element is a warning we don't want to do anything.
254  if (unique_id == WebAutofillClient::MenuItemIDWarningMessage)
255    return;
256
257  RenderViewHost* host = web_contents_->GetRenderViewHost();
258
259  if (is_preview) {
260    host->Send(new AutofillMsg_SetAutofillActionPreview(
261        host->GetRoutingID()));
262  } else {
263    host->Send(new AutofillMsg_SetAutofillActionFill(
264        host->GetRoutingID()));
265  }
266
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