blob: 95119bfad9940cee34276ce2e72985039e10e870 [file] [log] [blame]
// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/autofill/core/browser/autofill_external_delegate.h"
#include "base/strings/utf_string_conversions.h"
#include "components/autofill/core/browser/autocomplete_history_manager.h"
#include "components/autofill/core/browser/autofill_driver.h"
#include "components/autofill/core/browser/autofill_manager.h"
#include "components/autofill/core/common/autofill_messages.h"
#include "content/public/browser/render_view_host.h"
#include "content/public/browser/web_contents.h"
#include "grit/component_strings.h"
#include "third_party/WebKit/public/web/WebAutofillClient.h"
#include "ui/base/l10n/l10n_util.h"
#if defined(OS_ANDROID)
#include "content/public/browser/android/content_view_core.h"
#endif
using content::RenderViewHost;
using WebKit::WebAutofillClient;
namespace autofill {
AutofillExternalDelegate::AutofillExternalDelegate(
content::WebContents* web_contents,
AutofillManager* autofill_manager,
AutofillDriver* autofill_driver)
: web_contents_(web_contents),
autofill_manager_(autofill_manager),
autofill_driver_(autofill_driver),
password_autofill_manager_(web_contents),
autofill_query_id_(0),
display_warning_if_disabled_(false),
has_autofill_suggestion_(false),
has_shown_autofill_popup_for_current_edit_(false),
registered_keyboard_listener_with_(NULL),
weak_ptr_factory_(this) {
DCHECK(autofill_manager);
}
AutofillExternalDelegate::~AutofillExternalDelegate() {}
void AutofillExternalDelegate::OnQuery(int query_id,
const FormData& form,
const FormFieldData& field,
const gfx::RectF& element_bounds,
bool display_warning_if_disabled) {
autofill_query_form_ = form;
autofill_query_field_ = field;
display_warning_if_disabled_ = display_warning_if_disabled;
autofill_query_id_ = query_id;
element_bounds_ = element_bounds;
}
void AutofillExternalDelegate::OnSuggestionsReturned(
int query_id,
const std::vector<base::string16>& autofill_values,
const std::vector<base::string16>& autofill_labels,
const std::vector<base::string16>& autofill_icons,
const std::vector<int>& autofill_unique_ids) {
if (query_id != autofill_query_id_)
return;
std::vector<base::string16> values(autofill_values);
std::vector<base::string16> labels(autofill_labels);
std::vector<base::string16> icons(autofill_icons);
std::vector<int> ids(autofill_unique_ids);
// Add or hide warnings as appropriate.
ApplyAutofillWarnings(&values, &labels, &icons, &ids);
// Add a separator to go between the values and menu items.
values.push_back(base::string16());
labels.push_back(base::string16());
icons.push_back(base::string16());
ids.push_back(WebAutofillClient::MenuItemIDSeparator);
// Only include "Autofill Options" special menu item if we have Autofill
// suggestions.
has_autofill_suggestion_ = false;
for (size_t i = 0; i < ids.size(); ++i) {
if (ids[i] > 0) {
has_autofill_suggestion_ = true;
break;
}
}
if (has_autofill_suggestion_)
ApplyAutofillOptions(&values, &labels, &icons, &ids);
// Remove the separator if it is the last element.
DCHECK_GT(ids.size(), 0U);
if (ids.back() == WebAutofillClient::MenuItemIDSeparator) {
values.pop_back();
labels.pop_back();
icons.pop_back();
ids.pop_back();
}
// If anything else is added to modify the values after inserting the data
// list, AutofillPopupControllerImpl::UpdateDataListValues will need to be
// updated to match.
InsertDataListValues(&values, &labels, &icons, &ids);
if (values.empty()) {
// No suggestions, any popup currently showing is obsolete.
autofill_manager_->delegate()->HideAutofillPopup();
return;
}
// Send to display.
if (autofill_query_field_.is_focusable) {
autofill_manager_->delegate()->ShowAutofillPopup(
element_bounds_,
autofill_query_field_.text_direction,
values,
labels,
icons,
ids,
GetWeakPtr());
}
}
void AutofillExternalDelegate::OnShowPasswordSuggestions(
const std::vector<base::string16>& suggestions,
const std::vector<base::string16>& realms,
const FormFieldData& field,
const gfx::RectF& element_bounds) {
autofill_query_field_ = field;
element_bounds_ = element_bounds;
if (suggestions.empty()) {
autofill_manager_->delegate()->HideAutofillPopup();
return;
}
std::vector<base::string16> empty(suggestions.size());
std::vector<int> password_ids(suggestions.size(),
WebAutofillClient::MenuItemIDPasswordEntry);
autofill_manager_->delegate()->ShowAutofillPopup(
element_bounds_,
autofill_query_field_.text_direction,
suggestions,
realms,
empty,
password_ids,
GetWeakPtr());
}
void AutofillExternalDelegate::SetCurrentDataListValues(
const std::vector<base::string16>& data_list_values,
const std::vector<base::string16>& data_list_labels) {
data_list_values_ = data_list_values;
data_list_labels_ = data_list_labels;
autofill_manager_->delegate()->UpdateAutofillPopupDataListValues(
data_list_values,
data_list_labels);
}
void AutofillExternalDelegate::OnPopupShown(
content::KeyboardListener* listener) {
if (!registered_keyboard_listener_with_) {
registered_keyboard_listener_with_ = web_contents_->GetRenderViewHost();
registered_keyboard_listener_with_->AddKeyboardListener(listener);
}
autofill_manager_->OnDidShowAutofillSuggestions(
has_autofill_suggestion_ && !has_shown_autofill_popup_for_current_edit_);
has_shown_autofill_popup_for_current_edit_ |= has_autofill_suggestion_;
}
void AutofillExternalDelegate::OnPopupHidden(
content::KeyboardListener* listener) {
if ((!web_contents_->IsBeingDestroyed()) &&
(registered_keyboard_listener_with_ ==
web_contents_->GetRenderViewHost())) {
web_contents_->GetRenderViewHost()->RemoveKeyboardListener(listener);
}
registered_keyboard_listener_with_ = NULL;
}
void AutofillExternalDelegate::DidSelectSuggestion(int identifier) {
ClearPreviewedForm();
// Only preview the data if it is a profile.
if (identifier > 0)
FillAutofillFormData(identifier, true);
}
void AutofillExternalDelegate::DidAcceptSuggestion(const base::string16& value,
int identifier) {
RenderViewHost* host = web_contents_->GetRenderViewHost();
if (identifier == WebAutofillClient::MenuItemIDAutofillOptions) {
// User selected 'Autofill Options'.
autofill_manager_->OnShowAutofillDialog();
} else if (identifier == WebAutofillClient::MenuItemIDClearForm) {
// User selected 'Clear form'.
autofill_driver_->RendererShouldClearFilledForm();
} else if (identifier == WebAutofillClient::MenuItemIDPasswordEntry) {
bool success = password_autofill_manager_.DidAcceptAutofillSuggestion(
autofill_query_field_, value);
DCHECK(success);
} else if (identifier == WebAutofillClient::MenuItemIDDataListEntry) {
host->Send(new AutofillMsg_AcceptDataListSuggestion(host->GetRoutingID(),
value));
} else if (identifier == WebAutofillClient::MenuItemIDAutocompleteEntry) {
// User selected an Autocomplete, so we fill directly.
host->Send(new AutofillMsg_SetNodeText(host->GetRoutingID(), value));
} else {
FillAutofillFormData(identifier, false);
}
autofill_manager_->delegate()->HideAutofillPopup();
}
void AutofillExternalDelegate::RemoveSuggestion(const base::string16& value,
int identifier) {
if (identifier > 0) {
autofill_manager_->RemoveAutofillProfileOrCreditCard(identifier);
} else {
autofill_manager_->RemoveAutocompleteEntry(autofill_query_field_.name,
value);
}
}
void AutofillExternalDelegate::DidEndTextFieldEditing() {
autofill_manager_->delegate()->HideAutofillPopup();
has_shown_autofill_popup_for_current_edit_ = false;
}
void AutofillExternalDelegate::ClearPreviewedForm() {
autofill_driver_->RendererShouldClearPreviewedForm();
}
void AutofillExternalDelegate::Reset() {
autofill_manager_->delegate()->HideAutofillPopup();
password_autofill_manager_.Reset();
}
void AutofillExternalDelegate::AddPasswordFormMapping(
const FormFieldData& form,
const PasswordFormFillData& fill_data) {
password_autofill_manager_.AddPasswordFormMapping(form, fill_data);
}
base::WeakPtr<AutofillExternalDelegate> AutofillExternalDelegate::GetWeakPtr() {
return weak_ptr_factory_.GetWeakPtr();
}
void AutofillExternalDelegate::FillAutofillFormData(int unique_id,
bool is_preview) {
// If the selected element is a warning we don't want to do anything.
if (unique_id == WebAutofillClient::MenuItemIDWarningMessage)
return;
AutofillDriver::RendererFormDataAction renderer_action = is_preview ?
AutofillDriver::FORM_DATA_ACTION_PREVIEW :
AutofillDriver::FORM_DATA_ACTION_FILL;
DCHECK(autofill_driver_->RendererIsAvailable());
autofill_driver_->SetRendererActionOnFormDataReception(renderer_action);
// Fill the values for the whole form.
autofill_manager_->OnFillAutofillFormData(autofill_query_id_,
autofill_query_form_,
autofill_query_field_,
unique_id);
}
void AutofillExternalDelegate::ApplyAutofillWarnings(
std::vector<base::string16>* autofill_values,
std::vector<base::string16>* autofill_labels,
std::vector<base::string16>* autofill_icons,
std::vector<int>* autofill_unique_ids) {
if (!autofill_query_field_.should_autocomplete) {
// Autofill is disabled. If there were some profile or credit card
// suggestions to show, show a warning instead. Otherwise, clear out the
// list of suggestions.
if (!autofill_unique_ids->empty() && (*autofill_unique_ids)[0] > 0) {
// If autofill is disabled and we had suggestions, show a warning instead.
autofill_values->assign(
1, l10n_util::GetStringUTF16(IDS_AUTOFILL_WARNING_FORM_DISABLED));
autofill_labels->assign(1, base::string16());
autofill_icons->assign(1, base::string16());
autofill_unique_ids->assign(1,
WebAutofillClient::MenuItemIDWarningMessage);
} else {
autofill_values->clear();
autofill_labels->clear();
autofill_icons->clear();
autofill_unique_ids->clear();
}
} else if (autofill_unique_ids->size() > 1 &&
(*autofill_unique_ids)[0] ==
WebAutofillClient::MenuItemIDWarningMessage) {
// If we received a warning instead of suggestions from autofill but regular
// suggestions from autocomplete, don't show the autofill warning.
autofill_values->erase(autofill_values->begin());
autofill_labels->erase(autofill_labels->begin());
autofill_icons->erase(autofill_icons->begin());
autofill_unique_ids->erase(autofill_unique_ids->begin());
}
// If we were about to show a warning and we shouldn't, don't.
if (!autofill_unique_ids->empty() &&
(*autofill_unique_ids)[0] ==
WebAutofillClient::MenuItemIDWarningMessage &&
!display_warning_if_disabled_) {
autofill_values->clear();
autofill_labels->clear();
autofill_icons->clear();
autofill_unique_ids->clear();
}
}
void AutofillExternalDelegate::ApplyAutofillOptions(
std::vector<base::string16>* autofill_values,
std::vector<base::string16>* autofill_labels,
std::vector<base::string16>* autofill_icons,
std::vector<int>* autofill_unique_ids) {
// The form has been auto-filled, so give the user the chance to clear the
// form. Append the 'Clear form' menu item.
if (autofill_query_field_.is_autofilled) {
autofill_values->push_back(
l10n_util::GetStringUTF16(IDS_AUTOFILL_CLEAR_FORM_MENU_ITEM));
autofill_labels->push_back(base::string16());
autofill_icons->push_back(base::string16());
autofill_unique_ids->push_back(WebAutofillClient::MenuItemIDClearForm);
}
// Append the 'Chrome Autofill options' menu item;
autofill_values->push_back(
l10n_util::GetStringUTF16(IDS_AUTOFILL_OPTIONS_POPUP));
autofill_labels->push_back(base::string16());
autofill_icons->push_back(base::string16());
autofill_unique_ids->push_back(WebAutofillClient::MenuItemIDAutofillOptions);
}
void AutofillExternalDelegate::InsertDataListValues(
std::vector<base::string16>* autofill_values,
std::vector<base::string16>* autofill_labels,
std::vector<base::string16>* autofill_icons,
std::vector<int>* autofill_unique_ids) {
if (data_list_values_.empty())
return;
// Insert the separator between the datalist and Autofill values (if there
// are any).
if (!autofill_values->empty()) {
autofill_values->insert(autofill_values->begin(), base::string16());
autofill_labels->insert(autofill_labels->begin(), base::string16());
autofill_icons->insert(autofill_icons->begin(), base::string16());
autofill_unique_ids->insert(autofill_unique_ids->begin(),
WebAutofillClient::MenuItemIDSeparator);
}
// Insert the datalist elements.
autofill_values->insert(autofill_values->begin(),
data_list_values_.begin(),
data_list_values_.end());
autofill_labels->insert(autofill_labels->begin(),
data_list_labels_.begin(),
data_list_labels_.end());
// Set the values that all datalist elements share.
autofill_icons->insert(autofill_icons->begin(),
data_list_values_.size(),
base::string16());
autofill_unique_ids->insert(autofill_unique_ids->begin(),
data_list_values_.size(),
WebAutofillClient::MenuItemIDDataListEntry);
}
} // namespace autofill