autofill_external_delegate.cc revision ca12bfac764ba476d6cd062bf1dde12cc64c3f40
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 // 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::KeyboardListener* listener) { 166 if (!registered_keyboard_listener_with_) { 167 registered_keyboard_listener_with_ = web_contents_->GetRenderViewHost(); 168 registered_keyboard_listener_with_->AddKeyboardListener(listener); 169 } 170 171 autofill_manager_->OnDidShowAutofillSuggestions( 172 has_autofill_suggestion_ && !has_shown_autofill_popup_for_current_edit_); 173 has_shown_autofill_popup_for_current_edit_ |= has_autofill_suggestion_; 174} 175 176void AutofillExternalDelegate::OnPopupHidden( 177 content::KeyboardListener* listener) { 178 if ((!web_contents_->IsBeingDestroyed()) && 179 (registered_keyboard_listener_with_ == 180 web_contents_->GetRenderViewHost())) { 181 web_contents_->GetRenderViewHost()->RemoveKeyboardListener(listener); 182 } 183 184 registered_keyboard_listener_with_ = NULL; 185} 186 187void AutofillExternalDelegate::DidSelectSuggestion(int identifier) { 188 ClearPreviewedForm(); 189 190 // Only preview the data if it is a profile. 191 if (identifier > 0) 192 FillAutofillFormData(identifier, true); 193} 194 195void AutofillExternalDelegate::DidAcceptSuggestion(const base::string16& value, 196 int identifier) { 197 RenderViewHost* host = web_contents_->GetRenderViewHost(); 198 199 if (identifier == WebAutofillClient::MenuItemIDAutofillOptions) { 200 // User selected 'Autofill Options'. 201 autofill_manager_->OnShowAutofillDialog(); 202 } else if (identifier == WebAutofillClient::MenuItemIDClearForm) { 203 // User selected 'Clear form'. 204 autofill_driver_->RendererShouldClearFilledForm(); 205 } else if (identifier == WebAutofillClient::MenuItemIDPasswordEntry) { 206 bool success = password_autofill_manager_.DidAcceptAutofillSuggestion( 207 autofill_query_field_, value); 208 DCHECK(success); 209 } else if (identifier == WebAutofillClient::MenuItemIDDataListEntry) { 210 host->Send(new AutofillMsg_AcceptDataListSuggestion(host->GetRoutingID(), 211 value)); 212 } else if (identifier == WebAutofillClient::MenuItemIDAutocompleteEntry) { 213 // User selected an Autocomplete, so we fill directly. 214 host->Send(new AutofillMsg_SetNodeText(host->GetRoutingID(), value)); 215 } else { 216 FillAutofillFormData(identifier, false); 217 } 218 219 autofill_manager_->delegate()->HideAutofillPopup(); 220} 221 222void AutofillExternalDelegate::RemoveSuggestion(const base::string16& value, 223 int identifier) { 224 if (identifier > 0) { 225 autofill_manager_->RemoveAutofillProfileOrCreditCard(identifier); 226 } else { 227 autofill_manager_->RemoveAutocompleteEntry(autofill_query_field_.name, 228 value); 229 } 230} 231 232void AutofillExternalDelegate::DidEndTextFieldEditing() { 233 autofill_manager_->delegate()->HideAutofillPopup(); 234 235 has_shown_autofill_popup_for_current_edit_ = false; 236} 237 238void AutofillExternalDelegate::ClearPreviewedForm() { 239 autofill_driver_->RendererShouldClearPreviewedForm(); 240} 241 242void AutofillExternalDelegate::Reset() { 243 autofill_manager_->delegate()->HideAutofillPopup(); 244 245 password_autofill_manager_.Reset(); 246} 247 248void AutofillExternalDelegate::AddPasswordFormMapping( 249 const FormFieldData& form, 250 const PasswordFormFillData& fill_data) { 251 password_autofill_manager_.AddPasswordFormMapping(form, fill_data); 252} 253 254base::WeakPtr<AutofillExternalDelegate> AutofillExternalDelegate::GetWeakPtr() { 255 return weak_ptr_factory_.GetWeakPtr(); 256} 257 258void AutofillExternalDelegate::FillAutofillFormData(int unique_id, 259 bool is_preview) { 260 // If the selected element is a warning we don't want to do anything. 261 if (unique_id == WebAutofillClient::MenuItemIDWarningMessage) 262 return; 263 264 AutofillDriver::RendererFormDataAction renderer_action = is_preview ? 265 AutofillDriver::FORM_DATA_ACTION_PREVIEW : 266 AutofillDriver::FORM_DATA_ACTION_FILL; 267 268 DCHECK(autofill_driver_->RendererIsAvailable()); 269 autofill_driver_->SetRendererActionOnFormDataReception(renderer_action); 270 // Fill the values for the whole form. 271 autofill_manager_->OnFillAutofillFormData(autofill_query_id_, 272 autofill_query_form_, 273 autofill_query_field_, 274 unique_id); 275} 276 277void AutofillExternalDelegate::ApplyAutofillWarnings( 278 std::vector<base::string16>* autofill_values, 279 std::vector<base::string16>* autofill_labels, 280 std::vector<base::string16>* autofill_icons, 281 std::vector<int>* autofill_unique_ids) { 282 if (!autofill_query_field_.should_autocomplete) { 283 // Autofill is disabled. If there were some profile or credit card 284 // suggestions to show, show a warning instead. Otherwise, clear out the 285 // list of suggestions. 286 if (!autofill_unique_ids->empty() && (*autofill_unique_ids)[0] > 0) { 287 // If autofill is disabled and we had suggestions, show a warning instead. 288 autofill_values->assign( 289 1, l10n_util::GetStringUTF16(IDS_AUTOFILL_WARNING_FORM_DISABLED)); 290 autofill_labels->assign(1, base::string16()); 291 autofill_icons->assign(1, base::string16()); 292 autofill_unique_ids->assign(1, 293 WebAutofillClient::MenuItemIDWarningMessage); 294 } else { 295 autofill_values->clear(); 296 autofill_labels->clear(); 297 autofill_icons->clear(); 298 autofill_unique_ids->clear(); 299 } 300 } else if (autofill_unique_ids->size() > 1 && 301 (*autofill_unique_ids)[0] == 302 WebAutofillClient::MenuItemIDWarningMessage) { 303 // If we received a warning instead of suggestions from autofill but regular 304 // suggestions from autocomplete, don't show the autofill warning. 305 autofill_values->erase(autofill_values->begin()); 306 autofill_labels->erase(autofill_labels->begin()); 307 autofill_icons->erase(autofill_icons->begin()); 308 autofill_unique_ids->erase(autofill_unique_ids->begin()); 309 } 310 311 // If we were about to show a warning and we shouldn't, don't. 312 if (!autofill_unique_ids->empty() && 313 (*autofill_unique_ids)[0] == 314 WebAutofillClient::MenuItemIDWarningMessage && 315 !display_warning_if_disabled_) { 316 autofill_values->clear(); 317 autofill_labels->clear(); 318 autofill_icons->clear(); 319 autofill_unique_ids->clear(); 320 } 321} 322 323void AutofillExternalDelegate::ApplyAutofillOptions( 324 std::vector<base::string16>* autofill_values, 325 std::vector<base::string16>* autofill_labels, 326 std::vector<base::string16>* autofill_icons, 327 std::vector<int>* autofill_unique_ids) { 328 // The form has been auto-filled, so give the user the chance to clear the 329 // form. Append the 'Clear form' menu item. 330 if (autofill_query_field_.is_autofilled) { 331 autofill_values->push_back( 332 l10n_util::GetStringUTF16(IDS_AUTOFILL_CLEAR_FORM_MENU_ITEM)); 333 autofill_labels->push_back(base::string16()); 334 autofill_icons->push_back(base::string16()); 335 autofill_unique_ids->push_back(WebAutofillClient::MenuItemIDClearForm); 336 } 337 338 // Append the 'Chrome Autofill options' menu item; 339 autofill_values->push_back( 340 l10n_util::GetStringUTF16(IDS_AUTOFILL_OPTIONS_POPUP)); 341 autofill_labels->push_back(base::string16()); 342 autofill_icons->push_back(base::string16()); 343 autofill_unique_ids->push_back(WebAutofillClient::MenuItemIDAutofillOptions); 344} 345 346void AutofillExternalDelegate::InsertDataListValues( 347 std::vector<base::string16>* autofill_values, 348 std::vector<base::string16>* autofill_labels, 349 std::vector<base::string16>* autofill_icons, 350 std::vector<int>* autofill_unique_ids) { 351 if (data_list_values_.empty()) 352 return; 353 354 // Insert the separator between the datalist and Autofill values (if there 355 // are any). 356 if (!autofill_values->empty()) { 357 autofill_values->insert(autofill_values->begin(), base::string16()); 358 autofill_labels->insert(autofill_labels->begin(), base::string16()); 359 autofill_icons->insert(autofill_icons->begin(), base::string16()); 360 autofill_unique_ids->insert(autofill_unique_ids->begin(), 361 WebAutofillClient::MenuItemIDSeparator); 362 } 363 364 // Insert the datalist elements. 365 autofill_values->insert(autofill_values->begin(), 366 data_list_values_.begin(), 367 data_list_values_.end()); 368 autofill_labels->insert(autofill_labels->begin(), 369 data_list_labels_.begin(), 370 data_list_labels_.end()); 371 372 // Set the values that all datalist elements share. 373 autofill_icons->insert(autofill_icons->begin(), 374 data_list_values_.size(), 375 base::string16()); 376 autofill_unique_ids->insert(autofill_unique_ids->begin(), 377 data_list_values_.size(), 378 WebAutofillClient::MenuItemIDDataListEntry); 379} 380 381} // namespace autofill 382