autofill_external_delegate.cc revision 424c4d7b64af9d0d8fd9624f381f469654d5e3d2
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_key_press_event_callback_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 // If anything else is added to modify the values after inserting the data 104 // list, AutofillPopupControllerImpl::UpdateDataListValues will need to be 105 // updated to match. 106 InsertDataListValues(&values, &labels, &icons, &ids); 107 108 if (values.empty()) { 109 // No suggestions, any popup currently showing is obsolete. 110 autofill_manager_->delegate()->HideAutofillPopup(); 111 return; 112 } 113 114 // Send to display. 115 if (autofill_query_field_.is_focusable) { 116 autofill_manager_->delegate()->ShowAutofillPopup( 117 element_bounds_, 118 autofill_query_field_.text_direction, 119 values, 120 labels, 121 icons, 122 ids, 123 GetWeakPtr()); 124 } 125} 126 127void AutofillExternalDelegate::OnShowPasswordSuggestions( 128 const std::vector<base::string16>& suggestions, 129 const std::vector<base::string16>& realms, 130 const FormFieldData& field, 131 const gfx::RectF& element_bounds) { 132 autofill_query_field_ = field; 133 element_bounds_ = element_bounds; 134 135 if (suggestions.empty()) { 136 autofill_manager_->delegate()->HideAutofillPopup(); 137 return; 138 } 139 140 std::vector<base::string16> empty(suggestions.size()); 141 std::vector<int> password_ids(suggestions.size(), 142 WebAutofillClient::MenuItemIDPasswordEntry); 143 autofill_manager_->delegate()->ShowAutofillPopup( 144 element_bounds_, 145 autofill_query_field_.text_direction, 146 suggestions, 147 realms, 148 empty, 149 password_ids, 150 GetWeakPtr()); 151} 152 153void AutofillExternalDelegate::SetCurrentDataListValues( 154 const std::vector<base::string16>& data_list_values, 155 const std::vector<base::string16>& data_list_labels) { 156 data_list_values_ = data_list_values; 157 data_list_labels_ = data_list_labels; 158 159 autofill_manager_->delegate()->UpdateAutofillPopupDataListValues( 160 data_list_values, 161 data_list_labels); 162} 163 164void AutofillExternalDelegate::OnPopupShown( 165 content::RenderWidgetHost::KeyPressEventCallback* callback) { 166 if (callback && !registered_key_press_event_callback_with_) { 167 registered_key_press_event_callback_with_ = 168 web_contents_->GetRenderViewHost(); 169 registered_key_press_event_callback_with_->AddKeyPressEventCallback( 170 *callback); 171 } 172 173 autofill_manager_->OnDidShowAutofillSuggestions( 174 has_autofill_suggestion_ && !has_shown_autofill_popup_for_current_edit_); 175 has_shown_autofill_popup_for_current_edit_ |= has_autofill_suggestion_; 176} 177 178void AutofillExternalDelegate::OnPopupHidden( 179 content::RenderWidgetHost::KeyPressEventCallback* callback) { 180 if (callback && (!web_contents_->IsBeingDestroyed()) && 181 (registered_key_press_event_callback_with_ == 182 web_contents_->GetRenderViewHost())) { 183 web_contents_->GetRenderViewHost()->RemoveKeyPressEventCallback(*callback); 184 } 185 186 registered_key_press_event_callback_with_ = NULL; 187} 188 189bool AutofillExternalDelegate::ShouldRepostEvent(const ui::MouseEvent& event) { 190 NOTREACHED(); 191 return true; 192} 193 194void AutofillExternalDelegate::DidSelectSuggestion(int identifier) { 195 ClearPreviewedForm(); 196 197 // Only preview the data if it is a profile. 198 if (identifier > 0) 199 FillAutofillFormData(identifier, true); 200} 201 202void AutofillExternalDelegate::DidAcceptSuggestion(const base::string16& value, 203 int identifier) { 204 RenderViewHost* host = web_contents_->GetRenderViewHost(); 205 206 if (identifier == WebAutofillClient::MenuItemIDAutofillOptions) { 207 // User selected 'Autofill Options'. 208 autofill_manager_->OnShowAutofillDialog(); 209 } else if (identifier == WebAutofillClient::MenuItemIDClearForm) { 210 // User selected 'Clear form'. 211 autofill_driver_->RendererShouldClearFilledForm(); 212 } else if (identifier == WebAutofillClient::MenuItemIDPasswordEntry) { 213 bool success = password_autofill_manager_.DidAcceptAutofillSuggestion( 214 autofill_query_field_, value); 215 DCHECK(success); 216 } else if (identifier == WebAutofillClient::MenuItemIDDataListEntry) { 217 host->Send(new AutofillMsg_AcceptDataListSuggestion(host->GetRoutingID(), 218 value)); 219 } else if (identifier == WebAutofillClient::MenuItemIDAutocompleteEntry) { 220 // User selected an Autocomplete, so we fill directly. 221 host->Send(new AutofillMsg_SetNodeText(host->GetRoutingID(), value)); 222 } else { 223 FillAutofillFormData(identifier, false); 224 } 225 226 autofill_manager_->delegate()->HideAutofillPopup(); 227} 228 229void AutofillExternalDelegate::RemoveSuggestion(const base::string16& value, 230 int identifier) { 231 if (identifier > 0) { 232 autofill_manager_->RemoveAutofillProfileOrCreditCard(identifier); 233 } else { 234 autofill_manager_->RemoveAutocompleteEntry(autofill_query_field_.name, 235 value); 236 } 237} 238 239void AutofillExternalDelegate::DidEndTextFieldEditing() { 240 autofill_manager_->delegate()->HideAutofillPopup(); 241 242 has_shown_autofill_popup_for_current_edit_ = false; 243} 244 245void AutofillExternalDelegate::ClearPreviewedForm() { 246 autofill_driver_->RendererShouldClearPreviewedForm(); 247} 248 249void AutofillExternalDelegate::Reset() { 250 autofill_manager_->delegate()->HideAutofillPopup(); 251 252 password_autofill_manager_.Reset(); 253} 254 255void AutofillExternalDelegate::AddPasswordFormMapping( 256 const FormFieldData& form, 257 const PasswordFormFillData& fill_data) { 258 password_autofill_manager_.AddPasswordFormMapping(form, fill_data); 259} 260 261base::WeakPtr<AutofillExternalDelegate> AutofillExternalDelegate::GetWeakPtr() { 262 return weak_ptr_factory_.GetWeakPtr(); 263} 264 265void AutofillExternalDelegate::FillAutofillFormData(int unique_id, 266 bool is_preview) { 267 // If the selected element is a warning we don't want to do anything. 268 if (unique_id == WebAutofillClient::MenuItemIDWarningMessage) 269 return; 270 271 AutofillDriver::RendererFormDataAction renderer_action = is_preview ? 272 AutofillDriver::FORM_DATA_ACTION_PREVIEW : 273 AutofillDriver::FORM_DATA_ACTION_FILL; 274 275 DCHECK(autofill_driver_->RendererIsAvailable()); 276 autofill_driver_->SetRendererActionOnFormDataReception(renderer_action); 277 // Fill the values for the whole form. 278 autofill_manager_->OnFillAutofillFormData(autofill_query_id_, 279 autofill_query_form_, 280 autofill_query_field_, 281 unique_id); 282} 283 284void AutofillExternalDelegate::ApplyAutofillWarnings( 285 std::vector<base::string16>* autofill_values, 286 std::vector<base::string16>* autofill_labels, 287 std::vector<base::string16>* autofill_icons, 288 std::vector<int>* autofill_unique_ids) { 289 if (!autofill_query_field_.should_autocomplete) { 290 // Autofill is disabled. If there were some profile or credit card 291 // suggestions to show, show a warning instead. Otherwise, clear out the 292 // list of suggestions. 293 if (!autofill_unique_ids->empty() && (*autofill_unique_ids)[0] > 0) { 294 // If autofill is disabled and we had suggestions, show a warning instead. 295 autofill_values->assign( 296 1, l10n_util::GetStringUTF16(IDS_AUTOFILL_WARNING_FORM_DISABLED)); 297 autofill_labels->assign(1, base::string16()); 298 autofill_icons->assign(1, base::string16()); 299 autofill_unique_ids->assign(1, 300 WebAutofillClient::MenuItemIDWarningMessage); 301 } else { 302 autofill_values->clear(); 303 autofill_labels->clear(); 304 autofill_icons->clear(); 305 autofill_unique_ids->clear(); 306 } 307 } else if (autofill_unique_ids->size() > 1 && 308 (*autofill_unique_ids)[0] == 309 WebAutofillClient::MenuItemIDWarningMessage) { 310 // If we received a warning instead of suggestions from autofill but regular 311 // suggestions from autocomplete, don't show the autofill warning. 312 autofill_values->erase(autofill_values->begin()); 313 autofill_labels->erase(autofill_labels->begin()); 314 autofill_icons->erase(autofill_icons->begin()); 315 autofill_unique_ids->erase(autofill_unique_ids->begin()); 316 } 317 318 // If we were about to show a warning and we shouldn't, don't. 319 if (!autofill_unique_ids->empty() && 320 (*autofill_unique_ids)[0] == 321 WebAutofillClient::MenuItemIDWarningMessage && 322 !display_warning_if_disabled_) { 323 autofill_values->clear(); 324 autofill_labels->clear(); 325 autofill_icons->clear(); 326 autofill_unique_ids->clear(); 327 } 328} 329 330void AutofillExternalDelegate::ApplyAutofillOptions( 331 std::vector<base::string16>* autofill_values, 332 std::vector<base::string16>* autofill_labels, 333 std::vector<base::string16>* autofill_icons, 334 std::vector<int>* autofill_unique_ids) { 335 // The form has been auto-filled, so give the user the chance to clear the 336 // form. Append the 'Clear form' menu item. 337 if (autofill_query_field_.is_autofilled) { 338 autofill_values->push_back( 339 l10n_util::GetStringUTF16(IDS_AUTOFILL_CLEAR_FORM_MENU_ITEM)); 340 autofill_labels->push_back(base::string16()); 341 autofill_icons->push_back(base::string16()); 342 autofill_unique_ids->push_back(WebAutofillClient::MenuItemIDClearForm); 343 } 344 345 // Append the 'Chrome Autofill options' menu item; 346 autofill_values->push_back( 347 l10n_util::GetStringUTF16(IDS_AUTOFILL_OPTIONS_POPUP)); 348 autofill_labels->push_back(base::string16()); 349 autofill_icons->push_back(base::string16()); 350 autofill_unique_ids->push_back(WebAutofillClient::MenuItemIDAutofillOptions); 351} 352 353void AutofillExternalDelegate::InsertDataListValues( 354 std::vector<base::string16>* autofill_values, 355 std::vector<base::string16>* autofill_labels, 356 std::vector<base::string16>* autofill_icons, 357 std::vector<int>* autofill_unique_ids) { 358 if (data_list_values_.empty()) 359 return; 360 361 // Insert the separator between the datalist and Autofill values (if there 362 // are any). 363 if (!autofill_values->empty()) { 364 autofill_values->insert(autofill_values->begin(), base::string16()); 365 autofill_labels->insert(autofill_labels->begin(), base::string16()); 366 autofill_icons->insert(autofill_icons->begin(), base::string16()); 367 autofill_unique_ids->insert(autofill_unique_ids->begin(), 368 WebAutofillClient::MenuItemIDSeparator); 369 } 370 371 // Insert the datalist elements. 372 autofill_values->insert(autofill_values->begin(), 373 data_list_values_.begin(), 374 data_list_values_.end()); 375 autofill_labels->insert(autofill_labels->begin(), 376 data_list_labels_.begin(), 377 data_list_labels_.end()); 378 379 // Set the values that all datalist elements share. 380 autofill_icons->insert(autofill_icons->begin(), 381 data_list_values_.size(), 382 base::string16()); 383 autofill_unique_ids->insert(autofill_unique_ids->begin(), 384 data_list_values_.size(), 385 WebAutofillClient::MenuItemIDDataListEntry); 386} 387 388} // namespace autofill 389