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