| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2012 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/browser/autofill_external_delegate.h" | |
| 6 | |
| 7 #include "base/strings/utf_string_conversions.h" | |
| 8 #include "components/autofill/browser/autocomplete_history_manager.h" | |
| 9 #include "components/autofill/browser/autofill_manager.h" | |
| 10 #include "components/autofill/core/common/autofill_messages.h" | |
| 11 #include "content/public/browser/navigation_controller.h" | |
| 12 #include "content/public/browser/notification_service.h" | |
| 13 #include "content/public/browser/notification_source.h" | |
| 14 #include "content/public/browser/notification_types.h" | |
| 15 #include "content/public/browser/render_view_host.h" | |
| 16 #include "content/public/browser/web_contents.h" | |
| 17 #include "grit/component_strings.h" | |
| 18 #include "third_party/WebKit/Source/WebKit/chromium/public/WebAutofillClient.h" | |
| 19 #include "ui/base/l10n/l10n_util.h" | |
| 20 | |
| 21 #if defined(OS_ANDROID) | |
| 22 #include "content/public/browser/android/content_view_core.h" | |
| 23 #endif | |
| 24 | |
| 25 using content::RenderViewHost; | |
| 26 using WebKit::WebAutofillClient; | |
| 27 | |
| 28 namespace autofill { | |
| 29 | |
| 30 AutofillExternalDelegate::AutofillExternalDelegate( | |
| 31 content::WebContents* web_contents, | |
| 32 AutofillManager* autofill_manager) | |
| 33 : web_contents_(web_contents), | |
| 34 autofill_manager_(autofill_manager), | |
| 35 password_autofill_manager_(web_contents), | |
| 36 autofill_query_id_(0), | |
| 37 display_warning_if_disabled_(false), | |
| 38 has_autofill_suggestion_(false), | |
| 39 has_shown_autofill_popup_for_current_edit_(false), | |
| 40 registered_keyboard_listener_with_(NULL), | |
| 41 weak_ptr_factory_(this) { | |
| 42 DCHECK(autofill_manager); | |
| 43 | |
| 44 registrar_.Add(this, | |
| 45 content::NOTIFICATION_WEB_CONTENTS_VISIBILITY_CHANGED, | |
| 46 content::Source<content::WebContents>(web_contents)); | |
| 47 registrar_.Add( | |
| 48 this, | |
| 49 content::NOTIFICATION_NAV_ENTRY_COMMITTED, | |
| 50 content::Source<content::NavigationController>( | |
| 51 &(web_contents->GetController()))); | |
| 52 } | |
| 53 | |
| 54 AutofillExternalDelegate::~AutofillExternalDelegate() {} | |
| 55 | |
| 56 void AutofillExternalDelegate::OnQuery(int query_id, | |
| 57 const FormData& form, | |
| 58 const FormFieldData& field, | |
| 59 const gfx::RectF& element_bounds, | |
| 60 bool display_warning_if_disabled) { | |
| 61 autofill_query_form_ = form; | |
| 62 autofill_query_field_ = field; | |
| 63 display_warning_if_disabled_ = display_warning_if_disabled; | |
| 64 autofill_query_id_ = query_id; | |
| 65 element_bounds_ = element_bounds; | |
| 66 } | |
| 67 | |
| 68 void AutofillExternalDelegate::OnSuggestionsReturned( | |
| 69 int query_id, | |
| 70 const std::vector<base::string16>& autofill_values, | |
| 71 const std::vector<base::string16>& autofill_labels, | |
| 72 const std::vector<base::string16>& autofill_icons, | |
| 73 const std::vector<int>& autofill_unique_ids) { | |
| 74 if (query_id != autofill_query_id_) | |
| 75 return; | |
| 76 | |
| 77 std::vector<base::string16> values(autofill_values); | |
| 78 std::vector<base::string16> labels(autofill_labels); | |
| 79 std::vector<base::string16> icons(autofill_icons); | |
| 80 std::vector<int> ids(autofill_unique_ids); | |
| 81 | |
| 82 // Add or hide warnings as appropriate. | |
| 83 ApplyAutofillWarnings(&values, &labels, &icons, &ids); | |
| 84 | |
| 85 // Add a separator to go between the values and menu items. | |
| 86 values.push_back(base::string16()); | |
| 87 labels.push_back(base::string16()); | |
| 88 icons.push_back(base::string16()); | |
| 89 ids.push_back(WebAutofillClient::MenuItemIDSeparator); | |
| 90 | |
| 91 // Only include "Autofill Options" special menu item if we have Autofill | |
| 92 // suggestions. | |
| 93 has_autofill_suggestion_ = false; | |
| 94 for (size_t i = 0; i < ids.size(); ++i) { | |
| 95 if (ids[i] > 0) { | |
| 96 has_autofill_suggestion_ = true; | |
| 97 break; | |
| 98 } | |
| 99 } | |
| 100 | |
| 101 if (has_autofill_suggestion_) | |
| 102 ApplyAutofillOptions(&values, &labels, &icons, &ids); | |
| 103 | |
| 104 // Remove the separator if it is the last element. | |
| 105 DCHECK_GT(ids.size(), 0U); | |
| 106 if (ids.back() == WebAutofillClient::MenuItemIDSeparator) { | |
| 107 values.pop_back(); | |
| 108 labels.pop_back(); | |
| 109 icons.pop_back(); | |
| 110 ids.pop_back(); | |
| 111 } | |
| 112 | |
| 113 InsertDataListValues(&values, &labels, &icons, &ids); | |
| 114 | |
| 115 if (values.empty()) { | |
| 116 // No suggestions, any popup currently showing is obsolete. | |
| 117 autofill_manager_->delegate()->HideAutofillPopup(); | |
| 118 return; | |
| 119 } | |
| 120 | |
| 121 // Send to display. | |
| 122 if (autofill_query_field_.is_focusable) { | |
| 123 autofill_manager_->delegate()->ShowAutofillPopup( | |
| 124 element_bounds_, | |
| 125 autofill_query_field_.text_direction, | |
| 126 values, | |
| 127 labels, | |
| 128 icons, | |
| 129 ids, | |
| 130 GetWeakPtr()); | |
| 131 } | |
| 132 } | |
| 133 | |
| 134 void AutofillExternalDelegate::OnShowPasswordSuggestions( | |
| 135 const std::vector<base::string16>& suggestions, | |
| 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 empty, | |
| 154 empty, | |
| 155 password_ids, | |
| 156 GetWeakPtr()); | |
| 157 } | |
| 158 | |
| 159 void AutofillExternalDelegate::SetCurrentDataListValues( | |
| 160 const std::vector<base::string16>& data_list_values, | |
| 161 const std::vector<base::string16>& data_list_labels, | |
| 162 const std::vector<base::string16>& data_list_icons, | |
| 163 const std::vector<int>& data_list_unique_ids) { | |
| 164 data_list_values_ = data_list_values; | |
| 165 data_list_labels_ = data_list_labels; | |
| 166 data_list_icons_ = data_list_icons; | |
| 167 data_list_unique_ids_ = data_list_unique_ids; | |
| 168 } | |
| 169 | |
| 170 void 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 | |
| 182 void AutofillExternalDelegate::OnPopupHidden( | |
| 183 content::KeyboardListener* listener) { | |
| 184 if (registered_keyboard_listener_with_ == web_contents_->GetRenderViewHost()) | |
| 185 web_contents_->GetRenderViewHost()->RemoveKeyboardListener(listener); | |
| 186 | |
| 187 registered_keyboard_listener_with_ = NULL; | |
| 188 } | |
| 189 | |
| 190 void AutofillExternalDelegate::DidSelectSuggestion(int identifier) { | |
| 191 ClearPreviewedForm(); | |
| 192 | |
| 193 // Only preview the data if it is a profile. | |
| 194 if (identifier > 0) | |
| 195 FillAutofillFormData(identifier, true); | |
| 196 } | |
| 197 | |
| 198 void AutofillExternalDelegate::DidAcceptSuggestion(const base::string16& value, | |
| 199 int identifier) { | |
| 200 RenderViewHost* host = web_contents_->GetRenderViewHost(); | |
| 201 | |
| 202 if (identifier == WebAutofillClient::MenuItemIDAutofillOptions) { | |
| 203 // User selected 'Autofill Options'. | |
| 204 autofill_manager_->OnShowAutofillDialog(); | |
| 205 } else if (identifier == WebAutofillClient::MenuItemIDClearForm) { | |
| 206 // User selected 'Clear form'. | |
| 207 host->Send(new AutofillMsg_ClearForm(host->GetRoutingID())); | |
| 208 } else if (identifier == WebAutofillClient::MenuItemIDPasswordEntry) { | |
| 209 bool success = password_autofill_manager_.DidAcceptAutofillSuggestion( | |
| 210 autofill_query_field_, value); | |
| 211 DCHECK(success); | |
| 212 } else if (identifier == WebAutofillClient::MenuItemIDDataListEntry) { | |
| 213 host->Send(new AutofillMsg_AcceptDataListSuggestion(host->GetRoutingID(), | |
| 214 value)); | |
| 215 } else if (identifier == WebAutofillClient::MenuItemIDAutocompleteEntry) { | |
| 216 // User selected an Autocomplete, so we fill directly. | |
| 217 host->Send(new AutofillMsg_SetNodeText(host->GetRoutingID(), value)); | |
| 218 } else { | |
| 219 FillAutofillFormData(identifier, false); | |
| 220 } | |
| 221 | |
| 222 autofill_manager_->delegate()->HideAutofillPopup(); | |
| 223 } | |
| 224 | |
| 225 void AutofillExternalDelegate::RemoveSuggestion(const base::string16& value, | |
| 226 int identifier) { | |
| 227 if (identifier > 0) { | |
| 228 autofill_manager_->RemoveAutofillProfileOrCreditCard(identifier); | |
| 229 } else { | |
| 230 autofill_manager_->RemoveAutocompleteEntry(autofill_query_field_.name, | |
| 231 value); | |
| 232 } | |
| 233 } | |
| 234 | |
| 235 void AutofillExternalDelegate::DidEndTextFieldEditing() { | |
| 236 autofill_manager_->delegate()->HideAutofillPopup(); | |
| 237 | |
| 238 has_shown_autofill_popup_for_current_edit_ = false; | |
| 239 } | |
| 240 | |
| 241 void AutofillExternalDelegate::ClearPreviewedForm() { | |
| 242 RenderViewHost* host = web_contents_->GetRenderViewHost(); | |
| 243 if (host) | |
| 244 host->Send(new AutofillMsg_ClearPreviewedForm(host->GetRoutingID())); | |
| 245 } | |
| 246 | |
| 247 void AutofillExternalDelegate::Reset() { | |
| 248 autofill_manager_->delegate()->HideAutofillPopup(); | |
| 249 | |
| 250 password_autofill_manager_.Reset(); | |
| 251 } | |
| 252 | |
| 253 void AutofillExternalDelegate::AddPasswordFormMapping( | |
| 254 const FormFieldData& form, | |
| 255 const PasswordFormFillData& fill_data) { | |
| 256 password_autofill_manager_.AddPasswordFormMapping(form, fill_data); | |
| 257 } | |
| 258 | |
| 259 base::WeakPtr<AutofillExternalDelegate> AutofillExternalDelegate::GetWeakPtr() { | |
| 260 return weak_ptr_factory_.GetWeakPtr(); | |
| 261 } | |
| 262 | |
| 263 void AutofillExternalDelegate::FillAutofillFormData(int unique_id, | |
| 264 bool is_preview) { | |
| 265 // If the selected element is a warning we don't want to do anything. | |
| 266 if (unique_id == WebAutofillClient::MenuItemIDWarningMessage) | |
| 267 return; | |
| 268 | |
| 269 RenderViewHost* host = web_contents_->GetRenderViewHost(); | |
| 270 | |
| 271 if (is_preview) { | |
| 272 host->Send(new AutofillMsg_SetAutofillActionPreview( | |
| 273 host->GetRoutingID())); | |
| 274 } else { | |
| 275 host->Send(new AutofillMsg_SetAutofillActionFill( | |
| 276 host->GetRoutingID())); | |
| 277 } | |
| 278 | |
| 279 // Fill the values for the whole form. | |
| 280 autofill_manager_->OnFillAutofillFormData(autofill_query_id_, | |
| 281 autofill_query_form_, | |
| 282 autofill_query_field_, | |
| 283 unique_id); | |
| 284 } | |
| 285 | |
| 286 void AutofillExternalDelegate::ApplyAutofillWarnings( | |
| 287 std::vector<base::string16>* autofill_values, | |
| 288 std::vector<base::string16>* autofill_labels, | |
| 289 std::vector<base::string16>* autofill_icons, | |
| 290 std::vector<int>* autofill_unique_ids) { | |
| 291 if (!autofill_query_field_.should_autocomplete) { | |
| 292 // If autofill is disabled and we had suggestions, show a warning instead. | |
| 293 autofill_values->assign( | |
| 294 1, l10n_util::GetStringUTF16(IDS_AUTOFILL_WARNING_FORM_DISABLED)); | |
| 295 autofill_labels->assign(1, base::string16()); | |
| 296 autofill_icons->assign(1, base::string16()); | |
| 297 autofill_unique_ids->assign(1, WebAutofillClient::MenuItemIDWarningMessage); | |
| 298 } else if (autofill_unique_ids->size() > 1 && | |
| 299 (*autofill_unique_ids)[0] == | |
| 300 WebAutofillClient::MenuItemIDWarningMessage) { | |
| 301 // If we received a warning instead of suggestions from autofill but regular | |
| 302 // suggestions from autocomplete, don't show the autofill warning. | |
| 303 autofill_values->erase(autofill_values->begin()); | |
| 304 autofill_labels->erase(autofill_labels->begin()); | |
| 305 autofill_icons->erase(autofill_icons->begin()); | |
| 306 autofill_unique_ids->erase(autofill_unique_ids->begin()); | |
| 307 } | |
| 308 | |
| 309 // If we were about to show a warning and we shouldn't, don't. | |
| 310 if (!autofill_unique_ids->empty() && | |
| 311 (*autofill_unique_ids)[0] == | |
| 312 WebAutofillClient::MenuItemIDWarningMessage && | |
| 313 !display_warning_if_disabled_) { | |
| 314 autofill_values->clear(); | |
| 315 autofill_labels->clear(); | |
| 316 autofill_icons->clear(); | |
| 317 autofill_unique_ids->clear(); | |
| 318 } | |
| 319 } | |
| 320 | |
| 321 void AutofillExternalDelegate::ApplyAutofillOptions( | |
| 322 std::vector<base::string16>* autofill_values, | |
| 323 std::vector<base::string16>* autofill_labels, | |
| 324 std::vector<base::string16>* autofill_icons, | |
| 325 std::vector<int>* autofill_unique_ids) { | |
| 326 // The form has been auto-filled, so give the user the chance to clear the | |
| 327 // form. Append the 'Clear form' menu item. | |
| 328 if (autofill_query_field_.is_autofilled) { | |
| 329 autofill_values->push_back( | |
| 330 l10n_util::GetStringUTF16(IDS_AUTOFILL_CLEAR_FORM_MENU_ITEM)); | |
| 331 autofill_labels->push_back(base::string16()); | |
| 332 autofill_icons->push_back(base::string16()); | |
| 333 autofill_unique_ids->push_back(WebAutofillClient::MenuItemIDClearForm); | |
| 334 } | |
| 335 | |
| 336 // Append the 'Chrome Autofill options' menu item; | |
| 337 autofill_values->push_back( | |
| 338 l10n_util::GetStringUTF16(IDS_AUTOFILL_OPTIONS_POPUP)); | |
| 339 autofill_labels->push_back(base::string16()); | |
| 340 autofill_icons->push_back(base::string16()); | |
| 341 autofill_unique_ids->push_back(WebAutofillClient::MenuItemIDAutofillOptions); | |
| 342 } | |
| 343 | |
| 344 void AutofillExternalDelegate::InsertDataListValues( | |
| 345 std::vector<base::string16>* autofill_values, | |
| 346 std::vector<base::string16>* autofill_labels, | |
| 347 std::vector<base::string16>* autofill_icons, | |
| 348 std::vector<int>* autofill_unique_ids) { | |
| 349 if (data_list_values_.empty()) | |
| 350 return; | |
| 351 | |
| 352 // Insert the separator between the datalist and Autofill values (if there | |
| 353 // are any). | |
| 354 if (!autofill_values->empty()) { | |
| 355 autofill_values->insert(autofill_values->begin(), base::string16()); | |
| 356 autofill_labels->insert(autofill_labels->begin(), base::string16()); | |
| 357 autofill_icons->insert(autofill_icons->begin(), base::string16()); | |
| 358 autofill_unique_ids->insert(autofill_unique_ids->begin(), | |
| 359 WebAutofillClient::MenuItemIDSeparator); | |
| 360 } | |
| 361 | |
| 362 // Insert the datalist elements. | |
| 363 autofill_values->insert(autofill_values->begin(), | |
| 364 data_list_values_.begin(), | |
| 365 data_list_values_.end()); | |
| 366 autofill_labels->insert(autofill_labels->begin(), | |
| 367 data_list_labels_.begin(), | |
| 368 data_list_labels_.end()); | |
| 369 autofill_icons->insert(autofill_icons->begin(), | |
| 370 data_list_icons_.begin(), | |
| 371 data_list_icons_.end()); | |
| 372 autofill_unique_ids->insert(autofill_unique_ids->begin(), | |
| 373 data_list_unique_ids_.begin(), | |
| 374 data_list_unique_ids_.end()); | |
| 375 } | |
| 376 | |
| 377 void AutofillExternalDelegate::Observe( | |
| 378 int type, | |
| 379 const content::NotificationSource& source, | |
| 380 const content::NotificationDetails& details) { | |
| 381 if (type == content::NOTIFICATION_WEB_CONTENTS_VISIBILITY_CHANGED) { | |
| 382 if (!*content::Details<bool>(details).ptr()) | |
| 383 autofill_manager_->delegate()->HideAutofillPopup(); | |
| 384 } else if (type == content::NOTIFICATION_NAV_ENTRY_COMMITTED) { | |
| 385 autofill_manager_->delegate()->HideAutofillPopup(); | |
| 386 } else { | |
| 387 NOTREACHED(); | |
| 388 } | |
| 389 } | |
| 390 | |
| 391 } // namespace autofill | |
| OLD | NEW |