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