Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(465)

Unified Diff: chrome/browser/ui/autofill/autofill_dialog_controller_impl.cc

Issue 1931043002: Remove requestAutocomplete (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: rebase Created 4 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: chrome/browser/ui/autofill/autofill_dialog_controller_impl.cc
diff --git a/chrome/browser/ui/autofill/autofill_dialog_controller_impl.cc b/chrome/browser/ui/autofill/autofill_dialog_controller_impl.cc
deleted file mode 100644
index 45dd681729d8a80983f7cb781e44400b41e2285f..0000000000000000000000000000000000000000
--- a/chrome/browser/ui/autofill/autofill_dialog_controller_impl.cc
+++ /dev/null
@@ -1,2271 +0,0 @@
-// 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 "chrome/browser/ui/autofill/autofill_dialog_controller_impl.h"
-
-#include <algorithm>
-#include <map>
-#include <string>
-#include <utility>
-
-#include "base/bind.h"
-#include "base/bind_helpers.h"
-#include "base/i18n/case_conversion.h"
-#include "base/i18n/rtl.h"
-#include "base/location.h"
-#include "base/logging.h"
-#include "base/macros.h"
-#include "base/rand_util.h"
-#include "base/single_thread_task_runner.h"
-#include "base/strings/string_number_conversions.h"
-#include "base/strings/string_split.h"
-#include "base/strings/stringprintf.h"
-#include "base/strings/utf_string_conversions.h"
-#include "base/thread_task_runner_handle.h"
-#include "base/time/time.h"
-#include "chrome/browser/autofill/personal_data_manager_factory.h"
-#include "chrome/browser/autofill/risk_util.h"
-#include "chrome/browser/autofill/validation_rules_storage_factory.h"
-#include "chrome/browser/browser_process.h"
-#include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/ui/autofill/autofill_dialog_common.h"
-#include "chrome/browser/ui/autofill/autofill_dialog_i18n_input.h"
-#include "chrome/browser/ui/autofill/autofill_dialog_view.h"
-#include "chrome/browser/ui/autofill/data_model_wrapper.h"
-#include "chrome/browser/ui/browser.h"
-#include "chrome/browser/ui/browser_finder.h"
-#include "chrome/browser/ui/browser_navigator.h"
-#include "chrome/browser/ui/browser_navigator_params.h"
-#include "chrome/browser/ui/browser_window.h"
-#include "chrome/common/pref_names.h"
-#include "chrome/common/url_constants.h"
-#include "chrome/grit/chromium_strings.h"
-#include "chrome/grit/generated_resources.h"
-#include "components/autofill/core/browser/address_i18n.h"
-#include "components/autofill/core/browser/autofill_country.h"
-#include "components/autofill/core/browser/autofill_data_model.h"
-#include "components/autofill/core/browser/autofill_manager.h"
-#include "components/autofill/core/browser/autofill_type.h"
-#include "components/autofill/core/browser/country_names.h"
-#include "components/autofill/core/browser/detail_input.h"
-#include "components/autofill/core/browser/field_types.h"
-#include "components/autofill/core/browser/personal_data_manager.h"
-#include "components/autofill/core/browser/phone_number_i18n.h"
-#include "components/autofill/core/browser/server_field_types_util.h"
-#include "components/autofill/core/browser/validation.h"
-#include "components/autofill/core/common/autofill_pref_names.h"
-#include "components/autofill/core/common/form_data.h"
-#include "components/pref_registry/pref_registry_syncable.h"
-#include "components/prefs/pref_registry_simple.h"
-#include "components/prefs/pref_service.h"
-#include "components/prefs/scoped_user_pref_update.h"
-#include "content/public/browser/browser_thread.h"
-#include "content/public/browser/geolocation_provider.h"
-#include "content/public/browser/navigation_controller.h"
-#include "content/public/browser/navigation_details.h"
-#include "content/public/browser/navigation_entry.h"
-#include "content/public/browser/notification_service.h"
-#include "content/public/browser/notification_types.h"
-#include "content/public/browser/render_view_host.h"
-#include "content/public/browser/web_contents.h"
-#include "content/public/common/url_constants.h"
-#include "grit/components_scaled_resources.h"
-#include "grit/components_strings.h"
-#include "grit/platform_locale_settings.h"
-#include "grit/theme_resources.h"
-#include "net/cert/cert_status_flags.h"
-#include "third_party/libaddressinput/chromium/chrome_metadata_source.h"
-#include "third_party/libaddressinput/chromium/chrome_storage_impl.h"
-#include "third_party/libaddressinput/messages.h"
-#include "third_party/libaddressinput/src/cpp/include/libaddressinput/address_data.h"
-#include "third_party/libaddressinput/src/cpp/include/libaddressinput/address_field.h"
-#include "third_party/libaddressinput/src/cpp/include/libaddressinput/address_problem.h"
-#include "third_party/libaddressinput/src/cpp/include/libaddressinput/localization.h"
-#include "ui/base/l10n/l10n_util.h"
-#include "ui/base/models/combobox_model.h"
-#include "ui/base/resource/resource_bundle.h"
-#include "ui/gfx/canvas.h"
-#include "ui/gfx/geometry/vector2d.h"
-#include "ui/gfx/image/image_skia_operations.h"
-#include "ui/gfx/skia_util.h"
-
-using ::i18n::addressinput::AddressData;
-using ::i18n::addressinput::AddressField;
-using ::i18n::addressinput::AddressProblem;
-using ::i18n::addressinput::ADMIN_AREA;
-using ::i18n::addressinput::DEPENDENT_LOCALITY;
-using ::i18n::addressinput::FieldProblemMap;
-using ::i18n::addressinput::Localization;
-using ::i18n::addressinput::MISSING_REQUIRED_FIELD;
-
-namespace autofill {
-
-namespace {
-
-const char kAddNewItemKey[] = "add-new-item";
-const char kManageItemsKey[] = "manage-items";
-const char kSameAsBillingKey[] = "same-as-billing";
-
-// Keys for the kAutofillDialogAutofillDefault pref dictionary (do not change
-// these values).
-const char kGuidPrefKey[] = "guid";
-
-// This string is stored along with saved addresses and credit cards in the
-// WebDB, and hence should not be modified, so that it remains consistent over
-// time.
-const char kAutofillDialogOrigin[] = "Chrome Autofill dialog";
-
-// The number of milliseconds to delay enabling the submit button after showing
-// the dialog. This delay prevents users from accidentally clicking the submit
-// button on startup.
-const int kSubmitButtonDelayMs = 1000;
-
-// A helper class to make sure an AutofillDialogView knows when a series of
-// updates is incoming.
-class ScopedViewUpdates {
- public:
- explicit ScopedViewUpdates(AutofillDialogView* view) : view_(view) {
- if (view_)
- view_->UpdatesStarted();
- }
-
- ~ScopedViewUpdates() {
- if (view_)
- view_->UpdatesFinished();
- }
-
- private:
- AutofillDialogView* view_;
-
- DISALLOW_COPY_AND_ASSIGN(ScopedViewUpdates);
-};
-
-base::string16 NullGetInfo(const AutofillType& type) {
- return base::string16();
-}
-
-// Extract |type| from |inputs| using |section| to determine whether the info
-// should be billing or shipping specific (for sections with address info).
-base::string16 GetInfoFromInputs(const FieldValueMap& inputs,
- DialogSection section,
- const AutofillType& type) {
- ServerFieldType field_type = type.GetStorableType();
- if (section != SECTION_SHIPPING)
- field_type = AutofillType::GetEquivalentBillingFieldType(field_type);
-
- base::string16 info;
- FieldValueMap::const_iterator it = inputs.find(field_type);
- if (it != inputs.end())
- info = it->second;
-
- if (!info.empty() && type.html_type() == HTML_TYPE_COUNTRY_CODE) {
- info =
- base::ASCIIToUTF16(CountryNames::GetInstance()->GetCountryCode(info));
- }
-
- return info;
-}
-
-// Returns true if |input| should be used to fill a site-requested |field| which
-// is notated with a "shipping" tag, for use when the user has decided to use
-// the billing address as the shipping address.
-bool ServerTypeMatchesShippingField(ServerFieldType type,
- const AutofillField& field) {
- // Equivalent billing field type is used to support UseBillingAsShipping
- // usecase.
- return ServerTypeEncompassesFieldType(
- type, AutofillType(AutofillType::GetEquivalentBillingFieldType(
- field.Type().GetStorableType())));
-}
-
-// Initializes |form_group| from user-entered data.
-void FillFormGroupFromOutputs(const FieldValueMap& detail_outputs,
- FormGroup* form_group) {
- for (FieldValueMap::const_iterator iter = detail_outputs.begin();
- iter != detail_outputs.end(); ++iter) {
- ServerFieldType type = iter->first;
- if (!iter->second.empty()) {
- form_group->SetInfo(AutofillType(type),
- iter->second,
- g_browser_process->GetApplicationLocale());
- }
- }
-}
-
-// Returns a string descriptor for a DialogSection, for use with prefs (do not
-// change these values).
-std::string SectionToPrefString(DialogSection section) {
- switch (section) {
- case SECTION_CC:
- return "cc";
-
- case SECTION_BILLING:
- return "billing";
-
- case SECTION_SHIPPING:
- return "shipping";
- }
-
- NOTREACHED();
- return std::string();
-}
-
-gfx::Image CreditCardIconForType(const std::string& credit_card_type) {
- const int input_card_idr = CreditCard::IconResourceId(credit_card_type);
- ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
- if (input_card_idr == IDR_AUTOFILL_CC_GENERIC) {
- // When the credit card type is unknown, no image should be shown. However,
- // to simplify the view code on Mac, save space for the credit card image by
- // returning a transparent image of the appropriate size. All credit card
- // icons are the same size.
- return gfx::Image(gfx::ImageSkiaOperations::CreateTransparentImage(
- rb.GetImageNamed(IDR_AUTOFILL_CC_GENERIC).AsImageSkia(), 0));
- }
- return rb.GetImageNamed(input_card_idr);
-}
-
-gfx::Image CvcIconForCreditCardType(const base::string16& credit_card_type) {
- ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
- if (credit_card_type == l10n_util::GetStringUTF16(IDS_AUTOFILL_CC_AMEX))
- return rb.GetImageNamed(IDR_CREDIT_CARD_CVC_HINT_AMEX);
-
- return rb.GetImageNamed(IDR_CREDIT_CARD_CVC_HINT);
-}
-
-ServerFieldType CountryTypeForSection(DialogSection section) {
- return section == SECTION_SHIPPING ? ADDRESS_HOME_COUNTRY :
- ADDRESS_BILLING_COUNTRY;
-}
-
-ValidityMessage GetPhoneValidityMessage(const base::string16& country_name,
- const base::string16& number) {
- std::string region =
- CountryNames::GetInstance()->GetCountryCode(country_name);
- i18n::PhoneObject phone_object(number, region);
- ValidityMessage phone_message(base::string16(), true);
-
- // Check if the phone number is invalid. Allow valid international
- // numbers that don't match the address's country only if they have an
- // international calling code.
- if (!phone_object.IsValidNumber() ||
- (phone_object.country_code().empty() &&
- phone_object.region() != region)) {
- phone_message.text = l10n_util::GetStringUTF16(
- IDS_AUTOFILL_DIALOG_VALIDATION_INVALID_PHONE_NUMBER);
- }
-
- return phone_message;
-}
-
-// Constructs |inputs| from template data for a given |dialog_section|.
-// |country_country| specifies the country code that the inputs should be built
-// for. Sets the |language_code| to be used for address formatting, if
-// internationalized address input is enabled. The |language_code| parameter can
-// be NULL.
-void BuildInputsForSection(DialogSection dialog_section,
- const std::string& country_code,
- DetailInputs* inputs,
- std::string* language_code) {
- using l10n_util::GetStringUTF16;
-
- const DetailInput kCCInputs[] = {
- { DetailInput::LONG,
- CREDIT_CARD_NUMBER,
- GetStringUTF16(IDS_AUTOFILL_DIALOG_PLACEHOLDER_CARD_NUMBER) },
- { DetailInput::SHORT,
- CREDIT_CARD_EXP_MONTH,
- GetStringUTF16(IDS_AUTOFILL_DIALOG_PLACEHOLDER_EXPIRY_MONTH) },
- { DetailInput::SHORT,
- CREDIT_CARD_EXP_4_DIGIT_YEAR,
- GetStringUTF16(IDS_AUTOFILL_DIALOG_PLACEHOLDER_EXPIRY_YEAR) },
- { DetailInput::SHORT_EOL,
- CREDIT_CARD_VERIFICATION_CODE,
- GetStringUTF16(IDS_AUTOFILL_DIALOG_PLACEHOLDER_CVC),
- 1.5 },
- };
-
- const DetailInput kBillingPhoneInputs[] = {
- { DetailInput::LONG,
- PHONE_BILLING_WHOLE_NUMBER,
- GetStringUTF16(IDS_AUTOFILL_DIALOG_PLACEHOLDER_PHONE_NUMBER) },
- };
-
- const DetailInput kEmailInputs[] = {
- { DetailInput::LONG,
- EMAIL_ADDRESS,
- GetStringUTF16(IDS_AUTOFILL_DIALOG_PLACEHOLDER_EMAIL) },
- };
-
- const DetailInput kShippingPhoneInputs[] = {
- { DetailInput::LONG,
- PHONE_HOME_WHOLE_NUMBER,
- GetStringUTF16(IDS_AUTOFILL_DIALOG_PLACEHOLDER_PHONE_NUMBER) },
- };
-
- switch (dialog_section) {
- case SECTION_CC: {
- BuildInputs(kCCInputs, arraysize(kCCInputs), inputs);
- break;
- }
-
- case SECTION_BILLING: {
- i18ninput::BuildAddressInputs(common::ADDRESS_TYPE_BILLING,
- country_code, inputs, language_code);
- BuildInputs(kBillingPhoneInputs, arraysize(kBillingPhoneInputs), inputs);
- BuildInputs(kEmailInputs, arraysize(kEmailInputs), inputs);
- break;
- }
-
- case SECTION_SHIPPING: {
- i18ninput::BuildAddressInputs(common::ADDRESS_TYPE_SHIPPING,
- country_code, inputs, language_code);
- BuildInputs(kShippingPhoneInputs, arraysize(kShippingPhoneInputs),
- inputs);
- break;
- }
- }
-}
-
-} // namespace
-
-AutofillDialogViewDelegate::~AutofillDialogViewDelegate() {}
-
-AutofillDialogControllerImpl::~AutofillDialogControllerImpl() {
- if (popup_controller_)
- popup_controller_->Hide();
-
- AutofillMetrics::LogDialogInitialUserState(initial_user_state_);
-}
-
-// Checks the country code against the values the form structure enumerates.
-bool AutofillCountryFilter(
- const std::set<base::string16>& form_structure_values,
- const std::string& country_code) {
- if (!form_structure_values.empty() &&
- !form_structure_values.count(base::ASCIIToUTF16(country_code))) {
- return false;
- }
-
- return true;
-}
-
-// Checks the country code against the values the form structure enumerates and
-// against the ones Wallet allows.
-bool WalletCountryFilter(
- const std::set<base::string16>& form_structure_values,
- const std::set<std::string>& wallet_allowed_values,
- const std::string& country_code) {
- if ((!form_structure_values.empty() &&
- !form_structure_values.count(base::ASCIIToUTF16(country_code))) ||
- (!wallet_allowed_values.empty() &&
- !wallet_allowed_values.count(country_code))) {
- return false;
- }
-
- return true;
-}
-
-// static
-base::WeakPtr<AutofillDialogControllerImpl>
-AutofillDialogControllerImpl::Create(
- content::WebContents* contents,
- const FormData& form_structure,
- const GURL& source_url,
- const AutofillClient::ResultCallback& callback) {
- // AutofillDialogControllerImpl owns itself.
- AutofillDialogControllerImpl* autofill_dialog_controller =
- new AutofillDialogControllerImpl(contents,
- form_structure,
- source_url,
- callback);
- return autofill_dialog_controller->weak_ptr_factory_.GetWeakPtr();
-}
-
-// static
-void AutofillDialogController::RegisterPrefs(PrefRegistrySimple* registry) {
- registry->RegisterListPref(::prefs::kAutofillDialogWalletLocationAcceptance);
-}
-
-// static
-void AutofillDialogController::RegisterProfilePrefs(
- user_prefs::PrefRegistrySyncable* registry) {
- registry->RegisterBooleanPref(
- ::prefs::kAutofillDialogPayWithoutWallet,
- false,
- user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
- registry->RegisterDictionaryPref(
- ::prefs::kAutofillDialogAutofillDefault,
- user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
- registry->RegisterBooleanPref(
- ::prefs::kAutofillDialogSaveData,
- true,
- user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
- registry->RegisterBooleanPref(
- ::prefs::kAutofillDialogWalletShippingSameAsBilling,
- false,
- user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
-}
-
-// static
-base::WeakPtr<AutofillDialogController> AutofillDialogController::Create(
- content::WebContents* contents,
- const FormData& form_structure,
- const GURL& source_url,
- const AutofillClient::ResultCallback& callback) {
- return AutofillDialogControllerImpl::Create(contents,
- form_structure,
- source_url,
- callback);
-}
-
-void AutofillDialogControllerImpl::Show() {
- dialog_shown_timestamp_ = base::Time::Now();
-
- // Determine what field types should be included in the dialog.
- form_structure_.ParseFieldTypesFromAutocompleteAttributes();
-
- // Fail if the author didn't specify autocomplete types.
- if (!form_structure_.has_author_specified_types()) {
- callback_.Run(
- AutofillClient::AutocompleteResultErrorDisabled,
- base::ASCIIToUTF16("Form is missing autocomplete attributes."),
- NULL);
- delete this;
- return;
- }
-
- // Fail if the author didn't ask for at least some kind of credit card
- // information.
- bool has_credit_card_field = false;
- for (size_t i = 0; i < form_structure_.field_count(); ++i) {
- AutofillType type = form_structure_.field(i)->Type();
- if (type.html_type() != HTML_TYPE_UNSPECIFIED &&
- type.group() == CREDIT_CARD) {
- has_credit_card_field = true;
- break;
- }
- }
-
- if (!has_credit_card_field) {
- callback_.Run(AutofillClient::AutocompleteResultErrorDisabled,
- base::ASCIIToUTF16(
- "Form is not a payment form (must contain "
- "some autocomplete=\"cc-*\" fields). "),
- NULL);
- delete this;
- return;
- }
-
- billing_country_combobox_model_.reset(new CountryComboboxModel());
- billing_country_combobox_model_->SetCountries(
- *GetManager(),
- base::Bind(AutofillCountryFilter,
- form_structure_.PossibleValues(ADDRESS_BILLING_COUNTRY)));
- shipping_country_combobox_model_.reset(new CountryComboboxModel());
- acceptable_shipping_countries_ =
- form_structure_.PossibleValues(ADDRESS_HOME_COUNTRY);
- shipping_country_combobox_model_->SetCountries(
- *GetManager(),
- base::Bind(AutofillCountryFilter,
- base::ConstRef(acceptable_shipping_countries_)));
-
- // If the form has a country <select> but none of the options are valid, bail.
- if (billing_country_combobox_model_->GetItemCount() == 0 ||
- shipping_country_combobox_model_->GetItemCount() == 0) {
- callback_.Run(AutofillClient::AutocompleteResultErrorDisabled,
- base::ASCIIToUTF16("No valid/supported country options"
- " found."),
- NULL);
- delete this;
- return;
- }
-
- // Log any relevant UI metrics and security exceptions.
- AutofillMetrics::LogDialogUiEvent(AutofillMetrics::DIALOG_UI_SHOWN);
-
- AutofillMetrics::LogDialogSecurityMetric(
- AutofillMetrics::SECURITY_METRIC_DIALOG_SHOWN);
-
- // The Autofill dialog is shown in response to a message from the renderer and
- // as such, it can only be made in the context of the current document. A call
- // to GetActiveEntry would return a pending entry, if there was one, which
- // would be a security bug. Therefore, we use the last committed URL for the
- // access checks.
- const GURL& current_url = web_contents()->GetLastCommittedURL();
- invoked_from_same_origin_ =
- current_url.GetOrigin() == source_url_.GetOrigin();
-
- if (!invoked_from_same_origin_) {
- AutofillMetrics::LogDialogSecurityMetric(
- AutofillMetrics::SECURITY_METRIC_CROSS_ORIGIN_FRAME);
- }
-
- for (size_t i = SECTION_MIN; i <= SECTION_MAX; ++i) {
- DialogSection section = static_cast<DialogSection>(i);
-
- std::string country_code;
- CountryComboboxModel* model = CountryComboboxModelForSection(section);
- if (model)
- country_code = model->GetDefaultCountryCode();
-
- DetailInputs* inputs = MutableRequestedFieldsForSection(section);
- BuildInputsForSection(
- section, country_code, inputs,
- MutableAddressLanguageCodeForSection(section));
- }
-
- // Test whether we need to show the shipping section. If filling that section
- // would be a no-op, don't show it.
- cares_about_shipping_ = form_structure_.FillFields(
- RequestedTypesForSection(SECTION_SHIPPING),
- base::Bind(ServerTypeMatchesField, SECTION_SHIPPING),
- base::Bind(NullGetInfo), std::string(),
- g_browser_process->GetApplicationLocale());
-
- transaction_amount_ = form_structure_.GetUniqueValue(
- HTML_TYPE_TRANSACTION_AMOUNT);
- transaction_currency_ = form_structure_.GetUniqueValue(
- HTML_TYPE_TRANSACTION_CURRENCY);
- acceptable_cc_types_ = form_structure_.PossibleValues(CREDIT_CARD_TYPE);
-
- validator_.reset(new AddressValidator(
- std::unique_ptr<::i18n::addressinput::Source>(
- new autofill::ChromeMetadataSource(I18N_ADDRESS_VALIDATION_DATA_URL,
- profile_->GetRequestContext())),
- ValidationRulesStorageFactory::CreateStorage(), this));
-
- SuggestionsUpdated();
- SubmitButtonDelayBegin();
- view_.reset(CreateView());
- view_->Show();
- GetManager()->AddObserver(this);
-
- LogDialogLatencyToShow();
-}
-
-void AutofillDialogControllerImpl::Hide() {
- if (view_)
- view_->Hide();
-}
-
-// TODO(estade): remove.
-void AutofillDialogControllerImpl::TabActivated() {
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// AutofillDialogViewDelegate implementation.
-
-base::string16 AutofillDialogControllerImpl::DialogTitle() const {
- return l10n_util::GetStringUTF16(IDS_AUTOFILL_DIALOG_TITLE);
-}
-
-base::string16 AutofillDialogControllerImpl::EditSuggestionText() const {
- return l10n_util::GetStringUTF16(IDS_AUTOFILL_DIALOG_EDIT);
-}
-
-base::string16 AutofillDialogControllerImpl::CancelButtonText() const {
- return l10n_util::GetStringUTF16(IDS_CANCEL);
-}
-
-base::string16 AutofillDialogControllerImpl::ConfirmButtonText() const {
- return l10n_util::GetStringUTF16(IDS_AUTOFILL_DIALOG_SUBMIT_BUTTON);
-}
-
-base::string16 AutofillDialogControllerImpl::SaveLocallyText() const {
- return l10n_util::GetStringUTF16(IDS_AUTOFILL_DIALOG_SAVE_LOCALLY_CHECKBOX);
-}
-
-base::string16 AutofillDialogControllerImpl::SaveLocallyTooltip() const {
- return l10n_util::GetStringUTF16(IDS_AUTOFILL_DIALOG_SAVE_LOCALLY_TOOLTIP);
-}
-
-bool AutofillDialogControllerImpl::ShouldOfferToSaveInChrome() const {
- return IsAutofillEnabled() && !profile_->IsOffTheRecord() &&
- IsManuallyEditingAnySection();
-}
-
-bool AutofillDialogControllerImpl::ShouldSaveInChrome() const {
- return profile_->GetPrefs()->GetBoolean(::prefs::kAutofillDialogSaveData);
-}
-
-int AutofillDialogControllerImpl::GetDialogButtons() const {
- return ui::DIALOG_BUTTON_OK | ui::DIALOG_BUTTON_CANCEL;
-}
-
-bool AutofillDialogControllerImpl::IsDialogButtonEnabled(
- ui::DialogButton button) const {
- if (button == ui::DIALOG_BUTTON_OK)
- return !submit_button_delay_timer_.IsRunning();
-
- DCHECK_EQ(ui::DIALOG_BUTTON_CANCEL, button);
- return true;
-}
-
-bool AutofillDialogControllerImpl::SectionIsActive(DialogSection section)
- const {
- return FormStructureCaresAboutSection(section);
-}
-
-void AutofillDialogControllerImpl::ResetSectionInput(DialogSection section) {
- SetEditingExistingData(section, false);
- needs_validation_.erase(section);
-
- CountryComboboxModel* model = CountryComboboxModelForSection(section);
- if (model) {
- base::string16 country = model->GetItemAt(model->GetDefaultIndex());
- RebuildInputsForCountry(section, country, false);
- }
-
- DetailInputs* inputs = MutableRequestedFieldsForSection(section);
- for (DetailInputs::iterator it = inputs->begin();
- it != inputs->end(); ++it) {
- if (it->length != DetailInput::NONE) {
- it->initial_value.clear();
- } else if (!it->initial_value.empty() &&
- (it->type == ADDRESS_BILLING_COUNTRY ||
- it->type == ADDRESS_HOME_COUNTRY)) {
- GetValidator()->LoadRules(
- CountryNames::GetInstance()->GetCountryCode(it->initial_value));
- }
- }
-}
-
-void AutofillDialogControllerImpl::ShowEditUiIfBadSuggestion(
- DialogSection section) {
- // |CreateWrapper()| returns an empty wrapper if |IsEditingExistingData()|, so
- // get the wrapper before this potentially happens below.
- std::unique_ptr<DataModelWrapper> wrapper = CreateWrapper(section);
-
- // If the chosen item in |model| yields an empty suggestion text, it is
- // invalid. In this case, show the edit UI and highlight invalid fields.
- SuggestionsMenuModel* model = SuggestionsMenuModelForSection(section);
- base::string16 unused, unused2;
- if (IsASuggestionItemKey(model->GetItemKeyForCheckedItem()) &&
- !SuggestionTextForSection(section, &unused, &unused2)) {
- SetEditingExistingData(section, true);
- }
-
- if (wrapper && IsEditingExistingData(section)) {
- base::string16 country =
- wrapper->GetInfo(AutofillType(CountryTypeForSection(section)));
- if (!country.empty()) {
- // There's no user input to restore here as this is only called after
- // resetting all section input.
- if (RebuildInputsForCountry(section, country, false))
- UpdateSection(section);
- }
- wrapper->FillInputs(MutableRequestedFieldsForSection(section));
- }
-}
-
-bool AutofillDialogControllerImpl::InputWasEdited(ServerFieldType type,
- const base::string16& value) {
- if (value.empty())
- return false;
-
- // If this is a combobox at the default value, don't preserve it.
- ui::ComboboxModel* model = ComboboxModelForAutofillType(type);
- if (model && model->GetItemAt(model->GetDefaultIndex()) == value)
- return false;
-
- return true;
-}
-
-FieldValueMap AutofillDialogControllerImpl::TakeUserInputSnapshot() {
- FieldValueMap snapshot;
- if (!view_)
- return snapshot;
-
- for (size_t i = SECTION_MIN; i <= SECTION_MAX; ++i) {
- DialogSection section = static_cast<DialogSection>(i);
- SuggestionsMenuModel* model = SuggestionsMenuModelForSection(section);
- if (model->GetItemKeyForCheckedItem() != kAddNewItemKey)
- continue;
-
- FieldValueMap outputs;
- view_->GetUserInput(section, &outputs);
- // Remove fields that are empty, at their default values, or invalid.
- for (FieldValueMap::iterator it = outputs.begin(); it != outputs.end();
- ++it) {
- if (InputWasEdited(it->first, it->second) &&
- InputValidityMessage(section, it->first, it->second).empty()) {
- snapshot.insert(std::make_pair(it->first, it->second));
- }
- }
- }
-
- return snapshot;
-}
-
-void AutofillDialogControllerImpl::RestoreUserInputFromSnapshot(
- const FieldValueMap& snapshot) {
- if (snapshot.empty())
- return;
-
- for (size_t i = SECTION_MIN; i <= SECTION_MAX; ++i) {
- DialogSection section = static_cast<DialogSection>(i);
- if (!SectionIsActive(section))
- continue;
-
- DetailInputs* inputs = MutableRequestedFieldsForSection(section);
- for (size_t i = 0; i < inputs->size(); ++i) {
- DetailInput* input = &(*inputs)[i];
- if (input->length != DetailInput::NONE) {
- input->initial_value =
- GetInfoFromInputs(snapshot, section, AutofillType(input->type));
- }
- if (InputWasEdited(input->type, input->initial_value))
- SuggestionsMenuModelForSection(section)->SetCheckedItem(kAddNewItemKey);
- }
- }
-}
-
-void AutofillDialogControllerImpl::UpdateSection(DialogSection section) {
- if (view_)
- view_->UpdateSection(section);
-}
-
-void AutofillDialogControllerImpl::UpdateForErrors() {
- if (!view_)
- return;
-
- // Currently, the view should only need to be updated if validating a
- // suggestion that's based on existing data.
- for (size_t i = SECTION_MIN; i <= SECTION_MAX; ++i) {
- if (IsEditingExistingData(static_cast<DialogSection>(i))) {
- view_->UpdateForErrors();
- break;
- }
- }
-}
-
-const DetailInputs& AutofillDialogControllerImpl::RequestedFieldsForSection(
- DialogSection section) const {
- switch (section) {
- case SECTION_CC:
- return requested_cc_fields_;
- case SECTION_BILLING:
- return requested_billing_fields_;
- case SECTION_SHIPPING:
- return requested_shipping_fields_;
- }
-
- NOTREACHED();
- return requested_billing_fields_;
-}
-
-ui::ComboboxModel* AutofillDialogControllerImpl::ComboboxModelForAutofillType(
- ServerFieldType type) {
- switch (type) {
- case CREDIT_CARD_EXP_MONTH:
- return &cc_exp_month_combobox_model_;
-
- case CREDIT_CARD_EXP_4_DIGIT_YEAR:
- return &cc_exp_year_combobox_model_;
-
- case ADDRESS_BILLING_COUNTRY:
- return billing_country_combobox_model_.get();
-
- case ADDRESS_HOME_COUNTRY:
- return shipping_country_combobox_model_.get();
-
- default:
- return NULL;
- }
-}
-
-ui::MenuModel* AutofillDialogControllerImpl::MenuModelForSection(
- DialogSection section) {
- SuggestionsMenuModel* model = SuggestionsMenuModelForSection(section);
- // The shipping section menu is special. It will always show because there is
- // a choice between "Use billing" and "enter new".
- if (section == SECTION_SHIPPING)
- return model;
-
- // For other sections, only show a menu if there's at least one suggestion.
- for (int i = 0; i < model->GetItemCount(); ++i) {
- if (IsASuggestionItemKey(model->GetItemKeyAt(i)))
- return model;
- }
-
- return NULL;
-}
-
-base::string16 AutofillDialogControllerImpl::LabelForSection(
- DialogSection section) const {
- switch (section) {
- case SECTION_CC:
- return l10n_util::GetStringUTF16(IDS_AUTOFILL_DIALOG_SECTION_CC);
- case SECTION_BILLING:
- return l10n_util::GetStringUTF16(IDS_AUTOFILL_DIALOG_SECTION_BILLING);
- case SECTION_SHIPPING:
- return l10n_util::GetStringUTF16(IDS_AUTOFILL_DIALOG_SECTION_SHIPPING);
- }
- NOTREACHED();
- return base::string16();
-}
-
-SuggestionState AutofillDialogControllerImpl::SuggestionStateForSection(
- DialogSection section) {
- base::string16 vertically_compact, horizontally_compact;
- bool show_suggestion = SuggestionTextForSection(section,
- &vertically_compact,
- &horizontally_compact);
- return SuggestionState(show_suggestion,
- vertically_compact,
- horizontally_compact,
- SuggestionIconForSection(section),
- ExtraSuggestionTextForSection(section),
- ExtraSuggestionIconForSection(section));
-}
-
-bool AutofillDialogControllerImpl::SuggestionTextForSection(
- DialogSection section,
- base::string16* vertically_compact,
- base::string16* horizontally_compact) {
- // When the user has clicked 'edit' or a suggestion is somehow invalid (e.g. a
- // user selects a credit card that has expired), don't show a suggestion (even
- // though there is a profile selected in the model).
- if (IsEditingExistingData(section))
- return false;
-
- SuggestionsMenuModel* model = SuggestionsMenuModelForSection(section);
- std::string item_key = model->GetItemKeyForCheckedItem();
- if (item_key == kSameAsBillingKey) {
- *vertically_compact = *horizontally_compact = l10n_util::GetStringUTF16(
- IDS_AUTOFILL_DIALOG_USING_BILLING_FOR_SHIPPING);
- return true;
- }
-
- if (!IsASuggestionItemKey(item_key))
- return false;
-
- if (section == SECTION_BILLING || section == SECTION_SHIPPING) {
- // Also check if the address is invalid (rules may have loaded since
- // the dialog was shown).
- if (HasInvalidAddress(*GetManager()->GetProfileByGUID(item_key)))
- return false;
- }
-
- std::unique_ptr<DataModelWrapper> wrapper = CreateWrapper(section);
- return wrapper->GetDisplayText(vertically_compact, horizontally_compact);
-}
-
-base::string16 AutofillDialogControllerImpl::ExtraSuggestionTextForSection(
- DialogSection section) const {
- if (section == SECTION_CC)
- return l10n_util::GetStringUTF16(IDS_AUTOFILL_DIALOG_PLACEHOLDER_CVC);
-
- return base::string16();
-}
-
-std::unique_ptr<DataModelWrapper> AutofillDialogControllerImpl::CreateWrapper(
- DialogSection section) {
- SuggestionsMenuModel* model = SuggestionsMenuModelForSection(section);
- std::string item_key = model->GetItemKeyForCheckedItem();
- if (!IsASuggestionItemKey(item_key) || IsManuallyEditingSection(section))
- return std::unique_ptr<DataModelWrapper>();
-
- if (section == SECTION_CC) {
- CreditCard* card = GetManager()->GetCreditCardByGUID(item_key);
- DCHECK(card);
- return std::unique_ptr<DataModelWrapper>(
- new AutofillCreditCardWrapper(card));
- }
-
- AutofillProfile* profile = GetManager()->GetProfileByGUID(item_key);
- DCHECK(profile);
- if (section == SECTION_SHIPPING) {
- return std::unique_ptr<DataModelWrapper>(
- new AutofillShippingAddressWrapper(profile));
- }
- DCHECK_EQ(SECTION_BILLING, section);
- return std::unique_ptr<DataModelWrapper>(new AutofillProfileWrapper(profile));
-}
-
-gfx::Image AutofillDialogControllerImpl::SuggestionIconForSection(
- DialogSection section) {
- std::unique_ptr<DataModelWrapper> model = CreateWrapper(section);
- if (!model.get())
- return gfx::Image();
-
- return model->GetIcon();
-}
-
-gfx::Image AutofillDialogControllerImpl::ExtraSuggestionIconForSection(
- DialogSection section) {
- if (section != SECTION_CC)
- return gfx::Image();
-
- std::unique_ptr<DataModelWrapper> model = CreateWrapper(section);
- if (!model.get())
- return gfx::Image();
-
- return CvcIconForCreditCardType(
- model->GetInfo(AutofillType(CREDIT_CARD_TYPE)));
-}
-
-FieldIconMap AutofillDialogControllerImpl::IconsForFields(
- const FieldValueMap& user_inputs) const {
- FieldIconMap result;
- base::string16 credit_card_type;
-
- FieldValueMap::const_iterator credit_card_iter =
- user_inputs.find(CREDIT_CARD_NUMBER);
- if (credit_card_iter != user_inputs.end()) {
- const base::string16& number = credit_card_iter->second;
- const std::string type = CreditCard::GetCreditCardType(number);
- credit_card_type = CreditCard::TypeForDisplay(type);
- result[CREDIT_CARD_NUMBER] = CreditCardIconForType(type);
- }
-
- if (!user_inputs.count(CREDIT_CARD_VERIFICATION_CODE))
- return result;
-
- result[CREDIT_CARD_VERIFICATION_CODE] =
- CvcIconForCreditCardType(credit_card_type);
-
- return result;
-}
-
-bool AutofillDialogControllerImpl::FieldControlsIcons(
- ServerFieldType type) const {
- return type == CREDIT_CARD_NUMBER;
-}
-
-base::string16 AutofillDialogControllerImpl::TooltipForField(
- ServerFieldType type) const {
- if (type == PHONE_HOME_WHOLE_NUMBER || type == PHONE_BILLING_WHOLE_NUMBER)
- return l10n_util::GetStringUTF16(IDS_AUTOFILL_DIALOG_TOOLTIP_PHONE_NUMBER);
-
- return base::string16();
-}
-
-// TODO(groby): Add more tests.
-base::string16 AutofillDialogControllerImpl::InputValidityMessage(
- DialogSection section,
- ServerFieldType type,
- const base::string16& value) {
- AutofillType autofill_type(type);
- if (autofill_type.group() == ADDRESS_HOME ||
- autofill_type.group() == ADDRESS_BILLING) {
- return base::string16();
- }
-
- switch (autofill_type.GetStorableType()) {
- case EMAIL_ADDRESS:
- if (!value.empty() && !IsValidEmailAddress(value)) {
- return l10n_util::GetStringUTF16(
- IDS_AUTOFILL_DIALOG_VALIDATION_INVALID_EMAIL_ADDRESS);
- }
- break;
-
- case CREDIT_CARD_NUMBER: {
- if (!value.empty()) {
- base::string16 message = CreditCardNumberValidityMessage(value);
- if (!message.empty())
- return message;
- }
- break;
- }
-
- case CREDIT_CARD_EXP_MONTH:
- if (!InputWasEdited(CREDIT_CARD_EXP_MONTH, value)) {
- return l10n_util::GetStringUTF16(
- IDS_LIBADDRESSINPUT_MISSING_REQUIRED_FIELD);
- }
- break;
-
- case CREDIT_CARD_EXP_4_DIGIT_YEAR:
- if (!InputWasEdited(CREDIT_CARD_EXP_4_DIGIT_YEAR, value)) {
- return l10n_util::GetStringUTF16(
- IDS_LIBADDRESSINPUT_MISSING_REQUIRED_FIELD);
- }
- break;
-
- case CREDIT_CARD_VERIFICATION_CODE:
- if (!value.empty() && !autofill::IsValidCreditCardSecurityCode(value)) {
- return l10n_util::GetStringUTF16(
- IDS_AUTOFILL_DIALOG_VALIDATION_INVALID_CREDIT_CARD_SECURITY_CODE);
- }
- break;
-
- case NAME_FULL:
- break;
-
- case PHONE_HOME_WHOLE_NUMBER: // Used in shipping section.
- break;
-
- case PHONE_BILLING_WHOLE_NUMBER: // Used in billing section.
- break;
-
- default:
- NOTREACHED(); // Trying to validate unknown field.
- break;
- }
-
- return value.empty() ? l10n_util::GetStringUTF16(
- IDS_LIBADDRESSINPUT_MISSING_REQUIRED_FIELD) :
- base::string16();
-}
-
-// TODO(groby): Also add tests.
-ValidityMessages AutofillDialogControllerImpl::InputsAreValid(
- DialogSection section,
- const FieldValueMap& inputs) {
- ValidityMessages messages;
- if (inputs.empty())
- return messages;
-
- AddressValidator::Status status = AddressValidator::SUCCESS;
- if (section != SECTION_CC) {
- AutofillProfile profile;
- FillFormGroupFromOutputs(inputs, &profile);
- std::unique_ptr<AddressData> address_data =
- i18n::CreateAddressDataFromAutofillProfile(
- profile, g_browser_process->GetApplicationLocale());
- address_data->language_code = AddressLanguageCodeForSection(section);
-
- Localization localization;
- localization.SetGetter(l10n_util::GetStringUTF8);
- FieldProblemMap problems;
- status = GetValidator()->ValidateAddress(*address_data, NULL, &problems);
- bool billing = section != SECTION_SHIPPING;
-
- for (FieldProblemMap::const_iterator iter = problems.begin();
- iter != problems.end(); ++iter) {
- bool sure = iter->second != MISSING_REQUIRED_FIELD;
- base::string16 text = base::UTF8ToUTF16(localization.GetErrorMessage(
- *address_data, iter->first, iter->second, true, false));
- messages.Set(i18n::TypeForField(iter->first, billing),
- ValidityMessage(text, sure));
- }
- }
-
- for (FieldValueMap::const_iterator iter = inputs.begin();
- iter != inputs.end(); ++iter) {
- const ServerFieldType type = iter->first;
- base::string16 text = InputValidityMessage(section, type, iter->second);
-
- // Skip empty/unchanged fields in edit mode. If the individual field does
- // not have validation errors, assume it to be valid unless later proven
- // otherwise.
- bool sure = InputWasEdited(type, iter->second);
-
- if (sure && status == AddressValidator::RULES_NOT_READY &&
- !ComboboxModelForAutofillType(type) &&
- (AutofillType(type).group() == ADDRESS_HOME ||
- AutofillType(type).group() == ADDRESS_BILLING)) {
- DCHECK(text.empty());
- text = l10n_util::GetStringUTF16(
- IDS_AUTOFILL_DIALOG_VALIDATION_WAITING_FOR_RULES);
- sure = false;
- needs_validation_.insert(section);
- }
-
- messages.Set(type, ValidityMessage(text, sure));
- }
-
- // For the convenience of using operator[].
- FieldValueMap& field_values = const_cast<FieldValueMap&>(inputs);
- // Validate the date formed by month and year field. (Autofill dialog is
- // never supposed to have 2-digit years, so not checked).
- if (field_values.count(CREDIT_CARD_EXP_4_DIGIT_YEAR) &&
- field_values.count(CREDIT_CARD_EXP_MONTH) &&
- InputWasEdited(CREDIT_CARD_EXP_4_DIGIT_YEAR,
- field_values[CREDIT_CARD_EXP_4_DIGIT_YEAR]) &&
- InputWasEdited(CREDIT_CARD_EXP_MONTH,
- field_values[CREDIT_CARD_EXP_MONTH])) {
- ValidityMessage year_message(base::string16(), true);
- ValidityMessage month_message(base::string16(), true);
- if (!autofill::IsValidCreditCardExpirationDate(
- field_values[CREDIT_CARD_EXP_4_DIGIT_YEAR],
- field_values[CREDIT_CARD_EXP_MONTH], base::Time::Now())) {
- // The dialog shows the same error message for the month and year fields.
- year_message.text = l10n_util::GetStringUTF16(
- IDS_AUTOFILL_DIALOG_VALIDATION_INVALID_CREDIT_CARD_EXPIRATION_DATE);
- month_message.text = l10n_util::GetStringUTF16(
- IDS_AUTOFILL_DIALOG_VALIDATION_INVALID_CREDIT_CARD_EXPIRATION_DATE);
- }
- messages.Set(CREDIT_CARD_EXP_4_DIGIT_YEAR, year_message);
- messages.Set(CREDIT_CARD_EXP_MONTH, month_message);
- }
-
- // If there is a credit card number and a CVC, validate them together.
- if (field_values.count(CREDIT_CARD_NUMBER) &&
- field_values.count(CREDIT_CARD_VERIFICATION_CODE)) {
- ValidityMessage ccv_message(base::string16(), true);
- if (!autofill::IsValidCreditCardSecurityCode(
- field_values[CREDIT_CARD_VERIFICATION_CODE],
- field_values[CREDIT_CARD_NUMBER])) {
- ccv_message.text = l10n_util::GetStringUTF16(
- IDS_AUTOFILL_DIALOG_VALIDATION_INVALID_CREDIT_CARD_SECURITY_CODE);
- }
- messages.Set(CREDIT_CARD_VERIFICATION_CODE, ccv_message);
- }
-
- // Validate the shipping phone number against the country code of the address.
- if (field_values.count(ADDRESS_HOME_COUNTRY) &&
- field_values.count(PHONE_HOME_WHOLE_NUMBER)) {
- messages.Set(
- PHONE_HOME_WHOLE_NUMBER,
- GetPhoneValidityMessage(field_values[ADDRESS_HOME_COUNTRY],
- field_values[PHONE_HOME_WHOLE_NUMBER]));
- }
-
- // Validate the billing phone number against the country code of the address.
- if (field_values.count(ADDRESS_BILLING_COUNTRY) &&
- field_values.count(PHONE_BILLING_WHOLE_NUMBER)) {
- messages.Set(
- PHONE_BILLING_WHOLE_NUMBER,
- GetPhoneValidityMessage(field_values[ADDRESS_BILLING_COUNTRY],
- field_values[PHONE_BILLING_WHOLE_NUMBER]));
- }
-
- return messages;
-}
-
-void AutofillDialogControllerImpl::UserEditedOrActivatedInput(
- DialogSection section,
- ServerFieldType type,
- gfx::NativeView parent_view,
- const gfx::Rect& content_bounds,
- const base::string16& field_contents,
- bool was_edit) {
- ScopedViewUpdates updates(view_.get());
-
- if (type == ADDRESS_BILLING_COUNTRY || type == ADDRESS_HOME_COUNTRY) {
- const FieldValueMap& snapshot = TakeUserInputSnapshot();
-
- // Clobber the inputs because the view's already been updated.
- RebuildInputsForCountry(section, field_contents, true);
- RestoreUserInputFromSnapshot(snapshot);
- UpdateSection(section);
- }
-
- // The rest of this method applies only to textfields while Autofill is
- // enabled. If a combobox or Autofill is disabled, bail.
- if (ComboboxModelForAutofillType(type) || !IsAutofillEnabled())
- return;
-
- // If the field is edited down to empty, don't show a popup.
- if (was_edit && field_contents.empty()) {
- HidePopup();
- return;
- }
-
- // If the user clicks while the popup is already showing, be sure to hide
- // it.
- if (!was_edit && popup_controller_.get()) {
- HidePopup();
- return;
- }
-
- std::vector<autofill::Suggestion> popup_suggestions;
- popup_suggestion_ids_.clear();
- if (IsCreditCardType(type)) {
- popup_suggestions = GetManager()->GetCreditCardSuggestions(
- AutofillType(type), field_contents);
- for (const auto& suggestion : popup_suggestions)
- popup_suggestion_ids_.push_back(suggestion.backend_id);
- } else {
- popup_suggestions = GetManager()->GetProfileSuggestions(
- AutofillType(type),
- field_contents,
- false,
- RequestedTypesForSection(section));
- // Filter out ones we don't want.
- for (int i = 0; i < static_cast<int>(popup_suggestions.size()); i++) {
- const autofill::AutofillProfile* profile =
- GetManager()->GetProfileByGUID(popup_suggestions[i].backend_id);
- if (!profile || !ShouldSuggestProfile(section, *profile)) {
- popup_suggestions.erase(popup_suggestions.begin() + i);
- i--;
- }
- }
-
- // Save the IDs.
- for (const auto& suggestion : popup_suggestions)
- popup_suggestion_ids_.push_back(suggestion.backend_id);
-
- // This will append to the popup_suggestions but not the IDs since there
- // are no backend IDs for the I18N validator suggestions.
- GetI18nValidatorSuggestions(section, type, &popup_suggestions);
- }
-
- if (popup_suggestions.empty()) {
- HidePopup();
- return;
- }
-
- // |popup_input_type_| must be set before calling |Show()|.
- popup_input_type_ = type;
- popup_section_ = section;
-
- // Use our own 0-based IDs for the items.
- // TODO(estade): do we need separators and control rows like 'Clear
- // Form'?
- for (size_t i = 0; i < popup_suggestions.size(); ++i) {
- popup_suggestions[i].frontend_id = i;
- }
-
- popup_controller_ = AutofillPopupControllerImpl::GetOrCreate(
- popup_controller_, weak_ptr_factory_.GetWeakPtr(), NULL, parent_view,
- gfx::RectF(content_bounds),
- base::i18n::IsRTL() ? base::i18n::RIGHT_TO_LEFT
- : base::i18n::LEFT_TO_RIGHT);
- popup_controller_->Show(popup_suggestions);
-}
-
-void AutofillDialogControllerImpl::FocusMoved() {
- HidePopup();
-}
-
-bool AutofillDialogControllerImpl::ShouldShowErrorBubble() const {
- return popup_input_type_ == UNKNOWN_TYPE;
-}
-
-void AutofillDialogControllerImpl::ViewClosed() {
- GetManager()->RemoveObserver(this);
-
- delete this;
-}
-
-std::vector<DialogNotification> AutofillDialogControllerImpl::
- CurrentNotifications() {
- std::vector<DialogNotification> notifications;
-
- if (!invoked_from_same_origin_) {
- notifications.push_back(DialogNotification(
- DialogNotification::SECURITY_WARNING,
- l10n_util::GetStringFUTF16(IDS_AUTOFILL_DIALOG_SITE_WARNING,
- base::UTF8ToUTF16(source_url_.host()))));
- }
-
- return notifications;
-}
-
-void AutofillDialogControllerImpl::LinkClicked(const GURL& url) {
- OpenTabWithUrl(url);
-}
-
-void AutofillDialogControllerImpl::OnCancel() {
- HidePopup();
- if (!data_was_passed_back_)
- LogOnCancelMetrics();
- callback_.Run(
- AutofillClient::AutocompleteResultErrorCancel, base::string16(), NULL);
-}
-
-void AutofillDialogControllerImpl::OnAccept() {
- ScopedViewUpdates updates(view_.get());
- HidePopup();
- FinishSubmit();
-}
-
-Profile* AutofillDialogControllerImpl::profile() {
- return profile_;
-}
-
-content::WebContents* AutofillDialogControllerImpl::GetWebContents() {
- return web_contents();
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// AutofillPopupDelegate implementation.
-
-void AutofillDialogControllerImpl::OnPopupShown() {
- ScopedViewUpdates update(view_.get());
- view_->UpdateErrorBubble();
-
- AutofillMetrics::LogDialogPopupEvent(AutofillMetrics::DIALOG_POPUP_SHOWN);
-}
-
-void AutofillDialogControllerImpl::OnPopupHidden() {}
-
-void AutofillDialogControllerImpl::DidSelectSuggestion(
- const base::string16& value,
- int identifier) {
- // TODO(estade): implement.
-}
-
-void AutofillDialogControllerImpl::DidAcceptSuggestion(
- const base::string16& value,
- int identifier,
- int position) {
- DCHECK_NE(UNKNOWN_TYPE, popup_input_type_);
- // Because |HidePopup()| can be called from |UpdateSection()|, remember the
- // type of the input for later here.
- const ServerFieldType popup_input_type = popup_input_type_;
-
- ScopedViewUpdates updates(view_.get());
- std::unique_ptr<DataModelWrapper> wrapper;
-
- if (static_cast<size_t>(identifier) < popup_suggestion_ids_.size()) {
- const std::string& guid = popup_suggestion_ids_[identifier];
- if (IsCreditCardType(popup_input_type)) {
- wrapper.reset(new AutofillCreditCardWrapper(
- GetManager()->GetCreditCardByGUID(guid)));
- } else {
- wrapper.reset(new AutofillProfileWrapper(
- GetManager()->GetProfileByGUID(guid)));
- }
- } else {
- wrapper.reset(new I18nAddressDataWrapper(
- &i18n_validator_suggestions_[
- identifier - popup_suggestion_ids_.size()]));
- }
-
- // If the user hasn't switched away from the default country and |wrapper|'s
- // country differs from the |view_|'s, rebuild inputs and restore user data.
- const FieldValueMap snapshot = TakeUserInputSnapshot();
- bool billing_rebuilt = false, shipping_rebuilt = false;
-
- base::string16 billing_country =
- wrapper->GetInfo(AutofillType(ADDRESS_BILLING_COUNTRY));
- if (popup_section_ == ActiveBillingSection() &&
- !snapshot.count(ADDRESS_BILLING_COUNTRY) &&
- !billing_country.empty()) {
- billing_rebuilt = RebuildInputsForCountry(
- ActiveBillingSection(), billing_country, false);
- }
-
- base::string16 shipping_country =
- wrapper->GetInfo(AutofillType(ADDRESS_HOME_COUNTRY));
- if (popup_section_ == SECTION_SHIPPING &&
- !snapshot.count(ADDRESS_HOME_COUNTRY) &&
- !shipping_country.empty()) {
- shipping_rebuilt = RebuildInputsForCountry(
- SECTION_SHIPPING, shipping_country, false);
- }
-
- if (billing_rebuilt || shipping_rebuilt) {
- RestoreUserInputFromSnapshot(snapshot);
- if (billing_rebuilt)
- UpdateSection(ActiveBillingSection());
- if (shipping_rebuilt)
- UpdateSection(SECTION_SHIPPING);
- }
-
- DCHECK(SectionIsActive(popup_section_));
- wrapper->FillInputs(MutableRequestedFieldsForSection(popup_section_));
- view_->FillSection(popup_section_, popup_input_type);
-
- AutofillMetrics::LogDialogPopupEvent(
- AutofillMetrics::DIALOG_POPUP_FORM_FILLED);
-
- // TODO(estade): not sure why it's necessary to do this explicitly.
- HidePopup();
-}
-
-bool AutofillDialogControllerImpl::GetDeletionConfirmationText(
- const base::string16& value,
- int identifier,
- base::string16* title,
- base::string16* body) {
- return false;
-}
-
-bool AutofillDialogControllerImpl::RemoveSuggestion(const base::string16& value,
- int identifier) {
- // TODO(estade): implement.
- return false;
-}
-
-void AutofillDialogControllerImpl::ClearPreviewedForm() {
- // TODO(estade): implement.
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// SuggestionsMenuModelDelegate implementation.
-
-void AutofillDialogControllerImpl::SuggestionItemSelected(
- SuggestionsMenuModel* model,
- size_t index) {
- ScopedViewUpdates updates(view_.get());
-
- if (model->GetItemKeyAt(index) == kManageItemsKey) {
- GURL url;
- DCHECK(IsAutofillEnabled());
- GURL settings_url(chrome::kChromeUISettingsURL);
- url = settings_url.Resolve(chrome::kAutofillSubPage);
- OpenTabWithUrl(url);
- return;
- }
-
- model->SetCheckedIndex(index);
- DialogSection section = SectionForSuggestionsMenuModel(*model);
-
- ResetSectionInput(section);
- ShowEditUiIfBadSuggestion(section);
- UpdateSection(section);
- view_->UpdateNotificationArea();
- UpdateForErrors();
-
- LogSuggestionItemSelectedMetric(*model);
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// PersonalDataManagerObserver implementation.
-
-void AutofillDialogControllerImpl::OnPersonalDataChanged() {
- SuggestionsUpdated();
-}
-
-////////////////////////////////////////////////////////////////////////////////
-
-bool AutofillDialogControllerImpl::HandleKeyPressEventInInput(
- const content::NativeWebKeyboardEvent& event) {
- if (popup_controller_.get())
- return popup_controller_->HandleKeyPressEvent(event);
-
- return false;
-}
-
-void AutofillDialogControllerImpl::SubmitButtonDelayBegin() {
- submit_button_delay_timer_.Start(
- FROM_HERE,
- base::TimeDelta::FromMilliseconds(kSubmitButtonDelayMs),
- this,
- &AutofillDialogControllerImpl::OnSubmitButtonDelayEnd);
-}
-
-void AutofillDialogControllerImpl::SubmitButtonDelayEndForTesting() {
- DCHECK(submit_button_delay_timer_.IsRunning());
- submit_button_delay_timer_.user_task().Run();
- submit_button_delay_timer_.Stop();
-}
-
-AutofillDialogControllerImpl::AutofillDialogControllerImpl(
- content::WebContents* contents,
- const FormData& form_structure,
- const GURL& source_url,
- const AutofillClient::ResultCallback& callback)
- : WebContentsObserver(contents),
- profile_(Profile::FromBrowserContext(contents->GetBrowserContext())),
- initial_user_state_(AutofillMetrics::DIALOG_USER_STATE_UNKNOWN),
- form_structure_(form_structure),
- invoked_from_same_origin_(true),
- source_url_(source_url),
- callback_(callback),
- suggested_cc_(this),
- suggested_billing_(this),
- suggested_shipping_(this),
- cares_about_shipping_(true),
- popup_input_type_(UNKNOWN_TYPE),
- popup_section_(SECTION_MIN),
- data_was_passed_back_(false),
- was_ui_latency_logged_(false),
- weak_ptr_factory_(this) {
- DCHECK(!callback_.is_null());
-}
-
-AutofillDialogView* AutofillDialogControllerImpl::CreateView() {
- return AutofillDialogView::Create(this);
-}
-
-PersonalDataManager* AutofillDialogControllerImpl::GetManager() const {
- return PersonalDataManagerFactory::GetForProfile(profile_);
-}
-
-AddressValidator* AutofillDialogControllerImpl::GetValidator() {
- return validator_.get();
-}
-
-void AutofillDialogControllerImpl::OpenTabWithUrl(const GURL& url) {
- chrome::NavigateParams params(
- chrome::FindBrowserWithWebContents(web_contents()),
- url,
- ui::PAGE_TRANSITION_LINK);
- params.disposition = NEW_FOREGROUND_TAB;
- chrome::Navigate(&params);
-}
-
-// TODO(estade): remove.
-DialogSection AutofillDialogControllerImpl::ActiveBillingSection() const {
- return SECTION_BILLING;
-}
-
-bool AutofillDialogControllerImpl::IsEditingExistingData(
- DialogSection section) const {
- return section_editing_state_.count(section) > 0;
-}
-
-bool AutofillDialogControllerImpl::IsManuallyEditingSection(
- DialogSection section) const {
- return IsEditingExistingData(section) ||
- SuggestionsMenuModelForSection(section)->
- GetItemKeyForCheckedItem() == kAddNewItemKey;
-}
-
-void AutofillDialogControllerImpl::SuggestionsUpdated() {
- ScopedViewUpdates updates(view_.get());
-
- const FieldValueMap snapshot = TakeUserInputSnapshot();
-
- suggested_cc_.Reset();
- suggested_billing_.Reset();
- suggested_shipping_.Reset();
- HidePopup();
-
- suggested_shipping_.AddKeyedItem(
- kSameAsBillingKey,
- l10n_util::GetStringUTF16(IDS_AUTOFILL_DIALOG_USE_BILLING_FOR_SHIPPING));
-
- shipping_country_combobox_model_->SetCountries(
- *GetManager(),
- base::Bind(AutofillCountryFilter, acceptable_shipping_countries_));
-
- if (IsAutofillEnabled()) {
- PersonalDataManager* manager = GetManager();
- const std::vector<CreditCard*>& cards = manager->GetCreditCards();
- ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
- for (size_t i = 0; i < cards.size(); ++i) {
- if (!i18ninput::CardHasCompleteAndVerifiedData(*cards[i]))
- continue;
-
- suggested_cc_.AddKeyedItemWithIcon(
- cards[i]->guid(), cards[i]->Label(),
- rb.GetImageNamed(CreditCard::IconResourceId(cards[i]->type())));
- suggested_cc_.SetEnabled(
- cards[i]->guid(), !ShouldDisallowCcType(cards[i]->TypeForDisplay()));
- }
-
- const std::vector<AutofillProfile*>& profiles = manager->GetProfiles();
- std::vector<base::string16> labels;
- AutofillProfile::CreateDifferentiatingLabels(
- profiles, g_browser_process->GetApplicationLocale(), &labels);
- DCHECK_EQ(labels.size(), profiles.size());
- for (size_t i = 0; i < profiles.size(); ++i) {
- const AutofillProfile& profile = *profiles[i];
- if (!i18ninput::AddressHasCompleteAndVerifiedData(
- profile, g_browser_process->GetApplicationLocale())) {
- continue;
- }
-
- suggested_shipping_.AddKeyedItem(profile.guid(), labels[i]);
- suggested_shipping_.SetEnabled(
- profile.guid(),
- CanAcceptCountry(
- SECTION_SHIPPING,
- base::UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_COUNTRY))));
- if (!profile.GetRawInfo(EMAIL_ADDRESS).empty() &&
- !profile.IsPresentButInvalid(EMAIL_ADDRESS)) {
- suggested_billing_.AddKeyedItem(profile.guid(), labels[i]);
- suggested_billing_.SetEnabled(
- profile.guid(),
- CanAcceptCountry(
- SECTION_BILLING,
- base::UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_COUNTRY))));
- }
- }
- }
-
- suggested_cc_.AddKeyedItem(
- kAddNewItemKey,
- l10n_util::GetStringUTF16(IsAutofillEnabled()
- ? IDS_AUTOFILL_DIALOG_ADD_CREDIT_CARD
- : IDS_AUTOFILL_DIALOG_ENTER_CREDIT_CARD));
- suggested_cc_.AddKeyedItem(
- kManageItemsKey,
- l10n_util::GetStringUTF16(IDS_AUTOFILL_DIALOG_MANAGE_CREDIT_CARD));
- suggested_billing_.AddKeyedItem(
- kAddNewItemKey,
- l10n_util::GetStringUTF16(
- IsAutofillEnabled() ? IDS_AUTOFILL_DIALOG_ADD_BILLING_ADDRESS
- : IDS_AUTOFILL_DIALOG_ENTER_BILLING_DETAILS));
- suggested_billing_.AddKeyedItem(
- kManageItemsKey,
- l10n_util::GetStringUTF16(IDS_AUTOFILL_DIALOG_MANAGE_BILLING_ADDRESS));
-
- suggested_shipping_.AddKeyedItem(
- kAddNewItemKey,
- l10n_util::GetStringUTF16(
- IsAutofillEnabled()
- ? IDS_AUTOFILL_DIALOG_ADD_SHIPPING_ADDRESS
- : IDS_AUTOFILL_DIALOG_USE_DIFFERENT_SHIPPING_ADDRESS));
-
- if (IsAutofillEnabled()) {
- suggested_shipping_.AddKeyedItem(
- kManageItemsKey,
- l10n_util::GetStringUTF16(IDS_AUTOFILL_DIALOG_MANAGE_SHIPPING_ADDRESS));
-
- for (size_t i = SECTION_MIN; i <= SECTION_MAX; ++i) {
- DialogSection section = static_cast<DialogSection>(i);
- if (!SectionIsActive(section))
- continue;
-
- // Set the starting choice for the menu. First set to the default in case
- // the GUID saved in prefs refers to a profile that no longer exists.
- std::string guid;
- GetDefaultAutofillChoice(section, &guid);
- SuggestionsMenuModel* model = SuggestionsMenuModelForSection(section);
- model->SetCheckedItem(guid);
- if (GetAutofillChoice(section, &guid))
- model->SetCheckedItem(guid);
- }
- }
-
- if (view_)
- view_->ModelChanged();
-
- for (size_t i = SECTION_MIN; i <= SECTION_MAX; ++i) {
- ResetSectionInput(static_cast<DialogSection>(i));
- }
-
- FieldValueMap::const_iterator billing_it =
- snapshot.find(ADDRESS_BILLING_COUNTRY);
- if (billing_it != snapshot.end())
- RebuildInputsForCountry(ActiveBillingSection(), billing_it->second, true);
-
- FieldValueMap::const_iterator shipping_it =
- snapshot.find(ADDRESS_HOME_COUNTRY);
- if (shipping_it != snapshot.end())
- RebuildInputsForCountry(SECTION_SHIPPING, shipping_it->second, true);
-
- RestoreUserInputFromSnapshot(snapshot);
-
- for (size_t i = SECTION_MIN; i <= SECTION_MAX; ++i) {
- DialogSection section = static_cast<DialogSection>(i);
- if (!SectionIsActive(section))
- continue;
-
- ShowEditUiIfBadSuggestion(section);
- UpdateSection(section);
- }
-
- UpdateForErrors();
-}
-
-void AutofillDialogControllerImpl::FillOutputForSectionWithComparator(
- DialogSection section,
- const FormStructure::InputFieldComparator& compare) {
- if (!SectionIsActive(section))
- return;
-
- DetailInputs inputs;
- std::string country_code = CountryCodeForSection(section);
- BuildInputsForSection(section, country_code, &inputs,
- MutableAddressLanguageCodeForSection(section));
- std::vector<ServerFieldType> types = TypesFromInputs(inputs);
-
- std::unique_ptr<DataModelWrapper> wrapper = CreateWrapper(section);
- if (wrapper) {
- // Only fill in data that is associated with this section.
- wrapper->FillFormStructure(types, compare, &form_structure_);
-
- // CVC needs special-casing because the CreditCard class doesn't store or
- // handle them. This isn't necessary when filling the combined CC and
- // billing section as CVC comes from |full_wallet_| in this case.
- if (section == SECTION_CC)
- SetOutputForFieldsOfType(CREDIT_CARD_VERIFICATION_CODE, view_->GetCvc());
-
- } else {
- // The user manually input data. If using Autofill, save the info as new or
- // edited data. Always fill local data into |form_structure_|.
- FieldValueMap output;
- view_->GetUserInput(section, &output);
-
- if (section == SECTION_CC) {
- CreditCard card;
- FillFormGroupFromOutputs(output, &card);
-
- // The card holder name comes from the billing address section.
- card.SetRawInfo(CREDIT_CARD_NAME_FULL,
- GetValueFromSection(SECTION_BILLING, NAME_BILLING_FULL));
-
- AutofillCreditCardWrapper card_wrapper(&card);
- card_wrapper.FillFormStructure(types, compare, &form_structure_);
-
- // Again, CVC needs special-casing. Fill it in directly from |output|.
- SetOutputForFieldsOfType(
- CREDIT_CARD_VERIFICATION_CODE,
- output[CREDIT_CARD_VERIFICATION_CODE]);
- } else {
- AutofillProfile profile;
- FillFormGroupFromOutputs(output, &profile);
- profile.set_language_code(AddressLanguageCodeForSection(section));
-
- if (ShouldSaveDetailsLocally()) {
- profile.set_origin(RulesAreLoaded(section) ?
- kAutofillDialogOrigin : source_url_.GetOrigin().spec());
-
- std::string guid = GetManager()->SaveImportedProfile(profile);
- newly_saved_data_model_guids_[section] = guid;
- }
-
- AutofillProfileWrapper profile_wrapper(&profile);
- profile_wrapper.FillFormStructure(types, compare, &form_structure_);
- }
- }
-}
-
-void AutofillDialogControllerImpl::FillOutputForSection(DialogSection section) {
- FillOutputForSectionWithComparator(
- section, base::Bind(ServerTypeMatchesField, section));
-}
-
-bool AutofillDialogControllerImpl::FormStructureCaresAboutSection(
- DialogSection section) const {
- // For now, only SECTION_SHIPPING may be omitted due to a site not asking for
- // any of the fields.
- if (section == SECTION_SHIPPING)
- return cares_about_shipping_;
-
- return true;
-}
-
-void AutofillDialogControllerImpl::SetOutputForFieldsOfType(
- ServerFieldType type,
- const base::string16& output) {
- for (size_t i = 0; i < form_structure_.field_count(); ++i) {
- AutofillField* field = form_structure_.field(i);
- if (field->Type().GetStorableType() == type)
- field->value = output;
- }
-}
-
-base::string16 AutofillDialogControllerImpl::GetValueFromSection(
- DialogSection section,
- ServerFieldType type) {
- DCHECK(SectionIsActive(section));
-
- std::unique_ptr<DataModelWrapper> wrapper = CreateWrapper(section);
- if (wrapper)
- return wrapper->GetInfo(AutofillType(type));
-
- FieldValueMap output;
- view_->GetUserInput(section, &output);
- return output[type];
-}
-
-bool AutofillDialogControllerImpl::CanAcceptCountry(
- DialogSection section,
- const std::string& country_code) {
- DCHECK_EQ(2U, country_code.size());
- CountryComboboxModel* model = CountryComboboxModelForSection(section);
- const std::vector<AutofillCountry*>& countries = model->countries();
- for (size_t i = 0; i < countries.size(); ++i) {
- if (countries[i] && countries[i]->country_code() == country_code)
- return true;
- }
-
- return false;
-}
-
-bool AutofillDialogControllerImpl::ShouldSuggestProfile(
- DialogSection section,
- const AutofillProfile& profile) {
- std::string country_code =
- base::UTF16ToASCII(profile.GetRawInfo(ADDRESS_HOME_COUNTRY));
- return country_code.empty() || CanAcceptCountry(section, country_code);
-}
-
-SuggestionsMenuModel* AutofillDialogControllerImpl::
- SuggestionsMenuModelForSection(DialogSection section) {
- switch (section) {
- case SECTION_CC:
- return &suggested_cc_;
- case SECTION_BILLING:
- return &suggested_billing_;
- case SECTION_SHIPPING:
- return &suggested_shipping_;
- }
-
- NOTREACHED();
- return NULL;
-}
-
-const SuggestionsMenuModel* AutofillDialogControllerImpl::
- SuggestionsMenuModelForSection(DialogSection section) const {
- return const_cast<AutofillDialogControllerImpl*>(this)->
- SuggestionsMenuModelForSection(section);
-}
-
-DialogSection AutofillDialogControllerImpl::SectionForSuggestionsMenuModel(
- const SuggestionsMenuModel& model) {
- if (&model == &suggested_cc_)
- return SECTION_CC;
-
- if (&model == &suggested_billing_)
- return SECTION_BILLING;
-
- DCHECK_EQ(&model, &suggested_shipping_);
- return SECTION_SHIPPING;
-}
-
-CountryComboboxModel* AutofillDialogControllerImpl::
- CountryComboboxModelForSection(DialogSection section) {
- if (section == SECTION_BILLING)
- return billing_country_combobox_model_.get();
-
- if (section == SECTION_SHIPPING)
- return shipping_country_combobox_model_.get();
-
- return NULL;
-}
-
-void AutofillDialogControllerImpl::GetI18nValidatorSuggestions(
- DialogSection section,
- ServerFieldType type,
- std::vector<autofill::Suggestion>* popup_suggestions) {
- AddressField focused_field;
- if (!i18n::FieldForType(type, &focused_field))
- return;
-
- FieldValueMap inputs;
- view_->GetUserInput(section, &inputs);
-
- AutofillProfile profile;
- FillFormGroupFromOutputs(inputs, &profile);
-
- std::unique_ptr<AddressData> user_input =
- i18n::CreateAddressDataFromAutofillProfile(
- profile, g_browser_process->GetApplicationLocale());
- user_input->language_code = AddressLanguageCodeForSection(section);
-
- static const size_t kSuggestionsLimit = 10;
- AddressValidator::Status status = GetValidator()->GetSuggestions(
- *user_input, focused_field, kSuggestionsLimit,
- &i18n_validator_suggestions_);
-
- if (status != AddressValidator::SUCCESS)
- return;
-
- for (size_t i = 0; i < i18n_validator_suggestions_.size(); ++i) {
- popup_suggestions->push_back(autofill::Suggestion(
- base::UTF8ToUTF16(
- i18n_validator_suggestions_[i].GetFieldValue(focused_field))));
-
- // Disambiguate the suggestion by showing the smallest administrative
- // region of the suggested address:
- // ADMIN_AREA > LOCALITY > DEPENDENT_LOCALITY
- for (int field = DEPENDENT_LOCALITY; field >= ADMIN_AREA; --field) {
- const std::string& field_value =
- i18n_validator_suggestions_[i].GetFieldValue(
- static_cast<AddressField>(field));
- if (focused_field != field && !field_value.empty()) {
- popup_suggestions->back().label = base::UTF8ToUTF16(field_value);
- break;
- }
- }
- }
-}
-
-DetailInputs* AutofillDialogControllerImpl::MutableRequestedFieldsForSection(
- DialogSection section) {
- return const_cast<DetailInputs*>(&RequestedFieldsForSection(section));
-}
-
-std::string* AutofillDialogControllerImpl::MutableAddressLanguageCodeForSection(
- DialogSection section) {
- switch (section) {
- case SECTION_BILLING:
- return &billing_address_language_code_;
- case SECTION_SHIPPING:
- return &shipping_address_language_code_;
- case SECTION_CC:
- return NULL;
- }
- NOTREACHED();
- return NULL;
-}
-
-std::string AutofillDialogControllerImpl::AddressLanguageCodeForSection(
- DialogSection section) {
- std::string* language_code = MutableAddressLanguageCodeForSection(section);
- return language_code != NULL ? *language_code : std::string();
-}
-
-std::vector<ServerFieldType> AutofillDialogControllerImpl::
- RequestedTypesForSection(DialogSection section) const {
- return TypesFromInputs(RequestedFieldsForSection(section));
-}
-
-std::string AutofillDialogControllerImpl::CountryCodeForSection(
- DialogSection section) {
- base::string16 country;
-
- std::unique_ptr<DataModelWrapper> wrapper = CreateWrapper(section);
- if (wrapper) {
- country = wrapper->GetInfo(AutofillType(CountryTypeForSection(section)));
- } else {
- FieldValueMap outputs;
- view_->GetUserInput(section, &outputs);
- country = outputs[CountryTypeForSection(section)];
- }
-
- return CountryNames::GetInstance()->GetCountryCode(country);
-}
-
-bool AutofillDialogControllerImpl::RebuildInputsForCountry(
- DialogSection section,
- const base::string16& country_name,
- bool should_clobber) {
- CountryComboboxModel* model = CountryComboboxModelForSection(section);
- if (!model)
- return false;
-
- std::string country_code =
- CountryNames::GetInstance()->GetCountryCode(country_name);
- DCHECK(CanAcceptCountry(section, country_code));
-
- if (view_ && !should_clobber) {
- FieldValueMap outputs;
- view_->GetUserInput(section, &outputs);
-
- // If |country_name| is the same as the view, no-op and let the caller know.
- if (outputs[CountryTypeForSection(section)] == country_name)
- return false;
- }
-
- DetailInputs* inputs = MutableRequestedFieldsForSection(section);
- inputs->clear();
- BuildInputsForSection(section, country_code, inputs,
- MutableAddressLanguageCodeForSection(section));
-
- if (!country_code.empty()) {
- GetValidator()->LoadRules(
- CountryNames::GetInstance()->GetCountryCode(country_name));
- }
-
- return true;
-}
-
-void AutofillDialogControllerImpl::HidePopup() {
- if (popup_controller_)
- popup_controller_->Hide();
- popup_input_type_ = UNKNOWN_TYPE;
-}
-
-void AutofillDialogControllerImpl::SetEditingExistingData(
- DialogSection section, bool editing) {
- if (editing)
- section_editing_state_.insert(section);
- else
- section_editing_state_.erase(section);
-}
-
-bool AutofillDialogControllerImpl::IsASuggestionItemKey(
- const std::string& key) const {
- return !key.empty() &&
- key != kAddNewItemKey &&
- key != kManageItemsKey &&
- key != kSameAsBillingKey;
-}
-
-bool AutofillDialogControllerImpl::IsAutofillEnabled() const {
- return profile_->GetPrefs()->GetBoolean(prefs::kAutofillEnabled);
-}
-
-bool AutofillDialogControllerImpl::IsManuallyEditingAnySection() const {
- for (size_t section = SECTION_MIN; section <= SECTION_MAX; ++section) {
- if (IsManuallyEditingSection(static_cast<DialogSection>(section)))
- return true;
- }
- return false;
-}
-
-base::string16 AutofillDialogControllerImpl::CreditCardNumberValidityMessage(
- const base::string16& number) const {
- if (!number.empty() && !autofill::IsValidCreditCardNumber(number)) {
- return l10n_util::GetStringUTF16(
- IDS_AUTOFILL_DIALOG_VALIDATION_INVALID_CREDIT_CARD_NUMBER);
- }
-
- if (ShouldDisallowCcType(
- CreditCard::TypeForDisplay(CreditCard::GetCreditCardType(number)))) {
- int ids = IDS_AUTOFILL_DIALOG_VALIDATION_UNACCEPTED_GENERIC_CARD;
- const char* const type = CreditCard::GetCreditCardType(number);
- if (type == kAmericanExpressCard)
- ids = IDS_AUTOFILL_DIALOG_VALIDATION_UNACCEPTED_AMEX;
- else if (type == kDiscoverCard)
- ids = IDS_AUTOFILL_DIALOG_VALIDATION_UNACCEPTED_DISCOVER;
- else if (type == kMasterCard)
- ids = IDS_AUTOFILL_DIALOG_VALIDATION_UNACCEPTED_MASTERCARD;
- else if (type == kVisaCard)
- ids = IDS_AUTOFILL_DIALOG_VALIDATION_UNACCEPTED_VISA;
-
- return l10n_util::GetStringUTF16(ids);
- }
-
- // Card number is good and supported.
- return base::string16();
-}
-
-bool AutofillDialogControllerImpl::AllSectionsAreValid() {
- for (size_t section = SECTION_MIN; section <= SECTION_MAX; ++section) {
- if (!SectionIsValid(static_cast<DialogSection>(section)))
- return false;
- }
- return true;
-}
-
-bool AutofillDialogControllerImpl::SectionIsValid(
- DialogSection section) {
- if (!IsManuallyEditingSection(section))
- return true;
-
- FieldValueMap detail_outputs;
- view_->GetUserInput(section, &detail_outputs);
- return !InputsAreValid(section, detail_outputs).HasSureErrors();
-}
-
-bool AutofillDialogControllerImpl::RulesAreLoaded(DialogSection section) {
- AddressData address_data;
- address_data.region_code = CountryCodeForSection(section);
- AddressValidator::Status status = GetValidator()->ValidateAddress(
- address_data, NULL, NULL);
- return status == AddressValidator::SUCCESS;
-}
-
-bool AutofillDialogControllerImpl::ShouldDisallowCcType(
- const base::string16& type) const {
- if (acceptable_cc_types_.empty())
- return false;
-
- if (acceptable_cc_types_.find(base::i18n::ToUpper(type)) ==
- acceptable_cc_types_.end()) {
- return true;
- }
-
- return false;
-}
-
-bool AutofillDialogControllerImpl::HasInvalidAddress(
- const AutofillProfile& profile) {
- std::unique_ptr<AddressData> address_data =
- i18n::CreateAddressDataFromAutofillProfile(
- profile, g_browser_process->GetApplicationLocale());
-
- FieldProblemMap problems;
- GetValidator()->ValidateAddress(*address_data, NULL, &problems);
- return !problems.empty();
-}
-
-bool AutofillDialogControllerImpl::ShouldUseBillingForShipping() {
- return SectionIsActive(SECTION_SHIPPING) &&
- suggested_shipping_.GetItemKeyForCheckedItem() == kSameAsBillingKey;
-}
-
-bool AutofillDialogControllerImpl::ShouldSaveDetailsLocally() {
- // It's possible that the user checked [X] Save details locally before
- // switching payment methods, so only ask the view whether to save details
- // locally if that checkbox is showing (currently if not paying with wallet).
- // Also, if the user isn't editing any sections, there's no data to save
- // locally.
- return ShouldOfferToSaveInChrome() && view_->SaveDetailsLocally();
-}
-
-void AutofillDialogControllerImpl::FinishSubmit() {
- FillOutputForSection(SECTION_CC);
- FillOutputForSection(SECTION_BILLING);
-
- if (ShouldUseBillingForShipping()) {
- FillOutputForSectionWithComparator(
- SECTION_BILLING,
- base::Bind(ServerTypeMatchesShippingField));
- FillOutputForSectionWithComparator(
- SECTION_CC,
- base::Bind(ServerTypeMatchesShippingField));
- } else {
- FillOutputForSection(SECTION_SHIPPING);
- }
-
- if (ShouldOfferToSaveInChrome()) {
- for (size_t i = SECTION_MIN; i <= SECTION_MAX; ++i) {
- DialogSection section = static_cast<DialogSection>(i);
- if (!SectionIsActive(section) || section == SECTION_CC)
- continue;
-
- SuggestionsMenuModel* model = SuggestionsMenuModelForSection(section);
- std::string item_key = model->GetItemKeyForCheckedItem();
- if (IsASuggestionItemKey(item_key) || item_key == kSameAsBillingKey) {
- PersistAutofillChoice(section, item_key);
- } else if (item_key == kAddNewItemKey && ShouldSaveDetailsLocally()) {
- DCHECK(newly_saved_data_model_guids_.count(section));
- PersistAutofillChoice(section, newly_saved_data_model_guids_[section]);
- }
- }
-
- profile_->GetPrefs()->SetBoolean(::prefs::kAutofillDialogSaveData,
- view_->SaveDetailsLocally());
- }
-
- LogOnFinishSubmitMetrics();
-
- // Callback should be called as late as possible.
- callback_.Run(AutofillClient::AutocompleteResultSuccess,
- base::string16(),
- &form_structure_);
- data_was_passed_back_ = true;
-
- // This might delete us.
- Hide();
-}
-
-void AutofillDialogControllerImpl::OnAddressValidationRulesLoaded(
- const std::string& country_code,
- bool success) {
- // Rules may load instantly (during initialization, before the view is
- // even ready). We'll validate when the view is created.
- if (!view_)
- return;
-
- ScopedViewUpdates updates(view_.get());
-
- // TODO(dbeam): should we retry on failure?
- for (size_t i = SECTION_MIN; i <= SECTION_MAX; ++i) {
- DialogSection section = static_cast<DialogSection>(i);
- if (!SectionIsActive(section) ||
- CountryCodeForSection(section) != country_code) {
- continue;
- }
-
- if (IsManuallyEditingSection(section) && needs_validation_.count(section)) {
- view_->ValidateSection(section);
- needs_validation_.erase(section);
- } else if (success) {
- ShowEditUiIfBadSuggestion(section);
- UpdateSection(section);
- }
- }
-}
-
-void AutofillDialogControllerImpl::PersistAutofillChoice(
- DialogSection section,
- const std::string& guid) {
- DCHECK(ShouldOfferToSaveInChrome());
- std::unique_ptr<base::DictionaryValue> value(new base::DictionaryValue());
- value->SetString(kGuidPrefKey, guid);
-
- DictionaryPrefUpdate updater(profile()->GetPrefs(),
- ::prefs::kAutofillDialogAutofillDefault);
- base::DictionaryValue* autofill_choice = updater.Get();
- autofill_choice->Set(SectionToPrefString(section), value.release());
-}
-
-void AutofillDialogControllerImpl::GetDefaultAutofillChoice(
- DialogSection section,
- std::string* guid) {
- DCHECK(IsAutofillEnabled());
- // The default choice is the first thing in the menu that is a suggestion
- // item.
- SuggestionsMenuModel* model = SuggestionsMenuModelForSection(section);
- for (int i = 0; i < model->GetItemCount(); ++i) {
- // Try the first suggestion item that is enabled.
- if (IsASuggestionItemKey(model->GetItemKeyAt(i)) && model->IsEnabledAt(i)) {
- *guid = model->GetItemKeyAt(i);
- return;
- // Fall back to the first non-suggestion key.
- } else if (!IsASuggestionItemKey(model->GetItemKeyAt(i)) && guid->empty()) {
- *guid = model->GetItemKeyAt(i);
- }
- }
-}
-
-bool AutofillDialogControllerImpl::GetAutofillChoice(DialogSection section,
- std::string* guid) {
- DCHECK(IsAutofillEnabled());
- const base::DictionaryValue* choices = profile()->GetPrefs()->GetDictionary(
- ::prefs::kAutofillDialogAutofillDefault);
- if (!choices)
- return false;
-
- const base::DictionaryValue* choice = NULL;
- if (!choices->GetDictionary(SectionToPrefString(section), &choice))
- return false;
-
- choice->GetString(kGuidPrefKey, guid);
- return true;
-}
-
-void AutofillDialogControllerImpl::LogOnFinishSubmitMetrics() {
- AutofillMetrics::LogDialogUiDuration(
- base::Time::Now() - dialog_shown_timestamp_,
- AutofillMetrics::DIALOG_ACCEPTED);
-
- AutofillMetrics::LogDialogUiEvent(AutofillMetrics::DIALOG_UI_ACCEPTED);
-
- AutofillMetrics::DialogDismissalState dismissal_state;
- if (!IsManuallyEditingAnySection()) {
- dismissal_state = AutofillMetrics::DIALOG_ACCEPTED_EXISTING_AUTOFILL_DATA;
- } else if (ShouldSaveDetailsLocally()) {
- dismissal_state = AutofillMetrics::DIALOG_ACCEPTED_SAVE_TO_AUTOFILL;
- } else {
- dismissal_state = AutofillMetrics::DIALOG_ACCEPTED_NO_SAVE;
- }
-
- AutofillMetrics::LogDialogDismissalState(dismissal_state);
-}
-
-void AutofillDialogControllerImpl::LogOnCancelMetrics() {
- AutofillMetrics::LogDialogUiEvent(AutofillMetrics::DIALOG_UI_CANCELED);
-
- AutofillMetrics::DialogDismissalState dismissal_state;
- if (!IsManuallyEditingAnySection())
- dismissal_state = AutofillMetrics::DIALOG_CANCELED_NO_EDITS;
- else if (AllSectionsAreValid())
- dismissal_state = AutofillMetrics::DIALOG_CANCELED_NO_INVALID_FIELDS;
- else
- dismissal_state = AutofillMetrics::DIALOG_CANCELED_WITH_INVALID_FIELDS;
-
- AutofillMetrics::LogDialogDismissalState(dismissal_state);
-
- AutofillMetrics::LogDialogUiDuration(
- base::Time::Now() - dialog_shown_timestamp_,
- AutofillMetrics::DIALOG_CANCELED);
-}
-
-void AutofillDialogControllerImpl::LogSuggestionItemSelectedMetric(
- const SuggestionsMenuModel& model) {
- DialogSection section = SectionForSuggestionsMenuModel(model);
-
- AutofillMetrics::DialogUiEvent dialog_ui_event;
- if (model.GetItemKeyForCheckedItem() == kAddNewItemKey) {
- // Selected to add a new item.
- dialog_ui_event = common::DialogSectionToUiItemAddedEvent(section);
- } else if (IsASuggestionItemKey(model.GetItemKeyForCheckedItem())) {
- // Selected an existing item.
- dialog_ui_event = common::DialogSectionToUiSelectionChangedEvent(section);
- } else {
- // TODO(estade): add logging for "Manage items" or "Use billing for
- // shipping"?
- return;
- }
-
- AutofillMetrics::LogDialogUiEvent(dialog_ui_event);
-}
-
-void AutofillDialogControllerImpl::LogDialogLatencyToShow() {
- if (was_ui_latency_logged_)
- return;
-
- AutofillMetrics::LogDialogLatencyToShow(base::Time::Now() -
- dialog_shown_timestamp_);
- was_ui_latency_logged_ = true;
-}
-
-AutofillMetrics::DialogInitialUserStateMetric
- AutofillDialogControllerImpl::GetInitialUserState() const {
- // Consider a user to be an Autofill user if the user has any credit cards
- // or addresses saved. Check that the item count is greater than 2 because
- // an "empty" menu still has the "add new" menu item and "manage" menu item.
- const bool has_autofill_profiles =
- suggested_cc_.GetItemCount() > 2 ||
- suggested_billing_.GetItemCount() > 2;
-
- return has_autofill_profiles
- ? AutofillMetrics::DIALOG_USER_NOT_SIGNED_IN_HAS_AUTOFILL
- : AutofillMetrics::DIALOG_USER_NOT_SIGNED_IN_NO_AUTOFILL;
-}
-
-void AutofillDialogControllerImpl::OnSubmitButtonDelayEnd() {
- if (!view_)
- return;
- ScopedViewUpdates updates(view_.get());
- view_->UpdateButtonStrip();
-}
-
-} // namespace autofill

Powered by Google App Engine
This is Rietveld 408576698