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.
5 #include "components/autofill/core/browser/autofill_external_delegate.h"
8 #include "base/command_line.h"
9 #include "base/i18n/case_conversion.h"
10 #include "base/message_loop/message_loop.h"
11 #include "base/metrics/histogram_macros.h"
12 #include "base/metrics/sparse_histogram.h"
13 #include "base/strings/string_util.h"
14 #include "base/strings/utf_string_conversions.h"
15 #include "components/autofill/core/browser/autocomplete_history_manager.h"
16 #include "components/autofill/core/browser/autofill_driver.h"
17 #include "components/autofill/core/browser/autofill_manager.h"
18 #include "components/autofill/core/browser/autofill_metrics.h"
19 #include "components/autofill/core/browser/popup_item_ids.h"
20 #include "components/autofill/core/common/autofill_util.h"
21 #include "grit/components_strings.h"
22 #include "ui/base/l10n/l10n_util.h"
26 AutofillExternalDelegate::AutofillExternalDelegate(AutofillManager
* manager
,
27 AutofillDriver
* driver
)
31 has_suggestion_(false),
32 has_shown_popup_for_current_edit_(false),
33 should_show_scan_credit_card_(false),
34 has_shown_address_book_prompt(false),
35 weak_ptr_factory_(this) {
39 AutofillExternalDelegate::~AutofillExternalDelegate() {}
41 void AutofillExternalDelegate::OnQuery(int query_id
,
43 const FormFieldData
& field
,
44 const gfx::RectF
& element_bounds
) {
45 if (!query_form_
.SameFormAs(form
))
46 has_shown_address_book_prompt
= false;
51 element_bounds_
= element_bounds
;
52 should_show_scan_credit_card_
=
53 manager_
->ShouldShowScanCreditCard(query_form_
, query_field_
);
56 void AutofillExternalDelegate::OnSuggestionsReturned(
58 const std::vector
<Suggestion
>& input_suggestions
) {
59 if (query_id
!= query_id_
)
62 std::vector
<Suggestion
> suggestions(input_suggestions
);
64 // Add or hide warnings as appropriate.
65 ApplyAutofillWarnings(&suggestions
);
67 #if !defined(OS_ANDROID)
68 // Add a separator to go between the values and menu items.
69 suggestions
.push_back(Suggestion());
70 suggestions
.back().frontend_id
= POPUP_ITEM_ID_SEPARATOR
;
73 if (should_show_scan_credit_card_
) {
74 Suggestion
scan_credit_card(
75 l10n_util::GetStringUTF16(IDS_AUTOFILL_SCAN_CREDIT_CARD
));
76 scan_credit_card
.frontend_id
= POPUP_ITEM_ID_SCAN_CREDIT_CARD
;
77 scan_credit_card
.icon
= base::ASCIIToUTF16("scanCreditCardIcon");
78 suggestions
.push_back(scan_credit_card
);
80 if (!has_shown_popup_for_current_edit_
) {
81 AutofillMetrics::LogScanCreditCardPromptMetric(
82 AutofillMetrics::SCAN_CARD_ITEM_SHOWN
);
86 // Only include "Autofill Options" special menu item if we have Autofill
88 has_suggestion_
= false;
89 for (size_t i
= 0; i
< suggestions
.size(); ++i
) {
90 if (suggestions
[i
].frontend_id
> 0) {
91 has_suggestion_
= true;
97 ApplyAutofillOptions(&suggestions
);
99 #if !defined(OS_ANDROID)
100 // Remove the separator if it is the last element.
101 DCHECK_GT(suggestions
.size(), 0U);
102 if (suggestions
.back().frontend_id
== POPUP_ITEM_ID_SEPARATOR
)
103 suggestions
.pop_back();
106 // If anything else is added to modify the values after inserting the data
107 // list, AutofillPopupControllerImpl::UpdateDataListValues will need to be
109 InsertDataListValues(&suggestions
);
111 if (suggestions
.empty()) {
112 // No suggestions, any popup currently showing is obsolete.
113 manager_
->client()->HideAutofillPopup();
118 if (query_field_
.is_focusable
) {
119 manager_
->client()->ShowAutofillPopup(element_bounds_
,
120 query_field_
.text_direction
,
126 void AutofillExternalDelegate::SetCurrentDataListValues(
127 const std::vector
<base::string16
>& data_list_values
,
128 const std::vector
<base::string16
>& data_list_labels
) {
129 data_list_values_
= data_list_values
;
130 data_list_labels_
= data_list_labels
;
132 manager_
->client()->UpdateAutofillPopupDataListValues(data_list_values
,
136 void AutofillExternalDelegate::OnPopupShown() {
137 manager_
->DidShowSuggestions(
138 has_suggestion_
&& !has_shown_popup_for_current_edit_
,
141 has_shown_popup_for_current_edit_
|= has_suggestion_
;
144 void AutofillExternalDelegate::OnPopupHidden() {
145 driver_
->PopupHidden();
148 void AutofillExternalDelegate::DidSelectSuggestion(
149 const base::string16
& value
,
151 ClearPreviewedForm();
153 // Only preview the data if it is a profile.
155 FillAutofillFormData(identifier
, true);
156 else if (identifier
== POPUP_ITEM_ID_AUTOCOMPLETE_ENTRY
)
157 driver_
->RendererShouldPreviewFieldWithValue(value
);
160 void AutofillExternalDelegate::DidAcceptSuggestion(const base::string16
& value
,
163 if (identifier
== POPUP_ITEM_ID_AUTOFILL_OPTIONS
) {
164 // User selected 'Autofill Options'.
165 manager_
->ShowAutofillSettings();
166 } else if (identifier
== POPUP_ITEM_ID_CLEAR_FORM
) {
167 // User selected 'Clear form'.
168 driver_
->RendererShouldClearFilledForm();
169 } else if (identifier
== POPUP_ITEM_ID_PASSWORD_ENTRY
) {
170 NOTREACHED(); // Should be handled elsewhere.
171 } else if (identifier
== POPUP_ITEM_ID_DATALIST_ENTRY
) {
172 driver_
->RendererShouldAcceptDataListSuggestion(value
);
173 } else if (identifier
== POPUP_ITEM_ID_AUTOCOMPLETE_ENTRY
) {
174 // User selected an Autocomplete, so we fill directly.
175 driver_
->RendererShouldFillFieldWithValue(value
);
176 } else if (identifier
== POPUP_ITEM_ID_SCAN_CREDIT_CARD
) {
177 manager_
->client()->ScanCreditCard(base::Bind(
178 &AutofillExternalDelegate::OnCreditCardScanned
, GetWeakPtr()));
180 if (identifier
> 0) // Denotes an Autofill suggestion.
181 AutofillMetrics::LogSuggestionAcceptedIndex(position
);
183 FillAutofillFormData(identifier
, false);
186 if (should_show_scan_credit_card_
) {
187 AutofillMetrics::LogScanCreditCardPromptMetric(
188 identifier
== POPUP_ITEM_ID_SCAN_CREDIT_CARD
189 ? AutofillMetrics::SCAN_CARD_ITEM_SELECTED
190 : AutofillMetrics::SCAN_CARD_OTHER_ITEM_SELECTED
);
193 manager_
->client()->HideAutofillPopup();
196 bool AutofillExternalDelegate::GetDeletionConfirmationText(
197 const base::string16
& value
,
199 base::string16
* title
,
200 base::string16
* body
) {
201 return manager_
->GetDeletionConfirmationText(value
, identifier
, title
, body
);
204 bool AutofillExternalDelegate::RemoveSuggestion(const base::string16
& value
,
207 return manager_
->RemoveAutofillProfileOrCreditCard(identifier
);
209 if (identifier
== POPUP_ITEM_ID_AUTOCOMPLETE_ENTRY
) {
210 manager_
->RemoveAutocompleteEntry(query_field_
.name
, value
);
217 void AutofillExternalDelegate::DidEndTextFieldEditing() {
218 manager_
->client()->HideAutofillPopup();
220 has_shown_popup_for_current_edit_
= false;
223 void AutofillExternalDelegate::ClearPreviewedForm() {
224 driver_
->RendererShouldClearPreviewedForm();
227 void AutofillExternalDelegate::Reset() {
228 manager_
->client()->HideAutofillPopup();
231 void AutofillExternalDelegate::OnPingAck() {
232 // Reissue the most recent query, which will reopen the Autofill popup.
233 manager_
->OnQueryFormFieldAutofill(query_id_
, query_form_
, query_field_
,
237 base::WeakPtr
<AutofillExternalDelegate
> AutofillExternalDelegate::GetWeakPtr() {
238 return weak_ptr_factory_
.GetWeakPtr();
241 void AutofillExternalDelegate::OnCreditCardScanned(
242 const base::string16
& card_number
,
243 int expiration_month
,
244 int expiration_year
) {
245 manager_
->FillCreditCardForm(
246 query_id_
, query_form_
, query_field_
,
247 CreditCard(card_number
, expiration_month
, expiration_year
));
250 void AutofillExternalDelegate::FillAutofillFormData(int unique_id
,
252 // If the selected element is a warning we don't want to do anything.
253 if (unique_id
== POPUP_ITEM_ID_WARNING_MESSAGE
)
256 AutofillDriver::RendererFormDataAction renderer_action
= is_preview
?
257 AutofillDriver::FORM_DATA_ACTION_PREVIEW
:
258 AutofillDriver::FORM_DATA_ACTION_FILL
;
260 DCHECK(driver_
->RendererIsAvailable());
261 // Fill the values for the whole form.
262 manager_
->FillOrPreviewForm(renderer_action
,
269 void AutofillExternalDelegate::ApplyAutofillWarnings(
270 std::vector
<Suggestion
>* suggestions
) {
271 if (suggestions
->size() > 1 &&
272 (*suggestions
)[0].frontend_id
== POPUP_ITEM_ID_WARNING_MESSAGE
) {
273 // If we received a warning instead of suggestions from Autofill but regular
274 // suggestions from autocomplete, don't show the Autofill warning.
275 suggestions
->erase(suggestions
->begin());
279 void AutofillExternalDelegate::ApplyAutofillOptions(
280 std::vector
<Suggestion
>* suggestions
) {
281 // The form has been auto-filled, so give the user the chance to clear the
282 // form. Append the 'Clear form' menu item.
283 if (query_field_
.is_autofilled
) {
284 base::string16 value
=
285 l10n_util::GetStringUTF16(IDS_AUTOFILL_CLEAR_FORM_MENU_ITEM
);
286 // TODO(rouslan): Remove manual upper-casing when keyboard accessory becomes
287 // default on Android.
288 if (IsKeyboardAccessoryEnabled())
289 value
= base::i18n::ToUpper(value
);
291 suggestions
->push_back(Suggestion(value
));
292 suggestions
->back().frontend_id
= POPUP_ITEM_ID_CLEAR_FORM
;
295 // Append the 'Chrome Autofill options' menu item;
296 suggestions
->push_back(Suggestion(
297 l10n_util::GetStringUTF16(IDS_AUTOFILL_OPTIONS_POPUP
)));
298 suggestions
->back().frontend_id
= POPUP_ITEM_ID_AUTOFILL_OPTIONS
;
299 if (IsKeyboardAccessoryEnabled())
300 suggestions
->back().icon
= base::ASCIIToUTF16("settings");
303 void AutofillExternalDelegate::InsertDataListValues(
304 std::vector
<Suggestion
>* suggestions
) {
305 if (data_list_values_
.empty())
308 #if !defined(OS_ANDROID)
309 // Insert the separator between the datalist and Autofill values (if there
311 if (!suggestions
->empty()) {
312 suggestions
->insert(suggestions
->begin(), Suggestion());
313 (*suggestions
)[0].frontend_id
= POPUP_ITEM_ID_SEPARATOR
;
317 // Insert the datalist elements at the beginning.
318 suggestions
->insert(suggestions
->begin(), data_list_values_
.size(),
320 for (size_t i
= 0; i
< data_list_values_
.size(); i
++) {
321 (*suggestions
)[i
].value
= data_list_values_
[i
];
322 (*suggestions
)[i
].label
= data_list_labels_
[i
];
323 (*suggestions
)[i
].frontend_id
= POPUP_ITEM_ID_DATALIST_ENTRY
;
327 } // namespace autofill