Home | History | Annotate | Download | only in autofill
      1 // Copyright 2013 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "chrome/browser/ui/autofill/autofill_dialog_controller_impl.h"
      6 
      7 #include <algorithm>
      8 #include <map>
      9 #include <string>
     10 
     11 #include "apps/shell_window.h"
     12 #include "apps/shell_window_registry.h"
     13 #include "apps/ui/native_app_window.h"
     14 #include "base/base64.h"
     15 #include "base/bind.h"
     16 #include "base/i18n/case_conversion.h"
     17 #include "base/i18n/rtl.h"
     18 #include "base/logging.h"
     19 #include "base/prefs/pref_registry_simple.h"
     20 #include "base/prefs/pref_service.h"
     21 #include "base/prefs/scoped_user_pref_update.h"
     22 #include "base/rand_util.h"
     23 #include "base/strings/string_number_conversions.h"
     24 #include "base/strings/string_split.h"
     25 #include "base/strings/string_util.h"
     26 #include "base/strings/utf_string_conversions.h"
     27 #include "base/time/time.h"
     28 #include "chrome/browser/autofill/personal_data_manager_factory.h"
     29 #include "chrome/browser/browser_process.h"
     30 #include "chrome/browser/profiles/profile.h"
     31 #include "chrome/browser/ui/autofill/autofill_dialog_common.h"
     32 #include "chrome/browser/ui/autofill/autofill_dialog_view.h"
     33 #include "chrome/browser/ui/autofill/data_model_wrapper.h"
     34 #if !defined(OS_ANDROID)
     35 #include "chrome/browser/ui/autofill/generated_credit_card_bubble_controller.h"
     36 #include "chrome/browser/ui/autofill/new_credit_card_bubble_controller.h"
     37 #endif
     38 #include "chrome/browser/ui/browser.h"
     39 #include "chrome/browser/ui/browser_finder.h"
     40 #include "chrome/browser/ui/browser_navigator.h"
     41 #include "chrome/browser/ui/browser_window.h"
     42 #include "chrome/common/chrome_version_info.h"
     43 #include "chrome/common/pref_names.h"
     44 #include "chrome/common/render_messages.h"
     45 #include "chrome/common/url_constants.h"
     46 #include "components/autofill/content/browser/risk/fingerprint.h"
     47 #include "components/autofill/content/browser/risk/proto/fingerprint.pb.h"
     48 #include "components/autofill/content/browser/wallet/form_field_error.h"
     49 #include "components/autofill/content/browser/wallet/full_wallet.h"
     50 #include "components/autofill/content/browser/wallet/gaia_account.h"
     51 #include "components/autofill/content/browser/wallet/instrument.h"
     52 #include "components/autofill/content/browser/wallet/wallet_address.h"
     53 #include "components/autofill/content/browser/wallet/wallet_items.h"
     54 #include "components/autofill/content/browser/wallet/wallet_service_url.h"
     55 #include "components/autofill/content/browser/wallet/wallet_signin_helper.h"
     56 #include "components/autofill/core/browser/autofill_country.h"
     57 #include "components/autofill/core/browser/autofill_data_model.h"
     58 #include "components/autofill/core/browser/autofill_manager.h"
     59 #include "components/autofill/core/browser/autofill_type.h"
     60 #include "components/autofill/core/browser/personal_data_manager.h"
     61 #include "components/autofill/core/browser/phone_number_i18n.h"
     62 #include "components/autofill/core/browser/validation.h"
     63 #include "components/autofill/core/common/form_data.h"
     64 #include "components/user_prefs/pref_registry_syncable.h"
     65 #include "content/public/browser/browser_thread.h"
     66 #include "content/public/browser/geolocation_provider.h"
     67 #include "content/public/browser/navigation_controller.h"
     68 #include "content/public/browser/navigation_details.h"
     69 #include "content/public/browser/navigation_entry.h"
     70 #include "content/public/browser/notification_service.h"
     71 #include "content/public/browser/notification_types.h"
     72 #include "content/public/browser/render_view_host.h"
     73 #include "content/public/browser/web_contents.h"
     74 #include "content/public/browser/web_contents_view.h"
     75 #include "content/public/common/url_constants.h"
     76 #include "grit/chromium_strings.h"
     77 #include "grit/component_strings.h"
     78 #include "grit/generated_resources.h"
     79 #include "grit/platform_locale_settings.h"
     80 #include "grit/theme_resources.h"
     81 #include "grit/webkit_resources.h"
     82 #include "net/cert/cert_status_flags.h"
     83 #include "ui/base/base_window.h"
     84 #include "ui/base/l10n/l10n_util.h"
     85 #include "ui/base/models/combobox_model.h"
     86 #include "ui/base/resource/resource_bundle.h"
     87 #include "ui/events/event.h"
     88 #include "ui/gfx/canvas.h"
     89 #include "ui/gfx/image/image_skia_operations.h"
     90 #include "ui/gfx/skia_util.h"
     91 
     92 namespace autofill {
     93 
     94 namespace {
     95 
     96 const char kAddNewItemKey[] = "add-new-item";
     97 const char kManageItemsKey[] = "manage-items";
     98 const char kSameAsBillingKey[] = "same-as-billing";
     99 
    100 // URLs for Wallet error messages.
    101 const char kBuyerLegalAddressStatusUrl[] =
    102     "https://wallet.google.com/manage/settings";
    103 const char kKnowYourCustomerStatusUrl[] = "https://wallet.google.com/kyc";
    104 
    105 // Keys for the kAutofillDialogAutofillDefault pref dictionary (do not change
    106 // these values).
    107 const char kGuidPrefKey[] = "guid";
    108 
    109 // This string is stored along with saved addresses and credit cards in the
    110 // WebDB, and hence should not be modified, so that it remains consistent over
    111 // time.
    112 const char kAutofillDialogOrigin[] = "Chrome Autofill dialog";
    113 
    114 // HSL shift to gray out an image.
    115 const color_utils::HSL kGrayImageShift = {-1, 0, 0.8};
    116 
    117 // Limit Wallet items refresh rate to at most once per minute.
    118 const int64 kWalletItemsRefreshRateSeconds = 60;
    119 
    120 // The number of milliseconds to delay enabling the submit button after showing
    121 // the dialog. This delay prevents users from accidentally clicking the submit
    122 // button on startup.
    123 const int kSubmitButtonDelayMs = 1000;
    124 
    125 // A helper class to make sure an AutofillDialogView knows when a series of
    126 // updates is incoming.
    127 class ScopedViewUpdates {
    128  public:
    129   explicit ScopedViewUpdates(AutofillDialogView* view) : view_(view) {
    130     if (view_)
    131       view_->UpdatesStarted();
    132   }
    133 
    134   ~ScopedViewUpdates() {
    135     if (view_)
    136       view_->UpdatesFinished();
    137   }
    138 
    139  private:
    140   AutofillDialogView* view_;
    141 
    142   DISALLOW_COPY_AND_ASSIGN(ScopedViewUpdates);
    143 };
    144 
    145 // Returns true if |input| should be used to fill a site-requested |field| which
    146 // is notated with a "shipping" tag, for use when the user has decided to use
    147 // the billing address as the shipping address.
    148 bool DetailInputMatchesShippingField(const DetailInput& input,
    149                                      const AutofillField& field) {
    150   // Equivalent billing field type is used to support UseBillingAsShipping
    151   // usecase.
    152   ServerFieldType field_type =
    153       AutofillType::GetEquivalentBillingFieldType(
    154           field.Type().GetStorableType());
    155 
    156   return common::InputTypeMatchesFieldType(input, AutofillType(field_type));
    157 }
    158 
    159 // Initializes |form_group| from user-entered data.
    160 void FillFormGroupFromOutputs(const FieldValueMap& detail_outputs,
    161                               FormGroup* form_group) {
    162   for (FieldValueMap::const_iterator iter = detail_outputs.begin();
    163        iter != detail_outputs.end(); ++iter) {
    164     ServerFieldType type = iter->first;
    165     if (!iter->second.empty()) {
    166       if (type == ADDRESS_HOME_COUNTRY || type == ADDRESS_BILLING_COUNTRY) {
    167         form_group->SetInfo(AutofillType(type),
    168                             iter->second,
    169                             g_browser_process->GetApplicationLocale());
    170       } else {
    171         form_group->SetRawInfo(
    172             AutofillType(type).GetStorableType(), iter->second);
    173       }
    174     }
    175   }
    176 }
    177 
    178 // Get billing info from |output| and put it into |card|, |cvc|, and |profile|.
    179 // These outparams are required because |card|/|profile| accept different types
    180 // of raw info, and CreditCard doesn't save CVCs.
    181 void GetBillingInfoFromOutputs(const FieldValueMap& output,
    182                                CreditCard* card,
    183                                base::string16* cvc,
    184                                AutofillProfile* profile) {
    185   for (FieldValueMap::const_iterator it = output.begin();
    186        it != output.end(); ++it) {
    187     const ServerFieldType type = it->first;
    188     base::string16 trimmed;
    189     TrimWhitespace(it->second, TRIM_ALL, &trimmed);
    190 
    191     // Special case CVC as CreditCard just swallows it.
    192     if (type == CREDIT_CARD_VERIFICATION_CODE) {
    193       if (cvc)
    194         cvc->assign(trimmed);
    195     } else if (type == ADDRESS_HOME_COUNTRY ||
    196                type == ADDRESS_BILLING_COUNTRY) {
    197       if (profile) {
    198         profile->SetInfo(AutofillType(type),
    199                          trimmed,
    200                          g_browser_process->GetApplicationLocale());
    201       }
    202     } else {
    203       // Copy the credit card name to |profile| in addition to |card| as
    204       // wallet::Instrument requires a recipient name for its billing address.
    205       if (card && type == NAME_FULL)
    206         card->SetRawInfo(CREDIT_CARD_NAME, trimmed);
    207 
    208       if (common::IsCreditCardType(type)) {
    209         if (card)
    210           card->SetRawInfo(type, trimmed);
    211       } else if (profile) {
    212         profile->SetRawInfo(AutofillType(type).GetStorableType(), trimmed);
    213       }
    214     }
    215   }
    216 }
    217 
    218 // Returns the containing window for the given |web_contents|. The containing
    219 // window might be a browser window for a Chrome tab, or it might be a shell
    220 // window for a platform app.
    221 ui::BaseWindow* GetBaseWindowForWebContents(
    222     const content::WebContents* web_contents) {
    223   Browser* browser = chrome::FindBrowserWithWebContents(web_contents);
    224   if (browser)
    225     return browser->window();
    226 
    227   gfx::NativeWindow native_window =
    228       web_contents->GetView()->GetTopLevelNativeWindow();
    229   apps::ShellWindow* shell_window =
    230       apps::ShellWindowRegistry::
    231           GetShellWindowForNativeWindowAnyProfile(native_window);
    232   return shell_window->GetBaseWindow();
    233 }
    234 
    235 // Returns a string descriptor for a DialogSection, for use with prefs (do not
    236 // change these values).
    237 std::string SectionToPrefString(DialogSection section) {
    238   switch (section) {
    239     case SECTION_CC:
    240       return "cc";
    241 
    242     case SECTION_BILLING:
    243       return "billing";
    244 
    245     case SECTION_CC_BILLING:
    246       // The SECTION_CC_BILLING section isn't active when using Autofill.
    247       NOTREACHED();
    248       return std::string();
    249 
    250     case SECTION_SHIPPING:
    251       return "shipping";
    252   }
    253 
    254   NOTREACHED();
    255   return std::string();
    256 }
    257 
    258 // Check if a given MaskedInstrument is allowed for the purchase.
    259 bool IsInstrumentAllowed(
    260     const wallet::WalletItems::MaskedInstrument& instrument) {
    261   switch (instrument.status()) {
    262     case wallet::WalletItems::MaskedInstrument::VALID:
    263     case wallet::WalletItems::MaskedInstrument::PENDING:
    264     case wallet::WalletItems::MaskedInstrument::EXPIRED:
    265     case wallet::WalletItems::MaskedInstrument::BILLING_INCOMPLETE:
    266       return true;
    267     default:
    268       return false;
    269   }
    270 }
    271 
    272 // Signals that the user has opted in to geolocation services.  Factored out
    273 // into a separate method because all interaction with the geolocation provider
    274 // needs to happen on the IO thread, which is not the thread
    275 // AutofillDialogViewDelegate lives on.
    276 void UserDidOptIntoLocationServices() {
    277   content::GeolocationProvider::GetInstance()->UserDidOptIntoLocationServices();
    278 }
    279 
    280 // Returns whether |data_model| is complete, i.e. can fill out all the
    281 // |requested_fields|, and verified, i.e. not just automatically aggregated.
    282 // Incomplete or unverifed data will not be displayed in the dropdown menu.
    283 bool HasCompleteAndVerifiedData(const AutofillDataModel& data_model,
    284                                 const DetailInputs& requested_fields) {
    285   if (!data_model.IsVerified())
    286     return false;
    287 
    288   for (size_t i = 0; i < requested_fields.size(); ++i) {
    289     ServerFieldType type =
    290         AutofillType(requested_fields[i].type).GetStorableType();
    291     if (type != ADDRESS_HOME_LINE2 &&
    292         type != CREDIT_CARD_VERIFICATION_CODE &&
    293         data_model.GetRawInfo(type).empty()) {
    294       return false;
    295     }
    296   }
    297 
    298   return true;
    299 }
    300 
    301 // Returns true if |profile| has an invalid address, i.e. an invalid state, zip
    302 // code, phone number, or email address. Otherwise returns false. Profiles with
    303 // invalid addresses are not suggested in the dropdown menu for billing and
    304 // shipping addresses.
    305 bool HasInvalidAddress(const AutofillProfile& profile) {
    306   return profile.IsPresentButInvalid(ADDRESS_HOME_STATE) ||
    307          profile.IsPresentButInvalid(ADDRESS_HOME_ZIP) ||
    308          profile.IsPresentButInvalid(PHONE_HOME_WHOLE_NUMBER);
    309 }
    310 
    311 // Loops through |addresses_| comparing to |address| ignoring ID. If a match
    312 // is not found, NULL is returned.
    313 const wallet::Address* FindDuplicateAddress(
    314     const std::vector<wallet::Address*>& addresses,
    315     const wallet::Address& address) {
    316   for (size_t i = 0; i < addresses.size(); ++i) {
    317     if (addresses[i]->EqualsIgnoreID(address))
    318       return addresses[i];
    319   }
    320   return NULL;
    321 }
    322 
    323 bool IsCardHolderNameValidForWallet(const base::string16& name) {
    324   base::string16 whitespace_collapsed_name = CollapseWhitespace(name, true);
    325   std::vector<base::string16> split_name;
    326   base::SplitString(whitespace_collapsed_name, ' ', &split_name);
    327   return split_name.size() >= 2;
    328 }
    329 
    330 DialogSection SectionFromLocation(wallet::FormFieldError::Location location) {
    331   switch (location) {
    332     case wallet::FormFieldError::PAYMENT_INSTRUMENT:
    333     case wallet::FormFieldError::LEGAL_ADDRESS:
    334       return SECTION_CC_BILLING;
    335 
    336     case wallet::FormFieldError::SHIPPING_ADDRESS:
    337       return SECTION_SHIPPING;
    338 
    339     case wallet::FormFieldError::UNKNOWN_LOCATION:
    340       NOTREACHED();
    341       return SECTION_MAX;
    342   }
    343 
    344   NOTREACHED();
    345   return SECTION_MAX;
    346 }
    347 
    348 scoped_ptr<DialogNotification> GetWalletError(
    349     wallet::WalletClient::ErrorType error_type) {
    350   base::string16 text;
    351   GURL url;
    352 
    353   switch (error_type) {
    354     case wallet::WalletClient::UNVERIFIED_KNOW_YOUR_CUSTOMER_STATUS:
    355       text = l10n_util::GetStringUTF16(
    356           IDS_AUTOFILL_WALLET_UNVERIFIED_KNOW_YOUR_CUSTOMER_STATUS);
    357       url = GURL(kKnowYourCustomerStatusUrl);
    358       break;
    359 
    360     case wallet::WalletClient::BUYER_LEGAL_ADDRESS_NOT_SUPPORTED:
    361       text = l10n_util::GetStringUTF16(
    362           IDS_AUTOFILL_WALLET_BUYER_COUNTRY_NOT_SUPPORTED);
    363       url = GURL(kBuyerLegalAddressStatusUrl);
    364       break;
    365 
    366     default:
    367       // The notification will not have a link; it's handled in the next
    368       // switch statement.
    369       break;
    370   }
    371 
    372   if (!text.empty()) {
    373     scoped_ptr<DialogNotification> notification(new DialogNotification(
    374         DialogNotification::WALLET_ERROR,
    375         text));
    376     notification->set_link_url(url);
    377     return notification.Pass();
    378   }
    379 
    380   int error_ids = 0;
    381   int error_code = 0;
    382 
    383   switch (error_type) {
    384     case wallet::WalletClient::UNSUPPORTED_MERCHANT:
    385       error_ids = IDS_AUTOFILL_WALLET_UNSUPPORTED_MERCHANT;
    386       break;
    387 
    388     case wallet::WalletClient::BAD_REQUEST:
    389       error_ids = IDS_AUTOFILL_WALLET_UPGRADE_CHROME_ERROR;
    390       error_code = 71;
    391       break;
    392 
    393     case wallet::WalletClient::INVALID_PARAMS:
    394       error_ids = IDS_AUTOFILL_WALLET_UPGRADE_CHROME_ERROR;
    395       error_code = 42;
    396       break;
    397 
    398     case wallet::WalletClient::BUYER_ACCOUNT_ERROR:
    399       error_ids = IDS_AUTOFILL_WALLET_BUYER_ACCOUNT_ERROR;
    400       error_code = 12;
    401       break;
    402 
    403     case wallet::WalletClient::UNSUPPORTED_API_VERSION:
    404       error_ids = IDS_AUTOFILL_WALLET_UPGRADE_CHROME_ERROR;
    405       error_code = 43;
    406       break;
    407 
    408     case wallet::WalletClient::SERVICE_UNAVAILABLE:
    409       error_ids = IDS_AUTOFILL_WALLET_SERVICE_UNAVAILABLE_ERROR;
    410       error_code = 61;
    411       break;
    412 
    413     case wallet::WalletClient::INTERNAL_ERROR:
    414       error_ids = IDS_AUTOFILL_WALLET_UNKNOWN_ERROR;
    415       error_code = 62;
    416       break;
    417 
    418     case wallet::WalletClient::MALFORMED_RESPONSE:
    419       error_ids = IDS_AUTOFILL_WALLET_UNKNOWN_ERROR;
    420       error_code = 72;
    421       break;
    422 
    423     case wallet::WalletClient::NETWORK_ERROR:
    424       error_ids = IDS_AUTOFILL_WALLET_UNKNOWN_ERROR;
    425       error_code = 73;
    426       break;
    427 
    428     case wallet::WalletClient::UNKNOWN_ERROR:
    429       error_ids = IDS_AUTOFILL_WALLET_UNKNOWN_ERROR;
    430       error_code = 74;
    431       break;
    432 
    433     default:
    434       break;
    435   }
    436 
    437   DCHECK_NE(0, error_ids);
    438 
    439   // The other error types are strings of the form "XXX. You can pay without
    440   // wallet."
    441   scoped_ptr<DialogNotification> notification(new DialogNotification(
    442       DialogNotification::WALLET_ERROR,
    443       l10n_util::GetStringFUTF16(IDS_AUTOFILL_DIALOG_COMPLETE_WITHOUT_WALLET,
    444                                  l10n_util::GetStringUTF16(error_ids))));
    445 
    446   if (error_code) {
    447     notification->set_tooltip_text(
    448         l10n_util::GetStringFUTF16(IDS_AUTOFILL_WALLET_ERROR_CODE_TOOLTIP,
    449                                    base::IntToString16(error_code)));
    450   }
    451 
    452   return notification.Pass();
    453 }
    454 
    455 // Returns the ID of the address or instrument that should be selected in the
    456 // UI, given that the |default_id| is currently the default ID on the Wallet
    457 // server, |previous_default_id| was the default ID prior to re-fetching the
    458 // Wallet data, and |previously_selected_id| was the ID of the item selected in
    459 // the dialog prior to re-fetching the Wallet data.
    460 std::string GetIdToSelect(const std::string& default_id,
    461                           const std::string& previous_default_id,
    462                           const std::string& previously_selected_id) {
    463   // If the default ID changed since the last fetch of the Wallet data, select
    464   // it rather than the previously selected item, as the user's intention in
    465   // changing the default was probably to use it.
    466   if (default_id != previous_default_id)
    467     return default_id;
    468 
    469   // Otherwise, prefer the previously selected item, if there was one.
    470   return !previously_selected_id.empty() ? previously_selected_id : default_id;
    471 }
    472 
    473 // Generate a random card number in a user displayable format.
    474 base::string16 GenerateRandomCardNumber() {
    475   std::string card_number;
    476   for (size_t i = 0; i < 4; ++i) {
    477     int part = base::RandInt(0, 10000);
    478     base::StringAppendF(&card_number, "%04d ", part);
    479   }
    480   return ASCIIToUTF16(card_number);
    481 }
    482 
    483 gfx::Image CreditCardIconForType(const std::string& credit_card_type) {
    484   const int input_card_idr = CreditCard::IconResourceId(credit_card_type);
    485   ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
    486   gfx::Image result = rb.GetImageNamed(input_card_idr);
    487   if (input_card_idr == IDR_AUTOFILL_CC_GENERIC) {
    488     // When the credit card type is unknown, no image should be shown. However,
    489     // to simplify the view code on Mac, save space for the credit card image by
    490     // returning a transparent image of the appropriate size. Not all credit
    491     // card images are the same size, but none is larger than the Visa icon.
    492     result = gfx::Image(gfx::ImageSkiaOperations::CreateTransparentImage(
    493         rb.GetImageNamed(IDR_AUTOFILL_CC_VISA).AsImageSkia(), 0));
    494   }
    495   return result;
    496 }
    497 
    498 gfx::Image CvcIconForCreditCardType(const base::string16& credit_card_type) {
    499   ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
    500   if (credit_card_type == l10n_util::GetStringUTF16(IDS_AUTOFILL_CC_AMEX))
    501     return rb.GetImageNamed(IDR_CREDIT_CARD_CVC_HINT_AMEX);
    502 
    503   return rb.GetImageNamed(IDR_CREDIT_CARD_CVC_HINT);
    504 }
    505 
    506 }  // namespace
    507 
    508 AutofillDialogViewDelegate::~AutofillDialogViewDelegate() {}
    509 
    510 AutofillDialogControllerImpl::~AutofillDialogControllerImpl() {
    511   if (popup_controller_)
    512     popup_controller_->Hide();
    513 
    514   GetMetricLogger().LogDialogInitialUserState(initial_user_state_);
    515 }
    516 
    517 // static
    518 base::WeakPtr<AutofillDialogControllerImpl>
    519     AutofillDialogControllerImpl::Create(
    520     content::WebContents* contents,
    521     const FormData& form_structure,
    522     const GURL& source_url,
    523     const base::Callback<void(const FormStructure*)>& callback) {
    524   // AutofillDialogControllerImpl owns itself.
    525   AutofillDialogControllerImpl* autofill_dialog_controller =
    526       new AutofillDialogControllerImpl(contents,
    527                                        form_structure,
    528                                        source_url,
    529                                        callback);
    530   return autofill_dialog_controller->weak_ptr_factory_.GetWeakPtr();
    531 }
    532 
    533 // static
    534 void AutofillDialogController::RegisterPrefs(PrefRegistrySimple* registry) {
    535   registry->RegisterListPref(::prefs::kAutofillDialogWalletLocationAcceptance);
    536 }
    537 
    538 // static
    539 void AutofillDialogController::RegisterProfilePrefs(
    540     user_prefs::PrefRegistrySyncable* registry) {
    541   registry->RegisterBooleanPref(
    542       ::prefs::kAutofillDialogPayWithoutWallet,
    543       false,
    544       user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
    545   registry->RegisterDictionaryPref(
    546       ::prefs::kAutofillDialogAutofillDefault,
    547       user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
    548   registry->RegisterBooleanPref(
    549       ::prefs::kAutofillDialogSaveData,
    550       true,
    551       user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
    552   registry->RegisterBooleanPref(
    553       ::prefs::kAutofillDialogWalletShippingSameAsBilling,
    554       false,
    555       user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
    556 }
    557 
    558 // static
    559 base::WeakPtr<AutofillDialogController> AutofillDialogController::Create(
    560     content::WebContents* contents,
    561     const FormData& form_structure,
    562     const GURL& source_url,
    563     const base::Callback<void(const FormStructure*)>& callback) {
    564   return AutofillDialogControllerImpl::Create(contents,
    565                                               form_structure,
    566                                               source_url,
    567                                               callback);
    568 }
    569 
    570 void AutofillDialogControllerImpl::Show() {
    571   dialog_shown_timestamp_ = base::Time::Now();
    572 
    573   // Determine what field types should be included in the dialog.
    574   bool has_types = false;
    575   bool has_sections = false;
    576   form_structure_.ParseFieldTypesFromAutocompleteAttributes(
    577       &has_types, &has_sections);
    578 
    579   // Fail if the author didn't specify autocomplete types.
    580   if (!has_types) {
    581     callback_.Run(NULL);
    582     delete this;
    583     return;
    584   }
    585 
    586   // Log any relevant UI metrics and security exceptions.
    587   GetMetricLogger().LogDialogUiEvent(AutofillMetrics::DIALOG_UI_SHOWN);
    588 
    589   GetMetricLogger().LogDialogSecurityMetric(
    590       AutofillMetrics::SECURITY_METRIC_DIALOG_SHOWN);
    591 
    592   // The Autofill dialog is shown in response to a message from the renderer and
    593   // as such, it can only be made in the context of the current document. A call
    594   // to GetActiveEntry would return a pending entry, if there was one, which
    595   // would be a security bug. Therefore, we use the last committed URL for the
    596   // access checks.
    597   const GURL& current_url = web_contents()->GetLastCommittedURL();
    598   invoked_from_same_origin_ =
    599       current_url.GetOrigin() == source_url_.GetOrigin();
    600 
    601   if (!invoked_from_same_origin_) {
    602     GetMetricLogger().LogDialogSecurityMetric(
    603         AutofillMetrics::SECURITY_METRIC_CROSS_ORIGIN_FRAME);
    604   }
    605 
    606   common::BuildInputsForSection(SECTION_CC,
    607                                 &requested_cc_fields_);
    608   common::BuildInputsForSection(SECTION_BILLING,
    609                                 &requested_billing_fields_);
    610   common::BuildInputsForSection(SECTION_CC_BILLING,
    611                                 &requested_cc_billing_fields_);
    612   common::BuildInputsForSection(SECTION_SHIPPING,
    613                                 &requested_shipping_fields_);
    614 
    615   // Test whether we need to show the shipping section. If filling that section
    616   // would be a no-op, don't show it.
    617   const DetailInputs& inputs = RequestedFieldsForSection(SECTION_SHIPPING);
    618   EmptyDataModelWrapper empty_wrapper;
    619   cares_about_shipping_ = empty_wrapper.FillFormStructure(
    620       inputs,
    621       base::Bind(common::DetailInputMatchesField, SECTION_SHIPPING),
    622       &form_structure_);
    623 
    624   account_chooser_model_.reset(
    625       new AccountChooserModel(this,
    626                               profile_,
    627                               !ShouldShowAccountChooser(),
    628                               metric_logger_));
    629 
    630   if (account_chooser_model_->WalletIsSelected())
    631     FetchWalletCookie();
    632 
    633   // TODO(estade): don't show the dialog if the site didn't specify the right
    634   // fields. First we must figure out what the "right" fields are.
    635   SuggestionsUpdated();
    636   SubmitButtonDelayBegin();
    637   view_.reset(CreateView());
    638   view_->Show();
    639   GetManager()->AddObserver(this);
    640 
    641   if (!account_chooser_model_->WalletIsSelected())
    642     LogDialogLatencyToShow();
    643 }
    644 
    645 void AutofillDialogControllerImpl::Hide() {
    646   if (view_)
    647     view_->Hide();
    648 }
    649 
    650 void AutofillDialogControllerImpl::TabActivated() {
    651   // If the user switched away from this tab and then switched back, reload the
    652   // Wallet items, in case they've changed.
    653   int64 seconds_elapsed_since_last_refresh =
    654       (base::TimeTicks::Now() - last_wallet_items_fetch_timestamp_).InSeconds();
    655   if (IsPayingWithWallet() && wallet_items_ &&
    656       seconds_elapsed_since_last_refresh >= kWalletItemsRefreshRateSeconds) {
    657     GetWalletItems();
    658   }
    659 }
    660 
    661 TestableAutofillDialogView* AutofillDialogControllerImpl::GetTestableView() {
    662   return view_ ? view_->GetTestableView() : NULL;
    663 }
    664 
    665 ////////////////////////////////////////////////////////////////////////////////
    666 // AutofillDialogViewDelegate implementation.
    667 
    668 base::string16 AutofillDialogControllerImpl::DialogTitle() const {
    669   if (ShouldShowSpinner())
    670     return base::string16();
    671 
    672   return l10n_util::GetStringUTF16(IDS_AUTOFILL_DIALOG_TITLE);
    673 }
    674 
    675 base::string16 AutofillDialogControllerImpl::AccountChooserText() const {
    676   if (!account_chooser_model_->WalletIsSelected())
    677     return l10n_util::GetStringUTF16(IDS_AUTOFILL_DIALOG_PAYING_WITHOUT_WALLET);
    678 
    679   if (SignedInState() == SIGNED_IN)
    680     return account_chooser_model_->GetActiveWalletAccountName();
    681 
    682   // In this case, the account chooser should be showing the signin link.
    683   return base::string16();
    684 }
    685 
    686 base::string16 AutofillDialogControllerImpl::SignInLinkText() const {
    687   int ids = SignedInState() == NOT_CHECKED ?
    688       IDS_AUTOFILL_DIALOG_USE_WALLET_LINK :
    689       ShouldShowSignInWebView() ? IDS_AUTOFILL_DIALOG_CANCEL_SIGN_IN :
    690                                   IDS_AUTOFILL_DIALOG_SIGN_IN;
    691 
    692   return l10n_util::GetStringUTF16(ids);
    693 }
    694 
    695 base::string16 AutofillDialogControllerImpl::SpinnerText() const {
    696   return l10n_util::GetStringUTF16(IDS_AUTOFILL_DIALOG_LOADING);
    697 }
    698 
    699 base::string16 AutofillDialogControllerImpl::EditSuggestionText() const {
    700   return l10n_util::GetStringUTF16(IDS_AUTOFILL_DIALOG_EDIT);
    701 }
    702 
    703 base::string16 AutofillDialogControllerImpl::CancelButtonText() const {
    704   return l10n_util::GetStringUTF16(IDS_CANCEL);
    705 }
    706 
    707 base::string16 AutofillDialogControllerImpl::ConfirmButtonText() const {
    708   return l10n_util::GetStringUTF16(IsSubmitPausedOn(wallet::VERIFY_CVV) ?
    709       IDS_AUTOFILL_DIALOG_VERIFY_BUTTON : IDS_AUTOFILL_DIALOG_SUBMIT_BUTTON);
    710 }
    711 
    712 base::string16 AutofillDialogControllerImpl::SaveLocallyText() const {
    713   return l10n_util::GetStringUTF16(IDS_AUTOFILL_DIALOG_SAVE_LOCALLY_CHECKBOX);
    714 }
    715 
    716 base::string16 AutofillDialogControllerImpl::SaveLocallyTooltip() const {
    717   return l10n_util::GetStringUTF16(IDS_AUTOFILL_DIALOG_SAVE_LOCALLY_TOOLTIP);
    718 }
    719 
    720 base::string16 AutofillDialogControllerImpl::LegalDocumentsText() {
    721   if (!IsPayingWithWallet() || ShouldShowSignInWebView())
    722     return base::string16();
    723 
    724   return legal_documents_text_;
    725 }
    726 
    727 bool AutofillDialogControllerImpl::ShouldShowSpinner() const {
    728   return SignedInState() == REQUIRES_RESPONSE ||
    729          SignedInState() == REQUIRES_PASSIVE_SIGN_IN;
    730 }
    731 
    732 // TODO(estade): Only show account chooser for Wallet in the US.
    733 // http://crbug.com/323641
    734 bool AutofillDialogControllerImpl::ShouldShowAccountChooser() const {
    735   return !ShouldShowSpinner();
    736 }
    737 
    738 bool AutofillDialogControllerImpl::ShouldShowSignInWebView() const {
    739   return !signin_registrar_.IsEmpty();
    740 }
    741 
    742 GURL AutofillDialogControllerImpl::SignInUrl() const {
    743   return wallet::GetSignInUrl();
    744 }
    745 
    746 bool AutofillDialogControllerImpl::ShouldOfferToSaveInChrome() const {
    747   return !IsPayingWithWallet() &&
    748       !profile_->IsOffTheRecord() &&
    749       IsManuallyEditingAnySection() &&
    750       !ShouldShowSpinner();
    751 }
    752 
    753 bool AutofillDialogControllerImpl::ShouldSaveInChrome() const {
    754   return profile_->GetPrefs()->GetBoolean(::prefs::kAutofillDialogSaveData);
    755 }
    756 
    757 int AutofillDialogControllerImpl::GetDialogButtons() const {
    758   if (waiting_for_explicit_sign_in_response_)
    759     return ui::DIALOG_BUTTON_NONE;
    760 
    761   if (ShouldShowSpinner() && !handling_use_wallet_link_click_)
    762     return ui::DIALOG_BUTTON_CANCEL;
    763 
    764   return ui::DIALOG_BUTTON_OK | ui::DIALOG_BUTTON_CANCEL;
    765 }
    766 
    767 bool AutofillDialogControllerImpl::IsDialogButtonEnabled(
    768     ui::DialogButton button) const {
    769   if (button == ui::DIALOG_BUTTON_OK) {
    770     if (IsSubmitPausedOn(wallet::VERIFY_CVV))
    771       return true;
    772 
    773     if (ShouldShowSpinner() || is_submitting_)
    774       return false;
    775 
    776     if (submit_button_delay_timer_.IsRunning())
    777       return false;
    778 
    779     return true;
    780   }
    781 
    782   DCHECK_EQ(ui::DIALOG_BUTTON_CANCEL, button);
    783   return !is_submitting_ || IsSubmitPausedOn(wallet::VERIFY_CVV);
    784 }
    785 
    786 DialogOverlayState AutofillDialogControllerImpl::GetDialogOverlay() {
    787   bool show_wallet_interstitial = IsPayingWithWallet() && is_submitting_ &&
    788       !(full_wallet_ && !full_wallet_->required_actions().empty());
    789   if (!show_wallet_interstitial) {
    790     card_scrambling_delay_.Stop();
    791     card_scrambling_refresher_.Stop();
    792     return DialogOverlayState();
    793   }
    794 
    795   ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
    796   DialogOverlayState state;
    797   state.string.font = rb.GetFont(ui::ResourceBundle::BaseFont).DeriveFont(3);
    798   state.string.text_color = SK_ColorDKGRAY;
    799 
    800   const SkColor start_top_color = SkColorSetRGB(0xD6, 0xD6, 0xD6);
    801   const SkColor start_bottom_color = SkColorSetRGB(0x98, 0x98, 0x98);
    802   const SkColor final_top_color = SkColorSetRGB(0x52, 0x9F, 0xF8);
    803   const SkColor final_bottom_color = SkColorSetRGB(0x22, 0x75, 0xE5);
    804 
    805   if (full_wallet_ && full_wallet_->required_actions().empty()) {
    806     card_scrambling_delay_.Stop();
    807     card_scrambling_refresher_.Stop();
    808 
    809     base::string16 cc_number =
    810         full_wallet_->GetInfo(AutofillType(CREDIT_CARD_NUMBER));
    811     DCHECK_GE(cc_number.size(), 4U);
    812     state.image = GetGeneratedCardImage(
    813         ASCIIToUTF16("XXXX XXXX XXXX ") +
    814             cc_number.substr(cc_number.size() - 4),
    815         full_wallet_->billing_address()->recipient_name(),
    816         color_utils::AlphaBlend(
    817             final_top_color,
    818             start_top_color,
    819             255 * card_generated_animation_.GetCurrentValue()),
    820         color_utils::AlphaBlend(
    821             final_bottom_color,
    822             start_bottom_color,
    823             255 * card_generated_animation_.GetCurrentValue()));
    824 
    825     state.string.text = l10n_util::GetStringUTF16(
    826         IDS_AUTOFILL_DIALOG_CARD_GENERATION_DONE);
    827   } else {
    828     // Start the refresher if it isn't running. Wait one second before pumping
    829     // updates to the view.
    830     if (!card_scrambling_delay_.IsRunning() &&
    831         !card_scrambling_refresher_.IsRunning()) {
    832       scrambled_card_number_ = GenerateRandomCardNumber();
    833       card_scrambling_delay_.Start(
    834           FROM_HERE,
    835           base::TimeDelta::FromSeconds(1),
    836           this,
    837           &AutofillDialogControllerImpl::StartCardScramblingRefresher);
    838     }
    839 
    840     DCHECK(!scrambled_card_number_.empty());
    841     state.image = GetGeneratedCardImage(
    842         scrambled_card_number_,
    843         submitted_cardholder_name_,
    844         start_top_color,
    845         start_bottom_color);
    846 
    847     // "Submitting" waiting page.
    848     state.string.text = l10n_util::GetStringUTF16(
    849         IDS_AUTOFILL_DIALOG_CARD_GENERATION_IN_PROGRESS);
    850   }
    851 
    852   return state;
    853 }
    854 
    855 const std::vector<gfx::Range>& AutofillDialogControllerImpl::
    856     LegalDocumentLinks() {
    857   return legal_document_link_ranges_;
    858 }
    859 
    860 bool AutofillDialogControllerImpl::SectionIsActive(DialogSection section)
    861     const {
    862   if (IsSubmitPausedOn(wallet::VERIFY_CVV))
    863     return section == SECTION_CC_BILLING;
    864 
    865   if (!FormStructureCaresAboutSection(section))
    866     return false;
    867 
    868   if (IsPayingWithWallet())
    869     return section == SECTION_CC_BILLING || section == SECTION_SHIPPING;
    870 
    871   return section != SECTION_CC_BILLING;
    872 }
    873 
    874 void AutofillDialogControllerImpl::GetWalletItems() {
    875   ScopedViewUpdates updates(view_.get());
    876 
    877   wallet_items_requested_ = true;
    878   wallet::WalletClient* wallet_client = GetWalletClient();
    879   wallet_client->CancelRequests();
    880 
    881   previously_selected_instrument_id_.clear();
    882   previously_selected_shipping_address_id_.clear();
    883   if (wallet_items_) {
    884     previous_default_instrument_id_ = wallet_items_->default_instrument_id();
    885     previous_default_shipping_address_id_ = wallet_items_->default_address_id();
    886 
    887     const wallet::WalletItems::MaskedInstrument* instrument =
    888         ActiveInstrument();
    889     if (instrument)
    890       previously_selected_instrument_id_ = instrument->object_id();
    891 
    892     const wallet::Address* address = ActiveShippingAddress();
    893     if (address)
    894       previously_selected_shipping_address_id_ = address->object_id();
    895   }
    896 
    897   last_wallet_items_fetch_timestamp_ = base::TimeTicks::Now();
    898   passive_failed_ = false;
    899   wallet_items_.reset();
    900 
    901   // The "Loading..." page should be showing now, which should cause the
    902   // account chooser to hide.
    903   view_->UpdateAccountChooser();
    904   wallet_client->GetWalletItems();
    905 }
    906 
    907 void AutofillDialogControllerImpl::HideSignIn() {
    908   ScopedViewUpdates updates(view_.get());
    909   signin_registrar_.RemoveAll();
    910   view_->HideSignIn();
    911   view_->UpdateAccountChooser();
    912 }
    913 
    914 AutofillDialogControllerImpl::DialogSignedInState
    915     AutofillDialogControllerImpl::SignedInState() const {
    916   if (wallet_error_notification_)
    917     return SIGN_IN_DISABLED;
    918 
    919   if (signin_helper_ || (wallet_items_requested_ && !wallet_items_))
    920     return REQUIRES_RESPONSE;
    921 
    922   if (!wallet_items_requested_)
    923     return NOT_CHECKED;
    924 
    925   if (wallet_items_->HasRequiredAction(wallet::GAIA_AUTH) ||
    926       passive_failed_) {
    927     return REQUIRES_SIGN_IN;
    928   }
    929 
    930   if (wallet_items_->HasRequiredAction(wallet::PASSIVE_GAIA_AUTH))
    931     return REQUIRES_PASSIVE_SIGN_IN;
    932 
    933   return SIGNED_IN;
    934 }
    935 
    936 void AutofillDialogControllerImpl::SignedInStateUpdated() {
    937   if (!ShouldShowSpinner())
    938     waiting_for_explicit_sign_in_response_ = false;
    939 
    940   switch (SignedInState()) {
    941     case SIGNED_IN:
    942       LogDialogLatencyToShow();
    943       break;
    944 
    945     case REQUIRES_SIGN_IN:
    946       if (handling_use_wallet_link_click_)
    947         SignInLinkClicked();
    948       // Fall through.
    949     case SIGN_IN_DISABLED:
    950       // Switch to the local account and refresh the dialog.
    951       signin_helper_.reset();
    952       OnWalletSigninError();
    953       handling_use_wallet_link_click_ = false;
    954       break;
    955 
    956     case REQUIRES_PASSIVE_SIGN_IN:
    957       // Attempt to passively sign in the user.
    958       DCHECK(!signin_helper_);
    959       signin_helper_.reset(new wallet::WalletSigninHelper(
    960           this,
    961           profile_->GetRequestContext()));
    962       signin_helper_->StartPassiveSignin(GetWalletClient()->user_index());
    963       break;
    964 
    965     case NOT_CHECKED:
    966     case REQUIRES_RESPONSE:
    967       break;
    968   }
    969 }
    970 
    971 void AutofillDialogControllerImpl::OnWalletOrSigninUpdate() {
    972   ScopedViewUpdates updates(view_.get());
    973   SignedInStateUpdated();
    974   SuggestionsUpdated();
    975   UpdateAccountChooserView();
    976 
    977   if (view_) {
    978     view_->UpdateButtonStrip();
    979     view_->UpdateOverlay();
    980   }
    981 
    982   // On the first successful response, compute the initial user state metric.
    983   if (initial_user_state_ == AutofillMetrics::DIALOG_USER_STATE_UNKNOWN)
    984     initial_user_state_ = GetInitialUserState();
    985 }
    986 
    987 void AutofillDialogControllerImpl::OnWalletFormFieldError(
    988     const std::vector<wallet::FormFieldError>& form_field_errors) {
    989   if (form_field_errors.empty())
    990     return;
    991 
    992   for (std::vector<wallet::FormFieldError>::const_iterator it =
    993            form_field_errors.begin();
    994        it != form_field_errors.end(); ++it) {
    995     if (it->error_type() == wallet::FormFieldError::UNKNOWN_ERROR ||
    996         it->GetAutofillType() == MAX_VALID_FIELD_TYPE ||
    997         it->location() == wallet::FormFieldError::UNKNOWN_LOCATION) {
    998       wallet_server_validation_recoverable_ = false;
    999       break;
   1000     }
   1001     DialogSection section = SectionFromLocation(it->location());
   1002     wallet_errors_[section][it->GetAutofillType()] =
   1003         std::make_pair(it->GetErrorMessage(),
   1004                        GetValueFromSection(section, it->GetAutofillType()));
   1005   }
   1006 
   1007   // Unrecoverable validation errors.
   1008   if (!wallet_server_validation_recoverable_)
   1009     DisableWallet(wallet::WalletClient::UNKNOWN_ERROR);
   1010 
   1011   UpdateForErrors();
   1012 }
   1013 
   1014 void AutofillDialogControllerImpl::ConstructLegalDocumentsText() {
   1015   legal_documents_text_.clear();
   1016   legal_document_link_ranges_.clear();
   1017 
   1018   if (!wallet_items_)
   1019     return;
   1020 
   1021   PrefService* local_state = g_browser_process->local_state();
   1022   // List of users who have accepted location sharing for fraud protection
   1023   // on this device.
   1024   const base::ListValue* accepted =
   1025       local_state->GetList(::prefs::kAutofillDialogWalletLocationAcceptance);
   1026   bool has_accepted_location_sharing =
   1027       accepted->Find(base::StringValue(
   1028           account_chooser_model_->GetActiveWalletAccountName())) !=
   1029       accepted->end();
   1030 
   1031   if (wallet_items_->legal_documents().empty()) {
   1032     if (!has_accepted_location_sharing) {
   1033       legal_documents_text_ = l10n_util::GetStringUTF16(
   1034           IDS_AUTOFILL_DIALOG_LOCATION_DISCLOSURE);
   1035     }
   1036 
   1037     return;
   1038   }
   1039 
   1040   const std::vector<wallet::WalletItems::LegalDocument*>& documents =
   1041       wallet_items_->legal_documents();
   1042   // There should never be just one document because the privacy policy doc gets
   1043   // tacked on the end of other documents.
   1044   DCHECK_GE(documents.size(), 2U);
   1045 
   1046   std::vector<base::string16> link_names;
   1047   for (size_t i = 0; i < documents.size(); ++i) {
   1048     link_names.push_back(documents[i]->display_name());
   1049   }
   1050 
   1051   int resource_id = 0;
   1052   switch (documents.size()) {
   1053     case 2U:
   1054       resource_id = IDS_AUTOFILL_DIALOG_LEGAL_LINKS_2;
   1055       break;
   1056     case 3U:
   1057       resource_id = IDS_AUTOFILL_DIALOG_LEGAL_LINKS_3;
   1058       break;
   1059     case 4U:
   1060       resource_id = IDS_AUTOFILL_DIALOG_LEGAL_LINKS_4;
   1061       break;
   1062     case 5U:
   1063       resource_id = IDS_AUTOFILL_DIALOG_LEGAL_LINKS_5;
   1064       break;
   1065     case 6U:
   1066       resource_id = IDS_AUTOFILL_DIALOG_LEGAL_LINKS_6;
   1067       break;
   1068     default:
   1069       // We can only handle so many documents. For lack of a better way of
   1070       // handling document overflow, just error out if there are too many.
   1071       DisableWallet(wallet::WalletClient::UNKNOWN_ERROR);
   1072       return;
   1073   }
   1074 
   1075   std::vector<size_t> offsets;
   1076   base::string16 text =
   1077       l10n_util::GetStringFUTF16(resource_id, link_names,&offsets);
   1078 
   1079   // Tack on the location string if need be.
   1080   size_t base_offset = 0;
   1081   if (!has_accepted_location_sharing) {
   1082     text = l10n_util::GetStringFUTF16(
   1083         IDS_AUTOFILL_DIALOG_LOCATION_DISCLOSURE_WITH_LEGAL_DOCS,
   1084         text,
   1085         &base_offset);
   1086   }
   1087 
   1088   for (size_t i = 0; i < documents.size(); ++i) {
   1089     size_t link_start = offsets[i] + base_offset;
   1090     legal_document_link_ranges_.push_back(gfx::Range(
   1091         link_start, link_start + documents[i]->display_name().size()));
   1092   }
   1093   legal_documents_text_ = text;
   1094 }
   1095 
   1096 void AutofillDialogControllerImpl::ResetSectionInput(DialogSection section) {
   1097   SetEditingExistingData(section, false);
   1098 
   1099   DetailInputs* inputs = MutableRequestedFieldsForSection(section);
   1100   for (DetailInputs::iterator it = inputs->begin(); it != inputs->end(); ++it) {
   1101     it->initial_value = common::GetHardcodedValueForType(it->type);
   1102   }
   1103 }
   1104 
   1105 void AutofillDialogControllerImpl::ShowEditUiIfBadSuggestion(
   1106     DialogSection section) {
   1107   // |CreateWrapper()| returns an empty wrapper if |IsEditingExistingData()|, so
   1108   // get the wrapper before this potentially happens below.
   1109   scoped_ptr<DataModelWrapper> wrapper = CreateWrapper(section);
   1110 
   1111   // If the chosen item in |model| yields an empty suggestion text, it is
   1112   // invalid. In this case, show the edit UI and highlight invalid fields.
   1113   SuggestionsMenuModel* model = SuggestionsMenuModelForSection(section);
   1114   base::string16 unused, unused2;
   1115   if (IsASuggestionItemKey(model->GetItemKeyForCheckedItem()) &&
   1116       !SuggestionTextForSection(section, &unused, &unused2)) {
   1117     SetEditingExistingData(section, true);
   1118   }
   1119 
   1120   DetailInputs* inputs = MutableRequestedFieldsForSection(section);
   1121   if (wrapper && IsEditingExistingData(section))
   1122     wrapper->FillInputs(inputs);
   1123 }
   1124 
   1125 bool AutofillDialogControllerImpl::InputWasEdited(ServerFieldType type,
   1126                                                   const base::string16& value) {
   1127   if (value.empty())
   1128     return false;
   1129 
   1130   // If this is a combobox at the default value, don't preserve it.
   1131   ui::ComboboxModel* model = ComboboxModelForAutofillType(type);
   1132   if (model && model->GetItemAt(model->GetDefaultIndex()) == value)
   1133     return false;
   1134 
   1135   return true;
   1136 }
   1137 
   1138 FieldValueMap AutofillDialogControllerImpl::TakeUserInputSnapshot() {
   1139   FieldValueMap snapshot;
   1140   if (!view_)
   1141     return snapshot;
   1142 
   1143   for (size_t i = SECTION_MIN; i <= SECTION_MAX; ++i) {
   1144     DialogSection section = static_cast<DialogSection>(i);
   1145     SuggestionsMenuModel* model = SuggestionsMenuModelForSection(section);
   1146     if (model->GetItemKeyForCheckedItem() != kAddNewItemKey)
   1147       continue;
   1148 
   1149     FieldValueMap outputs;
   1150     view_->GetUserInput(section, &outputs);
   1151     // Remove fields that are empty, at their default values, or invalid.
   1152     for (FieldValueMap::iterator it = outputs.begin(); it != outputs.end();
   1153          ++it) {
   1154       if (InputWasEdited(it->first, it->second) &&
   1155           InputValidityMessage(section, it->first, it->second).empty()) {
   1156         snapshot.insert(std::make_pair(it->first, it->second));
   1157       }
   1158     }
   1159   }
   1160 
   1161   return snapshot;
   1162 }
   1163 
   1164 void AutofillDialogControllerImpl::RestoreUserInputFromSnapshot(
   1165     const FieldValueMap& snapshot) {
   1166   if (snapshot.empty())
   1167     return;
   1168 
   1169   FieldMapWrapper wrapper(snapshot);
   1170   for (size_t i = SECTION_MIN; i <= SECTION_MAX; ++i) {
   1171     DialogSection section = static_cast<DialogSection>(i);
   1172     if (!SectionIsActive(section))
   1173       continue;
   1174 
   1175     DetailInputs* inputs = MutableRequestedFieldsForSection(section);
   1176     wrapper.FillInputs(inputs);
   1177 
   1178     for (size_t i = 0; i < inputs->size(); ++i) {
   1179       if (InputWasEdited((*inputs)[i].type, (*inputs)[i].initial_value)) {
   1180         SuggestionsMenuModelForSection(section)->SetCheckedItem(kAddNewItemKey);
   1181         break;
   1182       }
   1183     }
   1184   }
   1185 }
   1186 
   1187 void AutofillDialogControllerImpl::UpdateSection(DialogSection section) {
   1188   if (view_)
   1189     view_->UpdateSection(section);
   1190 }
   1191 
   1192 void AutofillDialogControllerImpl::UpdateForErrors() {
   1193   if (!view_)
   1194     return;
   1195 
   1196   // Currently, the view should only need to be updated if there are
   1197   // |wallet_errors_| or validating a suggestion that's based on existing data.
   1198   bool should_update = !wallet_errors_.empty();
   1199   if (!should_update) {
   1200     for (size_t i = SECTION_MIN; i <= SECTION_MAX; ++i) {
   1201       if (IsEditingExistingData(static_cast<DialogSection>(i))) {
   1202         should_update = true;
   1203         break;
   1204       }
   1205     }
   1206   }
   1207 
   1208   if (should_update)
   1209     view_->UpdateForErrors();
   1210 }
   1211 
   1212 gfx::Image AutofillDialogControllerImpl::GetGeneratedCardImage(
   1213     const base::string16& card_number,
   1214     const base::string16& name,
   1215     const SkColor& gradient_top,
   1216     const SkColor& gradient_bottom) {
   1217   const int kCardWidthPx = 300;
   1218   const int kCardHeightPx = 190;
   1219   const gfx::Size size(kCardWidthPx, kCardHeightPx);
   1220   ui::ScaleFactor scale_factor = ui::GetScaleFactorForNativeView(
   1221       web_contents()->GetView()->GetNativeView());
   1222   gfx::Canvas canvas(size, ui::GetImageScale(scale_factor), false);
   1223 
   1224   gfx::Rect display_rect(size);
   1225 
   1226   skia::RefPtr<SkShader> shader = gfx::CreateGradientShader(
   1227       0, size.height(), gradient_top, gradient_bottom);
   1228   SkPaint paint;
   1229   paint.setShader(shader.get());
   1230   canvas.DrawRoundRect(display_rect, 8, paint);
   1231 
   1232   display_rect.Inset(20, 0, 0, 0);
   1233   gfx::Font font(l10n_util::GetStringUTF8(IDS_FIXED_FONT_FAMILY), 18);
   1234   gfx::FontList font_list(font);
   1235   gfx::ShadowValues shadows;
   1236   shadows.push_back(gfx::ShadowValue(gfx::Point(0, 1), 1.0, SK_ColorBLACK));
   1237   canvas.DrawStringRectWithShadows(
   1238       card_number,
   1239       font_list,
   1240       SK_ColorWHITE,
   1241       display_rect, 0, 0, shadows);
   1242 
   1243   base::string16 capitalized_name = base::i18n::ToUpper(name);
   1244   display_rect.Inset(0, size.height() / 2, 0, 0);
   1245   canvas.DrawStringRectWithShadows(
   1246       capitalized_name,
   1247       font_list,
   1248       SK_ColorWHITE,
   1249       display_rect, 0, 0, shadows);
   1250 
   1251   gfx::ImageSkia skia(canvas.ExtractImageRep());
   1252   return gfx::Image(skia);
   1253 }
   1254 
   1255 void AutofillDialogControllerImpl::StartCardScramblingRefresher() {
   1256   RefreshCardScramblingOverlay();
   1257   card_scrambling_refresher_.Start(
   1258       FROM_HERE,
   1259       base::TimeDelta::FromMilliseconds(75),
   1260       this,
   1261       &AutofillDialogControllerImpl::RefreshCardScramblingOverlay);
   1262 }
   1263 
   1264 void AutofillDialogControllerImpl::RefreshCardScramblingOverlay() {
   1265   scrambled_card_number_ = GenerateRandomCardNumber();
   1266   PushOverlayUpdate();
   1267 }
   1268 
   1269 void AutofillDialogControllerImpl::PushOverlayUpdate() {
   1270   if (view_) {
   1271     ScopedViewUpdates updates(view_.get());
   1272     view_->UpdateOverlay();
   1273   }
   1274 }
   1275 
   1276 const DetailInputs& AutofillDialogControllerImpl::RequestedFieldsForSection(
   1277     DialogSection section) const {
   1278   switch (section) {
   1279     case SECTION_CC:
   1280       return requested_cc_fields_;
   1281     case SECTION_BILLING:
   1282       return requested_billing_fields_;
   1283     case SECTION_CC_BILLING:
   1284       return requested_cc_billing_fields_;
   1285     case SECTION_SHIPPING:
   1286       return requested_shipping_fields_;
   1287   }
   1288 
   1289   NOTREACHED();
   1290   return requested_billing_fields_;
   1291 }
   1292 
   1293 ui::ComboboxModel* AutofillDialogControllerImpl::ComboboxModelForAutofillType(
   1294     ServerFieldType type) {
   1295   switch (type) {
   1296     case CREDIT_CARD_EXP_MONTH:
   1297       return &cc_exp_month_combobox_model_;
   1298 
   1299     case CREDIT_CARD_EXP_4_DIGIT_YEAR:
   1300       return &cc_exp_year_combobox_model_;
   1301 
   1302     case ADDRESS_HOME_COUNTRY:
   1303     case ADDRESS_BILLING_COUNTRY:
   1304       return &country_combobox_model_;
   1305 
   1306     default:
   1307       return NULL;
   1308   }
   1309 }
   1310 
   1311 ui::MenuModel* AutofillDialogControllerImpl::MenuModelForSection(
   1312     DialogSection section) {
   1313   SuggestionsMenuModel* model = SuggestionsMenuModelForSection(section);
   1314   // The shipping section menu is special. It will always show because there is
   1315   // a choice between "Use billing" and "enter new".
   1316   if (section == SECTION_SHIPPING)
   1317     return model;
   1318 
   1319   // For other sections, only show a menu if there's at least one suggestion.
   1320   for (int i = 0; i < model->GetItemCount(); ++i) {
   1321     if (IsASuggestionItemKey(model->GetItemKeyAt(i)))
   1322       return model;
   1323   }
   1324 
   1325   return NULL;
   1326 }
   1327 
   1328 ui::MenuModel* AutofillDialogControllerImpl::MenuModelForAccountChooser() {
   1329   // If there were unrecoverable Wallet errors, or if there are choices other
   1330   // than "Pay without the wallet", show the full menu.
   1331   // TODO(estade): this can present a braindead menu (only 1 option) when
   1332   // there's a wallet error.
   1333   if (wallet_error_notification_ ||
   1334       (SignedInState() == SIGNED_IN &&
   1335        account_chooser_model_->HasAccountsToChoose() &&
   1336        !ShouldShowSignInWebView())) {
   1337     return account_chooser_model_.get();
   1338   }
   1339 
   1340   // Otherwise, there is no menu, just a sign in link.
   1341   return NULL;
   1342 }
   1343 
   1344 gfx::Image AutofillDialogControllerImpl::AccountChooserImage() {
   1345   if (!MenuModelForAccountChooser() && !ShouldShowSignInWebView()) {
   1346     return ui::ResourceBundle::GetSharedInstance().GetImageNamed(
   1347         IDR_WALLET_ICON);
   1348   }
   1349 
   1350   return gfx::Image();
   1351 }
   1352 
   1353 gfx::Image AutofillDialogControllerImpl::ButtonStripImage() const {
   1354   if (IsPayingWithWallet()) {
   1355     return ui::ResourceBundle::GetSharedInstance().GetImageNamed(
   1356         IDR_WALLET_LOGO);
   1357   }
   1358 
   1359   return gfx::Image();
   1360 }
   1361 
   1362 base::string16 AutofillDialogControllerImpl::LabelForSection(
   1363     DialogSection section) const {
   1364   switch (section) {
   1365     case SECTION_CC:
   1366       return l10n_util::GetStringUTF16(IDS_AUTOFILL_DIALOG_SECTION_CC);
   1367     case SECTION_BILLING:
   1368     case SECTION_CC_BILLING:
   1369       return l10n_util::GetStringUTF16(IDS_AUTOFILL_DIALOG_SECTION_BILLING);
   1370     case SECTION_SHIPPING:
   1371       return l10n_util::GetStringUTF16(IDS_AUTOFILL_DIALOG_SECTION_SHIPPING);
   1372   }
   1373   NOTREACHED();
   1374   return base::string16();
   1375 }
   1376 
   1377 SuggestionState AutofillDialogControllerImpl::SuggestionStateForSection(
   1378     DialogSection section) {
   1379   base::string16 vertically_compact, horizontally_compact;
   1380   bool show_suggestion = SuggestionTextForSection(section,
   1381                                                   &vertically_compact,
   1382                                                   &horizontally_compact);
   1383   return SuggestionState(show_suggestion,
   1384                          vertically_compact,
   1385                          horizontally_compact,
   1386                          SuggestionIconForSection(section),
   1387                          ExtraSuggestionTextForSection(section),
   1388                          ExtraSuggestionIconForSection(section));
   1389 }
   1390 
   1391 bool AutofillDialogControllerImpl::SuggestionTextForSection(
   1392     DialogSection section,
   1393     base::string16* vertically_compact,
   1394     base::string16* horizontally_compact) {
   1395   base::string16 action_text = RequiredActionTextForSection(section);
   1396   if (!action_text.empty()) {
   1397     *vertically_compact = *horizontally_compact = action_text;
   1398     return true;
   1399   }
   1400 
   1401   // When the user has clicked 'edit' or a suggestion is somehow invalid (e.g. a
   1402   // user selects a credit card that has expired), don't show a suggestion (even
   1403   // though there is a profile selected in the model).
   1404   if (IsEditingExistingData(section))
   1405     return false;
   1406 
   1407   SuggestionsMenuModel* model = SuggestionsMenuModelForSection(section);
   1408   std::string item_key = model->GetItemKeyForCheckedItem();
   1409   if (item_key == kSameAsBillingKey) {
   1410     *vertically_compact = *horizontally_compact = l10n_util::GetStringUTF16(
   1411         IDS_AUTOFILL_DIALOG_USING_BILLING_FOR_SHIPPING);
   1412     return true;
   1413   }
   1414 
   1415   if (!IsASuggestionItemKey(item_key))
   1416     return false;
   1417 
   1418   scoped_ptr<DataModelWrapper> wrapper = CreateWrapper(section);
   1419   return wrapper->GetDisplayText(vertically_compact, horizontally_compact);
   1420 }
   1421 
   1422 base::string16 AutofillDialogControllerImpl::RequiredActionTextForSection(
   1423     DialogSection section) const {
   1424   if (section == SECTION_CC_BILLING && IsSubmitPausedOn(wallet::VERIFY_CVV)) {
   1425     const wallet::WalletItems::MaskedInstrument* current_instrument =
   1426         wallet_items_->GetInstrumentById(active_instrument_id_);
   1427     if (current_instrument)
   1428       return current_instrument->TypeAndLastFourDigits();
   1429 
   1430     FieldValueMap output;
   1431     view_->GetUserInput(section, &output);
   1432     CreditCard card;
   1433     GetBillingInfoFromOutputs(output, &card, NULL, NULL);
   1434     return card.TypeAndLastFourDigits();
   1435   }
   1436 
   1437   return base::string16();
   1438 }
   1439 
   1440 base::string16 AutofillDialogControllerImpl::ExtraSuggestionTextForSection(
   1441     DialogSection section) const {
   1442   if (section == SECTION_CC ||
   1443       (section == SECTION_CC_BILLING && IsSubmitPausedOn(wallet::VERIFY_CVV))) {
   1444     return l10n_util::GetStringUTF16(IDS_AUTOFILL_DIALOG_PLACEHOLDER_CVC);
   1445   }
   1446 
   1447   return base::string16();
   1448 }
   1449 
   1450 const wallet::WalletItems::MaskedInstrument* AutofillDialogControllerImpl::
   1451     ActiveInstrument() const {
   1452   if (!IsPayingWithWallet())
   1453     return NULL;
   1454 
   1455   const SuggestionsMenuModel* model =
   1456       SuggestionsMenuModelForSection(SECTION_CC_BILLING);
   1457   const std::string item_key = model->GetItemKeyForCheckedItem();
   1458   if (!IsASuggestionItemKey(item_key))
   1459     return NULL;
   1460 
   1461   int index;
   1462   if (!base::StringToInt(item_key, &index) || index < 0 ||
   1463       static_cast<size_t>(index) >= wallet_items_->instruments().size()) {
   1464     NOTREACHED();
   1465     return NULL;
   1466   }
   1467 
   1468   return wallet_items_->instruments()[index];
   1469 }
   1470 
   1471 const wallet::Address* AutofillDialogControllerImpl::
   1472     ActiveShippingAddress() const {
   1473   if (!IsPayingWithWallet() || !IsShippingAddressRequired())
   1474     return NULL;
   1475 
   1476   const SuggestionsMenuModel* model =
   1477       SuggestionsMenuModelForSection(SECTION_SHIPPING);
   1478   const std::string item_key = model->GetItemKeyForCheckedItem();
   1479   if (!IsASuggestionItemKey(item_key))
   1480     return NULL;
   1481 
   1482   int index;
   1483   if (!base::StringToInt(item_key, &index) || index < 0 ||
   1484       static_cast<size_t>(index) >= wallet_items_->addresses().size()) {
   1485     NOTREACHED();
   1486     return NULL;
   1487   }
   1488 
   1489   return wallet_items_->addresses()[index];
   1490 }
   1491 
   1492 scoped_ptr<DataModelWrapper> AutofillDialogControllerImpl::CreateWrapper(
   1493     DialogSection section) {
   1494   if (IsPayingWithWallet() && full_wallet_ &&
   1495       full_wallet_->required_actions().empty()) {
   1496     if (section == SECTION_CC_BILLING) {
   1497       return scoped_ptr<DataModelWrapper>(
   1498           new FullWalletBillingWrapper(full_wallet_.get()));
   1499     }
   1500     if (section == SECTION_SHIPPING) {
   1501       return scoped_ptr<DataModelWrapper>(
   1502           new FullWalletShippingWrapper(full_wallet_.get()));
   1503     }
   1504   }
   1505 
   1506   SuggestionsMenuModel* model = SuggestionsMenuModelForSection(section);
   1507   std::string item_key = model->GetItemKeyForCheckedItem();
   1508   if (!IsASuggestionItemKey(item_key) || IsManuallyEditingSection(section))
   1509     return scoped_ptr<DataModelWrapper>();
   1510 
   1511   if (IsPayingWithWallet()) {
   1512     if (section == SECTION_CC_BILLING) {
   1513       return scoped_ptr<DataModelWrapper>(
   1514           new WalletInstrumentWrapper(ActiveInstrument()));
   1515     }
   1516 
   1517     if (section == SECTION_SHIPPING) {
   1518       return scoped_ptr<DataModelWrapper>(
   1519           new WalletAddressWrapper(ActiveShippingAddress()));
   1520     }
   1521 
   1522     return scoped_ptr<DataModelWrapper>();
   1523   }
   1524 
   1525   if (section == SECTION_CC) {
   1526     CreditCard* card = GetManager()->GetCreditCardByGUID(item_key);
   1527     DCHECK(card);
   1528     return scoped_ptr<DataModelWrapper>(new AutofillCreditCardWrapper(card));
   1529   }
   1530 
   1531   AutofillProfile* profile = GetManager()->GetProfileByGUID(item_key);
   1532   DCHECK(profile);
   1533   if (section == SECTION_SHIPPING) {
   1534     return scoped_ptr<DataModelWrapper>(
   1535         new AutofillShippingAddressWrapper(profile));
   1536   }
   1537   DCHECK_EQ(SECTION_BILLING, section);
   1538   return scoped_ptr<DataModelWrapper>(
   1539       new AutofillProfileWrapper(profile));
   1540 }
   1541 
   1542 gfx::Image AutofillDialogControllerImpl::SuggestionIconForSection(
   1543     DialogSection section) {
   1544   scoped_ptr<DataModelWrapper> model = CreateWrapper(section);
   1545   if (!model.get())
   1546     return gfx::Image();
   1547 
   1548   return model->GetIcon();
   1549 }
   1550 
   1551 gfx::Image AutofillDialogControllerImpl::ExtraSuggestionIconForSection(
   1552     DialogSection section) {
   1553   if (section != SECTION_CC && section != SECTION_CC_BILLING)
   1554     return gfx::Image();
   1555 
   1556   scoped_ptr<DataModelWrapper> model = CreateWrapper(section);
   1557   if (!model.get())
   1558     return gfx::Image();
   1559 
   1560   return CvcIconForCreditCardType(
   1561       model->GetInfo(AutofillType(CREDIT_CARD_TYPE)));
   1562 }
   1563 
   1564 FieldIconMap AutofillDialogControllerImpl::IconsForFields(
   1565     const FieldValueMap& user_inputs) const {
   1566   FieldIconMap result;
   1567   base::string16 credit_card_type;
   1568 
   1569   FieldValueMap::const_iterator credit_card_iter =
   1570       user_inputs.find(CREDIT_CARD_NUMBER);
   1571   if (credit_card_iter != user_inputs.end()) {
   1572     const base::string16& number = credit_card_iter->second;
   1573     const std::string type = CreditCard::GetCreditCardType(number);
   1574     credit_card_type = CreditCard::TypeForDisplay(type);
   1575     result[CREDIT_CARD_NUMBER] = CreditCardIconForType(type);
   1576   }
   1577 
   1578   if (!user_inputs.count(CREDIT_CARD_VERIFICATION_CODE))
   1579     return result;
   1580 
   1581   result[CREDIT_CARD_VERIFICATION_CODE] =
   1582       CvcIconForCreditCardType(credit_card_type);
   1583 
   1584   return result;
   1585 }
   1586 
   1587 bool AutofillDialogControllerImpl::FieldControlsIcons(
   1588     ServerFieldType type) const {
   1589   return type == CREDIT_CARD_NUMBER;
   1590 }
   1591 
   1592 base::string16 AutofillDialogControllerImpl::TooltipForField(
   1593     ServerFieldType type) const {
   1594   if (type == PHONE_HOME_WHOLE_NUMBER || type == PHONE_BILLING_WHOLE_NUMBER)
   1595     return l10n_util::GetStringUTF16(IDS_AUTOFILL_DIALOG_TOOLTIP_PHONE_NUMBER);
   1596 
   1597   return base::string16();
   1598 }
   1599 
   1600 bool AutofillDialogControllerImpl::InputIsEditable(
   1601     const DetailInput& input,
   1602     DialogSection section) {
   1603   if (section != SECTION_CC_BILLING)
   1604     return true;
   1605 
   1606   if (input.type == CREDIT_CARD_NUMBER)
   1607     return !IsEditingExistingData(section);
   1608 
   1609   // For CVC, only require (allow) input if the user has edited some other
   1610   // aspect of the card.
   1611   if (input.type == CREDIT_CARD_VERIFICATION_CODE &&
   1612       IsEditingExistingData(section)) {
   1613     FieldValueMap output;
   1614     view_->GetUserInput(section, &output);
   1615     WalletInstrumentWrapper wrapper(ActiveInstrument());
   1616 
   1617     for (FieldValueMap::iterator iter = output.begin(); iter != output.end();
   1618          ++iter) {
   1619       if (iter->first == input.type)
   1620         continue;
   1621 
   1622       AutofillType type(iter->first);
   1623       if (type.group() == CREDIT_CARD &&
   1624           iter->second != wrapper.GetInfo(type)) {
   1625         return true;
   1626       }
   1627     }
   1628 
   1629     return false;
   1630   }
   1631 
   1632   return true;
   1633 }
   1634 
   1635 // TODO(groby): Add more tests.
   1636 base::string16 AutofillDialogControllerImpl::InputValidityMessage(
   1637     DialogSection section,
   1638     ServerFieldType type,
   1639     const base::string16& value) {
   1640   // If the field is edited, clear any Wallet errors.
   1641   if (IsPayingWithWallet()) {
   1642     WalletValidationErrors::iterator it = wallet_errors_.find(section);
   1643     if (it != wallet_errors_.end()) {
   1644       TypeErrorInputMap::const_iterator iter = it->second.find(type);
   1645       if (iter != it->second.end()) {
   1646         if (iter->second.second == value)
   1647           return iter->second.first;
   1648         it->second.erase(type);
   1649       }
   1650     }
   1651   }
   1652 
   1653   switch (AutofillType(type).GetStorableType()) {
   1654     case EMAIL_ADDRESS:
   1655       if (!value.empty() && !IsValidEmailAddress(value)) {
   1656         return l10n_util::GetStringUTF16(
   1657             IDS_AUTOFILL_DIALOG_VALIDATION_INVALID_EMAIL_ADDRESS);
   1658       }
   1659       break;
   1660 
   1661     case CREDIT_CARD_NUMBER: {
   1662       if (!value.empty()) {
   1663         base::string16 message = CreditCardNumberValidityMessage(value);
   1664         if (!message.empty())
   1665           return message;
   1666       }
   1667       break;
   1668     }
   1669 
   1670     case CREDIT_CARD_EXP_MONTH:
   1671       if (!InputWasEdited(CREDIT_CARD_EXP_MONTH, value)) {
   1672         return l10n_util::GetStringUTF16(
   1673             IDS_AUTOFILL_DIALOG_VALIDATION_MISSING_VALUE);
   1674       }
   1675       break;
   1676 
   1677     case CREDIT_CARD_EXP_4_DIGIT_YEAR:
   1678       if (!InputWasEdited(CREDIT_CARD_EXP_4_DIGIT_YEAR, value)) {
   1679         return l10n_util::GetStringUTF16(
   1680             IDS_AUTOFILL_DIALOG_VALIDATION_MISSING_VALUE);
   1681       }
   1682       break;
   1683 
   1684     case CREDIT_CARD_VERIFICATION_CODE:
   1685       if (!value.empty() && !autofill::IsValidCreditCardSecurityCode(value)) {
   1686         return l10n_util::GetStringUTF16(
   1687             IDS_AUTOFILL_DIALOG_VALIDATION_INVALID_CREDIT_CARD_SECURITY_CODE);
   1688       }
   1689       break;
   1690 
   1691     case ADDRESS_HOME_LINE1:
   1692       break;
   1693 
   1694     case ADDRESS_HOME_LINE2:
   1695       return base::string16();  // Line 2 is optional - always valid.
   1696 
   1697     case ADDRESS_HOME_CITY:
   1698     case ADDRESS_HOME_COUNTRY:
   1699       break;
   1700 
   1701     case ADDRESS_HOME_STATE:
   1702       if (!value.empty() && !autofill::IsValidState(value)) {
   1703         return l10n_util::GetStringUTF16(
   1704             IDS_AUTOFILL_DIALOG_VALIDATION_INVALID_REGION);
   1705       }
   1706       break;
   1707 
   1708     case ADDRESS_HOME_ZIP:
   1709       if (!value.empty() && !autofill::IsValidZip(value)) {
   1710         return l10n_util::GetStringUTF16(
   1711             IDS_AUTOFILL_DIALOG_VALIDATION_INVALID_ZIP_CODE);
   1712       }
   1713       break;
   1714 
   1715     case NAME_FULL:
   1716       // Wallet requires a first and last billing name.
   1717       if (section == SECTION_CC_BILLING && !value.empty() &&
   1718           !IsCardHolderNameValidForWallet(value)) {
   1719         DCHECK(IsPayingWithWallet());
   1720         return l10n_util::GetStringUTF16(
   1721             IDS_AUTOFILL_DIALOG_VALIDATION_WALLET_REQUIRES_TWO_NAMES);
   1722       }
   1723       break;
   1724 
   1725     case PHONE_HOME_WHOLE_NUMBER:  // Used in shipping section.
   1726       break;
   1727 
   1728     case PHONE_BILLING_WHOLE_NUMBER:  // Used in billing section.
   1729       break;
   1730 
   1731     default:
   1732       NOTREACHED();  // Trying to validate unknown field.
   1733       break;
   1734   }
   1735 
   1736   return value.empty() ?
   1737       l10n_util::GetStringUTF16(IDS_AUTOFILL_DIALOG_VALIDATION_MISSING_VALUE) :
   1738       base::string16();
   1739 }
   1740 
   1741 // TODO(groby): Also add tests.
   1742 ValidityMessages AutofillDialogControllerImpl::InputsAreValid(
   1743     DialogSection section,
   1744     const FieldValueMap& inputs) {
   1745   ValidityMessages messages;
   1746   std::map<ServerFieldType, base::string16> field_values;
   1747   for (FieldValueMap::const_iterator iter = inputs.begin();
   1748        iter != inputs.end(); ++iter) {
   1749     const ServerFieldType type = iter->first;
   1750 
   1751     base::string16 text = InputValidityMessage(section, type, iter->second);
   1752 
   1753     // Skip empty/unchanged fields in edit mode. Ignore country code as it
   1754     // always has a value. If the individual field does not have validation
   1755     // errors, assume it to be valid unless later proven otherwise.
   1756     bool sure = InputWasEdited(type, iter->second) ||
   1757                 ComboboxModelForAutofillType(type) == &country_combobox_model_;
   1758 
   1759     // Consider only individually valid fields for inter-field validation.
   1760     if (text.empty()) {
   1761       field_values[type] = iter->second;
   1762       // If the field is valid but can be invalidated by inter-field validation,
   1763       // assume it to be unsure.
   1764       if (type == CREDIT_CARD_EXP_4_DIGIT_YEAR ||
   1765           type == CREDIT_CARD_EXP_MONTH ||
   1766           type == CREDIT_CARD_VERIFICATION_CODE ||
   1767           type == PHONE_HOME_WHOLE_NUMBER ||
   1768           type == PHONE_BILLING_WHOLE_NUMBER) {
   1769         sure = false;
   1770       }
   1771     }
   1772     messages.Set(type, ValidityMessage(text, sure));
   1773   }
   1774 
   1775   // Validate the date formed by month and year field. (Autofill dialog is
   1776   // never supposed to have 2-digit years, so not checked).
   1777   if (field_values.count(CREDIT_CARD_EXP_4_DIGIT_YEAR) &&
   1778       field_values.count(CREDIT_CARD_EXP_MONTH) &&
   1779       InputWasEdited(CREDIT_CARD_EXP_4_DIGIT_YEAR,
   1780                      field_values[CREDIT_CARD_EXP_4_DIGIT_YEAR]) &&
   1781       InputWasEdited(CREDIT_CARD_EXP_MONTH,
   1782                      field_values[CREDIT_CARD_EXP_MONTH])) {
   1783     ValidityMessage year_message(base::string16(), true);
   1784     ValidityMessage month_message(base::string16(), true);
   1785     if (!IsCreditCardExpirationValid(field_values[CREDIT_CARD_EXP_4_DIGIT_YEAR],
   1786                                      field_values[CREDIT_CARD_EXP_MONTH])) {
   1787       // The dialog shows the same error message for the month and year fields.
   1788       year_message.text = l10n_util::GetStringUTF16(
   1789           IDS_AUTOFILL_DIALOG_VALIDATION_INVALID_CREDIT_CARD_EXPIRATION_DATE);
   1790       month_message.text = l10n_util::GetStringUTF16(
   1791           IDS_AUTOFILL_DIALOG_VALIDATION_INVALID_CREDIT_CARD_EXPIRATION_DATE);
   1792     }
   1793     messages.Set(CREDIT_CARD_EXP_4_DIGIT_YEAR, year_message);
   1794     messages.Set(CREDIT_CARD_EXP_MONTH, month_message);
   1795   }
   1796 
   1797   // If there is a credit card number and a CVC, validate them together.
   1798   if (field_values.count(CREDIT_CARD_NUMBER) &&
   1799       field_values.count(CREDIT_CARD_VERIFICATION_CODE)) {
   1800     ValidityMessage ccv_message(base::string16(), true);
   1801     if (!autofill::IsValidCreditCardSecurityCode(
   1802             field_values[CREDIT_CARD_VERIFICATION_CODE],
   1803             field_values[CREDIT_CARD_NUMBER])) {
   1804       ccv_message.text = l10n_util::GetStringUTF16(
   1805           IDS_AUTOFILL_DIALOG_VALIDATION_INVALID_CREDIT_CARD_SECURITY_CODE);
   1806     }
   1807     messages.Set(CREDIT_CARD_VERIFICATION_CODE, ccv_message);
   1808   }
   1809 
   1810   // Validate the shipping phone number against the country code of the address.
   1811   if (field_values.count(ADDRESS_HOME_COUNTRY) &&
   1812       field_values.count(PHONE_HOME_WHOLE_NUMBER)) {
   1813     i18n::PhoneObject phone_object(
   1814         field_values[PHONE_HOME_WHOLE_NUMBER],
   1815         AutofillCountry::GetCountryCode(
   1816             field_values[ADDRESS_HOME_COUNTRY],
   1817             g_browser_process->GetApplicationLocale()));
   1818     ValidityMessage phone_message(base::string16(), true);
   1819     if (!phone_object.IsValidNumber()) {
   1820       phone_message.text = l10n_util::GetStringUTF16(
   1821           IDS_AUTOFILL_DIALOG_VALIDATION_INVALID_PHONE_NUMBER);
   1822     }
   1823     messages.Set(PHONE_HOME_WHOLE_NUMBER, phone_message);
   1824   }
   1825 
   1826   // Validate the billing phone number against the country code of the address.
   1827   if (field_values.count(ADDRESS_BILLING_COUNTRY) &&
   1828       field_values.count(PHONE_BILLING_WHOLE_NUMBER)) {
   1829     i18n::PhoneObject phone_object(
   1830         field_values[PHONE_BILLING_WHOLE_NUMBER],
   1831         AutofillCountry::GetCountryCode(
   1832             field_values[ADDRESS_BILLING_COUNTRY],
   1833             g_browser_process->GetApplicationLocale()));
   1834     ValidityMessage phone_message(base::string16(), true);
   1835     if (!phone_object.IsValidNumber()) {
   1836       phone_message.text = l10n_util::GetStringUTF16(
   1837           IDS_AUTOFILL_DIALOG_VALIDATION_INVALID_PHONE_NUMBER);
   1838     }
   1839     messages.Set(PHONE_BILLING_WHOLE_NUMBER, phone_message);
   1840   }
   1841 
   1842   return messages;
   1843 }
   1844 
   1845 void AutofillDialogControllerImpl::UserEditedOrActivatedInput(
   1846     DialogSection section,
   1847     ServerFieldType type,
   1848     gfx::NativeView parent_view,
   1849     const gfx::Rect& content_bounds,
   1850     const base::string16& field_contents,
   1851     bool was_edit) {
   1852   // If the field is edited down to empty, don't show a popup.
   1853   if (was_edit && field_contents.empty()) {
   1854     HidePopup();
   1855     return;
   1856   }
   1857 
   1858   // If the user clicks while the popup is already showing, be sure to hide
   1859   // it.
   1860   if (!was_edit && popup_controller_.get()) {
   1861     HidePopup();
   1862     return;
   1863   }
   1864 
   1865   std::vector<base::string16> popup_values, popup_labels, popup_icons;
   1866   if (common::IsCreditCardType(type)) {
   1867     GetManager()->GetCreditCardSuggestions(AutofillType(type),
   1868                                            field_contents,
   1869                                            &popup_values,
   1870                                            &popup_labels,
   1871                                            &popup_icons,
   1872                                            &popup_guids_);
   1873   } else {
   1874     std::vector<ServerFieldType> field_types;
   1875     const DetailInputs& inputs = RequestedFieldsForSection(section);
   1876     for (DetailInputs::const_iterator iter = inputs.begin();
   1877          iter != inputs.end(); ++iter) {
   1878       field_types.push_back(iter->type);
   1879     }
   1880     GetManager()->GetProfileSuggestions(AutofillType(type),
   1881                                         field_contents,
   1882                                         false,
   1883                                         field_types,
   1884                                         &popup_values,
   1885                                         &popup_labels,
   1886                                         &popup_icons,
   1887                                         &popup_guids_);
   1888   }
   1889 
   1890   if (popup_values.empty()) {
   1891     HidePopup();
   1892     return;
   1893   }
   1894 
   1895   // |input_showing_popup_| must be set before calling |Show()|.
   1896   const DetailInputs& inputs = RequestedFieldsForSection(section);
   1897   for (DetailInputs::const_iterator iter = inputs.begin();
   1898        iter != inputs.end(); ++iter) {
   1899     if (iter->type == type) {
   1900       input_showing_popup_ = &(*iter);
   1901       break;
   1902     }
   1903   }
   1904 
   1905   if (!input_showing_popup_)
   1906     return;
   1907 
   1908   // TODO(estade): do we need separators and control rows like 'Clear
   1909   // Form'?
   1910   std::vector<int> popup_ids;
   1911   for (size_t i = 0; i < popup_guids_.size(); ++i) {
   1912     popup_ids.push_back(i);
   1913   }
   1914 
   1915   popup_controller_ = AutofillPopupControllerImpl::GetOrCreate(
   1916       popup_controller_,
   1917       weak_ptr_factory_.GetWeakPtr(),
   1918       NULL,
   1919       parent_view,
   1920       content_bounds,
   1921       base::i18n::IsRTL() ?
   1922           base::i18n::RIGHT_TO_LEFT : base::i18n::LEFT_TO_RIGHT);
   1923   popup_controller_->set_hide_on_outside_click(true);
   1924   popup_controller_->Show(popup_values,
   1925                           popup_labels,
   1926                           popup_icons,
   1927                           popup_ids);
   1928 }
   1929 
   1930 void AutofillDialogControllerImpl::FocusMoved() {
   1931   HidePopup();
   1932 }
   1933 
   1934 bool AutofillDialogControllerImpl::ShouldShowErrorBubble() const {
   1935   return !input_showing_popup_;
   1936 }
   1937 
   1938 void AutofillDialogControllerImpl::ViewClosed() {
   1939   GetManager()->RemoveObserver(this);
   1940 
   1941   // Called from here rather than in ~AutofillDialogControllerImpl as this
   1942   // relies on virtual methods that change to their base class in the dtor.
   1943   MaybeShowCreditCardBubble();
   1944 
   1945   delete this;
   1946 }
   1947 
   1948 std::vector<DialogNotification> AutofillDialogControllerImpl::
   1949     CurrentNotifications() {
   1950   std::vector<DialogNotification> notifications;
   1951 
   1952   // TODO(dbeam): figure out a way to dismiss this error after a while.
   1953   if (wallet_error_notification_)
   1954     notifications.push_back(*wallet_error_notification_);
   1955 
   1956   if (IsSubmitPausedOn(wallet::VERIFY_CVV)) {
   1957     notifications.push_back(DialogNotification(
   1958         DialogNotification::REQUIRED_ACTION,
   1959         l10n_util::GetStringUTF16(IDS_AUTOFILL_DIALOG_VERIFY_CVV)));
   1960   }
   1961 
   1962   if (!wallet_server_validation_recoverable_) {
   1963     notifications.push_back(DialogNotification(
   1964         DialogNotification::REQUIRED_ACTION,
   1965         l10n_util::GetStringUTF16(
   1966             IDS_AUTOFILL_DIALOG_FAILED_TO_SAVE_WALLET_DATA)));
   1967   }
   1968 
   1969   if (choose_another_instrument_or_address_) {
   1970     notifications.push_back(DialogNotification(
   1971         DialogNotification::REQUIRED_ACTION,
   1972         l10n_util::GetStringUTF16(
   1973             IDS_AUTOFILL_DIALOG_CHOOSE_DIFFERENT_WALLET_INSTRUMENT)));
   1974   }
   1975 
   1976   if (notifications.empty() && MenuModelForAccountChooser()) {
   1977     base::string16 text = l10n_util::GetStringUTF16(
   1978         IsManuallyEditingAnySection() ?
   1979             IDS_AUTOFILL_DIALOG_SAVE_DETAILS_IN_WALLET :
   1980             IDS_AUTOFILL_DIALOG_USE_WALLET);
   1981     DialogNotification notification(
   1982         DialogNotification::WALLET_USAGE_CONFIRMATION,
   1983         text);
   1984     notification.set_tooltip_text(
   1985         l10n_util::GetStringUTF16(
   1986             IDS_AUTOFILL_DIALOG_SAVE_IN_WALLET_TOOLTIP));
   1987     notification.set_checked(IsPayingWithWallet());
   1988     notifications.push_back(notification);
   1989   }
   1990 
   1991   if (IsPayingWithWallet() && !wallet::IsUsingProd()) {
   1992     notifications.push_back(DialogNotification(
   1993         DialogNotification::DEVELOPER_WARNING,
   1994         l10n_util::GetStringUTF16(IDS_AUTOFILL_DIALOG_NOT_PROD_WARNING)));
   1995   }
   1996 
   1997   if (!invoked_from_same_origin_) {
   1998     notifications.push_back(DialogNotification(
   1999         DialogNotification::SECURITY_WARNING,
   2000         l10n_util::GetStringFUTF16(IDS_AUTOFILL_DIALOG_SITE_WARNING,
   2001                                    UTF8ToUTF16(source_url_.host()))));
   2002   }
   2003 
   2004   return notifications;
   2005 }
   2006 
   2007 void AutofillDialogControllerImpl::LinkClicked(const GURL& url) {
   2008   OpenTabWithUrl(url);
   2009 }
   2010 
   2011 void AutofillDialogControllerImpl::SignInLinkClicked() {
   2012   ScopedViewUpdates updates(view_.get());
   2013 
   2014   if (SignedInState() == NOT_CHECKED) {
   2015     handling_use_wallet_link_click_ = true;
   2016     account_chooser_model_->SelectWalletAccount(0);
   2017     FetchWalletCookie();
   2018     view_->UpdateAccountChooser();
   2019   } else if (signin_registrar_.IsEmpty()) {
   2020     // Start sign in.
   2021     waiting_for_explicit_sign_in_response_ = true;
   2022     content::Source<content::NavigationController> source(view_->ShowSignIn());
   2023     signin_registrar_.Add(
   2024         this, content::NOTIFICATION_NAV_ENTRY_COMMITTED, source);
   2025     view_->UpdateAccountChooser();
   2026 
   2027     GetMetricLogger().LogDialogUiEvent(
   2028         AutofillMetrics::DIALOG_UI_SIGNIN_SHOWN);
   2029   } else {
   2030     waiting_for_explicit_sign_in_response_ = false;
   2031     HideSignIn();
   2032   }
   2033 }
   2034 
   2035 void AutofillDialogControllerImpl::NotificationCheckboxStateChanged(
   2036     DialogNotification::Type type, bool checked) {
   2037   if (type == DialogNotification::WALLET_USAGE_CONFIRMATION) {
   2038     if (checked) {
   2039       account_chooser_model_->SelectWalletAccount(
   2040           GetWalletClient()->user_index());
   2041     } else {
   2042       account_chooser_model_->SelectUseAutofill();
   2043     }
   2044 
   2045     AccountChoiceChanged();
   2046   }
   2047 }
   2048 
   2049 void AutofillDialogControllerImpl::LegalDocumentLinkClicked(
   2050     const gfx::Range& range) {
   2051   for (size_t i = 0; i < legal_document_link_ranges_.size(); ++i) {
   2052     if (legal_document_link_ranges_[i] == range) {
   2053       OpenTabWithUrl(wallet_items_->legal_documents()[i]->url());
   2054       return;
   2055     }
   2056   }
   2057 
   2058   NOTREACHED();
   2059 }
   2060 
   2061 bool AutofillDialogControllerImpl::OnCancel() {
   2062   HidePopup();
   2063   if (!is_submitting_)
   2064     LogOnCancelMetrics();
   2065   callback_.Run(NULL);
   2066   return true;
   2067 }
   2068 
   2069 bool AutofillDialogControllerImpl::OnAccept() {
   2070   ScopedViewUpdates updates(view_.get());
   2071   choose_another_instrument_or_address_ = false;
   2072   wallet_server_validation_recoverable_ = true;
   2073   HidePopup();
   2074 
   2075   // This must come before SetIsSubmitting().
   2076   if (IsPayingWithWallet()) {
   2077     // In the VERIFY_CVV case, hold onto the previously submitted cardholder
   2078     // name.
   2079     if (!IsSubmitPausedOn(wallet::VERIFY_CVV)) {
   2080       submitted_cardholder_name_ =
   2081           GetValueFromSection(SECTION_CC_BILLING, NAME_BILLING_FULL);
   2082 
   2083       // Snag the last four digits of the backing card now as it could be wiped
   2084       // out if a CVC challenge happens.
   2085       if (ActiveInstrument()) {
   2086         backing_card_last_four_ = ActiveInstrument()->TypeAndLastFourDigits();
   2087       } else {
   2088         FieldValueMap output;
   2089         view_->GetUserInput(SECTION_CC_BILLING, &output);
   2090         CreditCard card;
   2091         GetBillingInfoFromOutputs(output, &card, NULL, NULL);
   2092         backing_card_last_four_ = card.TypeAndLastFourDigits();
   2093       }
   2094     }
   2095     DCHECK(!submitted_cardholder_name_.empty());
   2096     DCHECK(!backing_card_last_four_.empty());
   2097   }
   2098 
   2099   SetIsSubmitting(true);
   2100 
   2101   if (IsSubmitPausedOn(wallet::VERIFY_CVV)) {
   2102     DCHECK(!active_instrument_id_.empty());
   2103     full_wallet_.reset();
   2104     GetWalletClient()->AuthenticateInstrument(
   2105         active_instrument_id_,
   2106         UTF16ToUTF8(view_->GetCvc()));
   2107     view_->UpdateOverlay();
   2108   } else if (IsPayingWithWallet()) {
   2109     AcceptLegalTerms();
   2110   } else {
   2111     FinishSubmit();
   2112   }
   2113 
   2114   return false;
   2115 }
   2116 
   2117 Profile* AutofillDialogControllerImpl::profile() {
   2118   return profile_;
   2119 }
   2120 
   2121 content::WebContents* AutofillDialogControllerImpl::GetWebContents() {
   2122   return web_contents();
   2123 }
   2124 
   2125 ////////////////////////////////////////////////////////////////////////////////
   2126 // AutofillPopupDelegate implementation.
   2127 
   2128 void AutofillDialogControllerImpl::OnPopupShown() {
   2129   ScopedViewUpdates update(view_.get());
   2130   view_->UpdateErrorBubble();
   2131 
   2132   GetMetricLogger().LogDialogPopupEvent(AutofillMetrics::DIALOG_POPUP_SHOWN);
   2133 }
   2134 
   2135 void AutofillDialogControllerImpl::OnPopupHidden() {}
   2136 
   2137 bool AutofillDialogControllerImpl::ShouldRepostEvent(
   2138     const ui::MouseEvent& event) {
   2139   // If the event would be reposted inside |input_showing_popup_|, just ignore.
   2140   return !view_->HitTestInput(*input_showing_popup_, event.location());
   2141 }
   2142 
   2143 void AutofillDialogControllerImpl::DidSelectSuggestion(int identifier) {
   2144   // TODO(estade): implement.
   2145 }
   2146 
   2147 void AutofillDialogControllerImpl::DidAcceptSuggestion(
   2148     const base::string16& value,
   2149     int identifier) {
   2150   ScopedViewUpdates updates(view_.get());
   2151   const PersonalDataManager::GUIDPair& pair = popup_guids_[identifier];
   2152 
   2153   scoped_ptr<DataModelWrapper> wrapper;
   2154   if (common::IsCreditCardType(input_showing_popup_->type)) {
   2155     wrapper.reset(new AutofillCreditCardWrapper(
   2156         GetManager()->GetCreditCardByGUID(pair.first)));
   2157   } else {
   2158     wrapper.reset(new AutofillProfileWrapper(
   2159         GetManager()->GetProfileByGUID(pair.first),
   2160         AutofillType(input_showing_popup_->type),
   2161         pair.second));
   2162   }
   2163 
   2164   for (size_t i = SECTION_MIN; i <= SECTION_MAX; ++i) {
   2165     DialogSection section = static_cast<DialogSection>(i);
   2166     wrapper->FillInputs(MutableRequestedFieldsForSection(section));
   2167     view_->FillSection(section, *input_showing_popup_);
   2168   }
   2169 
   2170   GetMetricLogger().LogDialogPopupEvent(
   2171       AutofillMetrics::DIALOG_POPUP_FORM_FILLED);
   2172 
   2173   // TODO(estade): not sure why it's necessary to do this explicitly.
   2174   HidePopup();
   2175 }
   2176 
   2177 void AutofillDialogControllerImpl::RemoveSuggestion(
   2178     const base::string16& value,
   2179     int identifier) {
   2180   // TODO(estade): implement.
   2181 }
   2182 
   2183 void AutofillDialogControllerImpl::ClearPreviewedForm() {
   2184   // TODO(estade): implement.
   2185 }
   2186 
   2187 ////////////////////////////////////////////////////////////////////////////////
   2188 // content::NotificationObserver implementation.
   2189 
   2190 void AutofillDialogControllerImpl::Observe(
   2191     int type,
   2192     const content::NotificationSource& source,
   2193     const content::NotificationDetails& details) {
   2194   DCHECK_EQ(type, content::NOTIFICATION_NAV_ENTRY_COMMITTED);
   2195   content::LoadCommittedDetails* load_details =
   2196       content::Details<content::LoadCommittedDetails>(details).ptr();
   2197   size_t user_index = 0;
   2198   if (IsSignInContinueUrl(load_details->entry->GetVirtualURL(), &user_index)) {
   2199     GetWalletClient()->SetUserIndex(user_index);
   2200     FetchWalletCookie();
   2201 
   2202     // NOTE: |HideSignIn()| may delete the WebContents which doesn't expect to
   2203     // be deleted while committing a nav entry. Just call |HideSignIn()| later.
   2204     base::MessageLoop::current()->PostTask(FROM_HERE,
   2205         base::Bind(&AutofillDialogControllerImpl::HideSignIn,
   2206                    base::Unretained(this)));
   2207   }
   2208 }
   2209 
   2210 ////////////////////////////////////////////////////////////////////////////////
   2211 // SuggestionsMenuModelDelegate implementation.
   2212 
   2213 void AutofillDialogControllerImpl::SuggestionsMenuWillShow() {
   2214   HidePopup();
   2215 }
   2216 
   2217 void AutofillDialogControllerImpl::SuggestionItemSelected(
   2218     SuggestionsMenuModel* model,
   2219     size_t index) {
   2220   ScopedViewUpdates updates(view_.get());
   2221 
   2222   if (model->GetItemKeyAt(index) == kManageItemsKey) {
   2223     GURL url;
   2224     if (!IsPayingWithWallet()) {
   2225       GURL settings_url(chrome::kChromeUISettingsURL);
   2226       url = settings_url.Resolve(chrome::kAutofillSubPage);
   2227     } else {
   2228       // Reset |last_wallet_items_fetch_timestamp_| to ensure that the Wallet
   2229       // data is refreshed as soon as the user switches back to this tab after
   2230       // potentially editing his data.
   2231       last_wallet_items_fetch_timestamp_ = base::TimeTicks();
   2232       size_t user_index = GetWalletClient()->user_index();
   2233       url = SectionForSuggestionsMenuModel(*model) == SECTION_SHIPPING ?
   2234           wallet::GetManageAddressesUrl(user_index) :
   2235           wallet::GetManageInstrumentsUrl(user_index);
   2236     }
   2237 
   2238     OpenTabWithUrl(url);
   2239     return;
   2240   }
   2241 
   2242   model->SetCheckedIndex(index);
   2243   DialogSection section = SectionForSuggestionsMenuModel(*model);
   2244   ResetSectionInput(section);
   2245   ShowEditUiIfBadSuggestion(section);
   2246   UpdateSection(section);
   2247   view_->UpdateNotificationArea();
   2248   UpdateForErrors();
   2249 
   2250   LogSuggestionItemSelectedMetric(*model);
   2251 }
   2252 
   2253 ////////////////////////////////////////////////////////////////////////////////
   2254 // wallet::WalletClientDelegate implementation.
   2255 
   2256 const AutofillMetrics& AutofillDialogControllerImpl::GetMetricLogger() const {
   2257   return metric_logger_;
   2258 }
   2259 
   2260 std::string AutofillDialogControllerImpl::GetRiskData() const {
   2261   DCHECK(!risk_data_.empty());
   2262   return risk_data_;
   2263 }
   2264 
   2265 std::string AutofillDialogControllerImpl::GetWalletCookieValue() const {
   2266   return wallet_cookie_value_;
   2267 }
   2268 
   2269 bool AutofillDialogControllerImpl::IsShippingAddressRequired() const {
   2270   return cares_about_shipping_;
   2271 }
   2272 
   2273 void AutofillDialogControllerImpl::OnDidAcceptLegalDocuments() {
   2274   DCHECK(is_submitting_ && IsPayingWithWallet());
   2275   has_accepted_legal_documents_ = true;
   2276   LoadRiskFingerprintData();
   2277 }
   2278 
   2279 void AutofillDialogControllerImpl::OnDidAuthenticateInstrument(bool success) {
   2280   DCHECK(is_submitting_ && IsPayingWithWallet());
   2281 
   2282   // TODO(dbeam): use the returned full wallet. http://crbug.com/224992
   2283   if (success) {
   2284     GetFullWallet();
   2285   } else {
   2286     DisableWallet(wallet::WalletClient::UNKNOWN_ERROR);
   2287     SuggestionsUpdated();
   2288   }
   2289 }
   2290 
   2291 void AutofillDialogControllerImpl::OnDidGetFullWallet(
   2292     scoped_ptr<wallet::FullWallet> full_wallet) {
   2293   DCHECK(is_submitting_ && IsPayingWithWallet());
   2294   ScopedViewUpdates updates(view_.get());
   2295 
   2296   full_wallet_ = full_wallet.Pass();
   2297 
   2298   if (full_wallet_->required_actions().empty()) {
   2299     FinishSubmit();
   2300     return;
   2301   }
   2302 
   2303   switch (full_wallet_->required_actions()[0]) {
   2304     case wallet::CHOOSE_ANOTHER_INSTRUMENT_OR_ADDRESS:
   2305       choose_another_instrument_or_address_ = true;
   2306       SetIsSubmitting(false);
   2307       GetWalletItems();
   2308       break;
   2309 
   2310     case wallet::VERIFY_CVV:
   2311       SuggestionsUpdated();
   2312       break;
   2313 
   2314     default:
   2315       DisableWallet(wallet::WalletClient::UNKNOWN_ERROR);
   2316       return;
   2317   }
   2318 
   2319   view_->UpdateNotificationArea();
   2320   view_->UpdateButtonStrip();
   2321   view_->UpdateOverlay();
   2322 }
   2323 
   2324 void AutofillDialogControllerImpl::OnPassiveSigninSuccess() {
   2325   FetchWalletCookie();
   2326 }
   2327 
   2328 void AutofillDialogControllerImpl::OnPassiveSigninFailure(
   2329     const GoogleServiceAuthError& error) {
   2330   signin_helper_.reset();
   2331   passive_failed_ = true;
   2332 
   2333   if (handling_use_wallet_link_click_ ||
   2334       GetWalletClient()->user_index() != 0) {
   2335     // TODO(estade): When a secondary account is selected and fails passive
   2336     // auth, we show a sign in page. Currently we show the generic add account
   2337     // page, but we should instead show sign in for the selected account.
   2338     // http://crbug.com/323327
   2339     SignInLinkClicked();
   2340     handling_use_wallet_link_click_ = false;
   2341   }
   2342 
   2343   OnWalletSigninError();
   2344 }
   2345 
   2346 void AutofillDialogControllerImpl::OnDidFetchWalletCookieValue(
   2347     const std::string& cookie_value) {
   2348   wallet_cookie_value_ = cookie_value;
   2349   signin_helper_.reset();
   2350   GetWalletItems();
   2351 }
   2352 
   2353 void AutofillDialogControllerImpl::OnDidGetWalletItems(
   2354     scoped_ptr<wallet::WalletItems> wallet_items) {
   2355   legal_documents_text_.clear();
   2356   legal_document_link_ranges_.clear();
   2357   has_accepted_legal_documents_ = false;
   2358 
   2359   wallet_items_ = wallet_items.Pass();
   2360 
   2361   if (wallet_items_ && !wallet_items_->ObfuscatedGaiaId().empty()) {
   2362     // Making sure the user index is in sync shouldn't be necessary, but is an
   2363     // extra precaution. But if there is no active account (such as in the
   2364     // PASSIVE_AUTH case), stick with the old active account.
   2365     GetWalletClient()->SetUserIndex(wallet_items_->active_account_index());
   2366 
   2367     std::vector<std::string> usernames;
   2368     for (size_t i = 0; i < wallet_items_->gaia_accounts().size(); ++i) {
   2369       usernames.push_back(wallet_items_->gaia_accounts()[i]->email_address());
   2370     }
   2371     account_chooser_model_->SetWalletAccounts(
   2372         usernames, wallet_items_->active_account_index());
   2373   }
   2374 
   2375   ConstructLegalDocumentsText();
   2376   OnWalletOrSigninUpdate();
   2377 }
   2378 
   2379 void AutofillDialogControllerImpl::OnDidSaveToWallet(
   2380     const std::string& instrument_id,
   2381     const std::string& address_id,
   2382     const std::vector<wallet::RequiredAction>& required_actions,
   2383     const std::vector<wallet::FormFieldError>& form_field_errors) {
   2384   DCHECK(is_submitting_ && IsPayingWithWallet());
   2385 
   2386   if (required_actions.empty()) {
   2387     if (!address_id.empty())
   2388       active_address_id_ = address_id;
   2389     if (!instrument_id.empty())
   2390       active_instrument_id_ = instrument_id;
   2391     GetFullWallet();
   2392   } else {
   2393     OnWalletFormFieldError(form_field_errors);
   2394     HandleSaveOrUpdateRequiredActions(required_actions);
   2395   }
   2396 }
   2397 
   2398 void AutofillDialogControllerImpl::OnWalletError(
   2399     wallet::WalletClient::ErrorType error_type) {
   2400   DisableWallet(error_type);
   2401 }
   2402 
   2403 ////////////////////////////////////////////////////////////////////////////////
   2404 // PersonalDataManagerObserver implementation.
   2405 
   2406 void AutofillDialogControllerImpl::OnPersonalDataChanged() {
   2407   if (is_submitting_)
   2408     return;
   2409 
   2410   SuggestionsUpdated();
   2411 }
   2412 
   2413 ////////////////////////////////////////////////////////////////////////////////
   2414 // AccountChooserModelDelegate implementation.
   2415 
   2416 void AutofillDialogControllerImpl::AccountChooserWillShow() {
   2417   HidePopup();
   2418 }
   2419 
   2420 void AutofillDialogControllerImpl::AccountChoiceChanged() {
   2421   ScopedViewUpdates updates(view_.get());
   2422   wallet::WalletClient* client = GetWalletClient();
   2423 
   2424   if (is_submitting_)
   2425     client->CancelRequests();
   2426 
   2427   SetIsSubmitting(false);
   2428 
   2429   size_t selected_user_index =
   2430       account_chooser_model_->GetActiveWalletAccountIndex();
   2431   if (account_chooser_model_->WalletIsSelected() &&
   2432       client->user_index() != selected_user_index) {
   2433     client->SetUserIndex(selected_user_index);
   2434     // Clear |wallet_items_| so we don't try to restore the selected instrument
   2435     // and address.
   2436     wallet_items_.reset();
   2437     GetWalletItems();
   2438   } else {
   2439     SuggestionsUpdated();
   2440     UpdateAccountChooserView();
   2441   }
   2442 }
   2443 
   2444 void AutofillDialogControllerImpl::AddAccount() {
   2445   SignInLinkClicked();
   2446 }
   2447 
   2448 void AutofillDialogControllerImpl::UpdateAccountChooserView() {
   2449   if (view_) {
   2450     ScopedViewUpdates updates(view_.get());
   2451     view_->UpdateAccountChooser();
   2452     view_->UpdateNotificationArea();
   2453   }
   2454 }
   2455 
   2456 ////////////////////////////////////////////////////////////////////////////////
   2457 
   2458 bool AutofillDialogControllerImpl::HandleKeyPressEventInInput(
   2459     const content::NativeWebKeyboardEvent& event) {
   2460   if (popup_controller_.get())
   2461     return popup_controller_->HandleKeyPressEvent(event);
   2462 
   2463   return false;
   2464 }
   2465 
   2466 bool AutofillDialogControllerImpl::IsSubmitPausedOn(
   2467     wallet::RequiredAction required_action) const {
   2468   return full_wallet_ && full_wallet_->HasRequiredAction(required_action);
   2469 }
   2470 
   2471 void AutofillDialogControllerImpl::ShowNewCreditCardBubble(
   2472     scoped_ptr<CreditCard> new_card,
   2473     scoped_ptr<AutofillProfile> billing_profile) {
   2474 #if !defined(OS_ANDROID)
   2475   NewCreditCardBubbleController::Show(web_contents(),
   2476                                       new_card.Pass(),
   2477                                       billing_profile.Pass());
   2478 #endif
   2479 }
   2480 
   2481 void AutofillDialogControllerImpl::SubmitButtonDelayBegin() {
   2482   submit_button_delay_timer_.Start(
   2483       FROM_HERE,
   2484       base::TimeDelta::FromMilliseconds(kSubmitButtonDelayMs),
   2485       this,
   2486       &AutofillDialogControllerImpl::OnSubmitButtonDelayEnd);
   2487 }
   2488 
   2489 void AutofillDialogControllerImpl::SubmitButtonDelayEndForTesting() {
   2490   DCHECK(submit_button_delay_timer_.IsRunning());
   2491   submit_button_delay_timer_.user_task().Run();
   2492   submit_button_delay_timer_.Stop();
   2493 }
   2494 
   2495 void AutofillDialogControllerImpl::
   2496     ClearLastWalletItemsFetchTimestampForTesting() {
   2497   last_wallet_items_fetch_timestamp_ = base::TimeTicks();
   2498 }
   2499 
   2500 AccountChooserModel* AutofillDialogControllerImpl::
   2501     AccountChooserModelForTesting() {
   2502   return account_chooser_model_.get();
   2503 }
   2504 
   2505 bool AutofillDialogControllerImpl::IsSignInContinueUrl(
   2506     const GURL& url,
   2507     size_t* user_index) const {
   2508   return wallet::IsSignInContinueUrl(url, user_index);
   2509 }
   2510 
   2511 AutofillDialogControllerImpl::AutofillDialogControllerImpl(
   2512     content::WebContents* contents,
   2513     const FormData& form_structure,
   2514     const GURL& source_url,
   2515     const base::Callback<void(const FormStructure*)>& callback)
   2516     : WebContentsObserver(contents),
   2517       profile_(Profile::FromBrowserContext(contents->GetBrowserContext())),
   2518       initial_user_state_(AutofillMetrics::DIALOG_USER_STATE_UNKNOWN),
   2519       form_structure_(form_structure),
   2520       invoked_from_same_origin_(true),
   2521       source_url_(source_url),
   2522       callback_(callback),
   2523       wallet_client_(profile_->GetRequestContext(), this, source_url),
   2524       wallet_items_requested_(false),
   2525       handling_use_wallet_link_click_(false),
   2526       passive_failed_(false),
   2527       country_combobox_model_(*GetManager()),
   2528       suggested_cc_(this),
   2529       suggested_billing_(this),
   2530       suggested_cc_billing_(this),
   2531       suggested_shipping_(this),
   2532       cares_about_shipping_(true),
   2533       input_showing_popup_(NULL),
   2534       weak_ptr_factory_(this),
   2535       waiting_for_explicit_sign_in_response_(false),
   2536       has_accepted_legal_documents_(false),
   2537       is_submitting_(false),
   2538       choose_another_instrument_or_address_(false),
   2539       wallet_server_validation_recoverable_(true),
   2540       data_was_passed_back_(false),
   2541       was_ui_latency_logged_(false),
   2542       card_generated_animation_(2000, 60, this) {
   2543   // TODO(estade): remove duplicates from |form_structure|?
   2544   DCHECK(!callback_.is_null());
   2545 }
   2546 
   2547 AutofillDialogView* AutofillDialogControllerImpl::CreateView() {
   2548   return AutofillDialogView::Create(this);
   2549 }
   2550 
   2551 PersonalDataManager* AutofillDialogControllerImpl::GetManager() const {
   2552   return PersonalDataManagerFactory::GetForProfile(profile_);
   2553 }
   2554 
   2555 const wallet::WalletClient* AutofillDialogControllerImpl::GetWalletClient()
   2556     const {
   2557   return const_cast<AutofillDialogControllerImpl*>(this)->GetWalletClient();
   2558 }
   2559 
   2560 wallet::WalletClient* AutofillDialogControllerImpl::GetWalletClient() {
   2561   return &wallet_client_;
   2562 }
   2563 
   2564 bool AutofillDialogControllerImpl::IsPayingWithWallet() const {
   2565   return account_chooser_model_->WalletIsSelected() &&
   2566          SignedInState() == SIGNED_IN;
   2567 }
   2568 
   2569 void AutofillDialogControllerImpl::LoadRiskFingerprintData() {
   2570   risk_data_.clear();
   2571 
   2572   uint64 obfuscated_gaia_id = 0;
   2573   bool success = base::StringToUint64(wallet_items_->ObfuscatedGaiaId(),
   2574                                       &obfuscated_gaia_id);
   2575   DCHECK(success);
   2576 
   2577   gfx::Rect window_bounds;
   2578   window_bounds = GetBaseWindowForWebContents(web_contents())->GetBounds();
   2579 
   2580   PrefService* user_prefs = profile_->GetPrefs();
   2581   std::string charset = user_prefs->GetString(::prefs::kDefaultCharset);
   2582   std::string accept_languages =
   2583       user_prefs->GetString(::prefs::kAcceptLanguages);
   2584   base::Time install_time = base::Time::FromTimeT(
   2585       g_browser_process->local_state()->GetInt64(::prefs::kInstallDate));
   2586 
   2587   risk::GetFingerprint(
   2588       obfuscated_gaia_id, window_bounds, *web_contents(),
   2589       chrome::VersionInfo().Version(), charset, accept_languages, install_time,
   2590       g_browser_process->GetApplicationLocale(),
   2591       base::Bind(&AutofillDialogControllerImpl::OnDidLoadRiskFingerprintData,
   2592                  weak_ptr_factory_.GetWeakPtr()));
   2593 }
   2594 
   2595 void AutofillDialogControllerImpl::OnDidLoadRiskFingerprintData(
   2596     scoped_ptr<risk::Fingerprint> fingerprint) {
   2597   DCHECK(AreLegalDocumentsCurrent());
   2598 
   2599   std::string proto_data;
   2600   fingerprint->SerializeToString(&proto_data);
   2601   base::Base64Encode(proto_data, &risk_data_);
   2602 
   2603   SubmitWithWallet();
   2604 }
   2605 
   2606 void AutofillDialogControllerImpl::OpenTabWithUrl(const GURL& url) {
   2607   chrome::NavigateParams params(
   2608       chrome::FindBrowserWithWebContents(web_contents()),
   2609       url,
   2610       content::PAGE_TRANSITION_LINK);
   2611   params.disposition = NEW_FOREGROUND_TAB;
   2612   chrome::Navigate(&params);
   2613 }
   2614 
   2615 bool AutofillDialogControllerImpl::IsEditingExistingData(
   2616     DialogSection section) const {
   2617   return section_editing_state_.count(section) > 0;
   2618 }
   2619 
   2620 bool AutofillDialogControllerImpl::IsManuallyEditingSection(
   2621     DialogSection section) const {
   2622   return IsEditingExistingData(section) ||
   2623          SuggestionsMenuModelForSection(section)->
   2624              GetItemKeyForCheckedItem() == kAddNewItemKey;
   2625 }
   2626 
   2627 void AutofillDialogControllerImpl::OnWalletSigninError() {
   2628   account_chooser_model_->SetHadWalletSigninError();
   2629   GetWalletClient()->CancelRequests();
   2630   LogDialogLatencyToShow();
   2631 }
   2632 
   2633 void AutofillDialogControllerImpl::DisableWallet(
   2634     wallet::WalletClient::ErrorType error_type) {
   2635   signin_helper_.reset();
   2636   wallet_items_.reset();
   2637   wallet_errors_.clear();
   2638   GetWalletClient()->CancelRequests();
   2639   SetIsSubmitting(false);
   2640   wallet_error_notification_ = GetWalletError(error_type);
   2641   account_chooser_model_->SetHadWalletError();
   2642 }
   2643 
   2644 void AutofillDialogControllerImpl::SuggestionsUpdated() {
   2645   ScopedViewUpdates updates(view_.get());
   2646 
   2647   const FieldValueMap snapshot = TakeUserInputSnapshot();
   2648 
   2649   suggested_cc_.Reset();
   2650   suggested_billing_.Reset();
   2651   suggested_cc_billing_.Reset();
   2652   suggested_shipping_.Reset();
   2653   HidePopup();
   2654 
   2655   suggested_shipping_.AddKeyedItem(
   2656       kSameAsBillingKey,
   2657       l10n_util::GetStringUTF16(IDS_AUTOFILL_DIALOG_USE_BILLING_FOR_SHIPPING));
   2658 
   2659   if (IsPayingWithWallet()) {
   2660     const std::vector<wallet::Address*>& addresses =
   2661         wallet_items_->addresses();
   2662 
   2663     bool shipping_same_as_billing = profile_->GetPrefs()->GetBoolean(
   2664         ::prefs::kAutofillDialogWalletShippingSameAsBilling);
   2665 
   2666     if (shipping_same_as_billing)
   2667       suggested_shipping_.SetCheckedItem(kSameAsBillingKey);
   2668 
   2669     for (size_t i = 0; i < addresses.size(); ++i) {
   2670       std::string key = base::IntToString(i);
   2671       suggested_shipping_.AddKeyedItemWithMinorText(
   2672           key,
   2673           addresses[i]->DisplayName(),
   2674           addresses[i]->DisplayNameDetail());
   2675 
   2676       // TODO(scr): Move this assignment outside the loop or comment why it
   2677       // can't be there.
   2678       const std::string default_shipping_address_id =
   2679           GetIdToSelect(wallet_items_->default_address_id(),
   2680                         previous_default_shipping_address_id_,
   2681                         previously_selected_shipping_address_id_);
   2682 
   2683       if (!shipping_same_as_billing &&
   2684           addresses[i]->object_id() == default_shipping_address_id) {
   2685         suggested_shipping_.SetCheckedItem(key);
   2686       }
   2687     }
   2688 
   2689     if (!IsSubmitPausedOn(wallet::VERIFY_CVV)) {
   2690       const std::vector<wallet::WalletItems::MaskedInstrument*>& instruments =
   2691           wallet_items_->instruments();
   2692       std::string first_active_instrument_key;
   2693       std::string default_instrument_key;
   2694       for (size_t i = 0; i < instruments.size(); ++i) {
   2695         bool allowed = IsInstrumentAllowed(*instruments[i]);
   2696         gfx::Image icon = instruments[i]->CardIcon();
   2697         if (!allowed && !icon.IsEmpty()) {
   2698           // Create a grayed disabled icon.
   2699           SkBitmap disabled_bitmap = SkBitmapOperations::CreateHSLShiftedBitmap(
   2700               *icon.ToSkBitmap(), kGrayImageShift);
   2701           icon = gfx::Image(
   2702               gfx::ImageSkia::CreateFrom1xBitmap(disabled_bitmap));
   2703         }
   2704         std::string key = base::IntToString(i);
   2705         suggested_cc_billing_.AddKeyedItemWithMinorTextAndIcon(
   2706             key,
   2707             instruments[i]->DisplayName(),
   2708             instruments[i]->DisplayNameDetail(),
   2709             icon);
   2710         suggested_cc_billing_.SetEnabled(key, allowed);
   2711 
   2712         if (allowed) {
   2713           if (first_active_instrument_key.empty())
   2714             first_active_instrument_key = key;
   2715 
   2716           const std::string default_instrument_id =
   2717               GetIdToSelect(wallet_items_->default_instrument_id(),
   2718                             previous_default_instrument_id_,
   2719                             previously_selected_instrument_id_);
   2720           if (instruments[i]->object_id() == default_instrument_id)
   2721             default_instrument_key = key;
   2722         }
   2723       }
   2724 
   2725       suggested_cc_billing_.AddKeyedItem(
   2726           kAddNewItemKey,
   2727           l10n_util::GetStringUTF16(IDS_AUTOFILL_DIALOG_ADD_BILLING_DETAILS));
   2728       if (!wallet_items_->HasRequiredAction(wallet::SETUP_WALLET)) {
   2729         suggested_cc_billing_.AddKeyedItemWithMinorText(
   2730             kManageItemsKey,
   2731             l10n_util::GetStringUTF16(
   2732                 IDS_AUTOFILL_DIALOG_MANAGE_BILLING_DETAILS),
   2733                 UTF8ToUTF16(wallet::GetManageInstrumentsUrl(0U).host()));
   2734       }
   2735 
   2736       // Determine which instrument item should be selected.
   2737       if (!default_instrument_key.empty())
   2738         suggested_cc_billing_.SetCheckedItem(default_instrument_key);
   2739       else if (!first_active_instrument_key.empty())
   2740         suggested_cc_billing_.SetCheckedItem(first_active_instrument_key);
   2741       else
   2742         suggested_cc_billing_.SetCheckedItem(kAddNewItemKey);
   2743     }
   2744   } else {
   2745     PersonalDataManager* manager = GetManager();
   2746     const std::vector<CreditCard*>& cards = manager->GetCreditCards();
   2747     ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
   2748     for (size_t i = 0; i < cards.size(); ++i) {
   2749       if (!HasCompleteAndVerifiedData(*cards[i], requested_cc_fields_))
   2750         continue;
   2751 
   2752       suggested_cc_.AddKeyedItemWithIcon(
   2753           cards[i]->guid(),
   2754           cards[i]->Label(),
   2755           rb.GetImageNamed(CreditCard::IconResourceId(cards[i]->type())));
   2756     }
   2757 
   2758     const std::vector<AutofillProfile*>& profiles = manager->GetProfiles();
   2759     std::vector<base::string16> labels;
   2760     AutofillProfile::CreateDifferentiatingLabels(profiles, &labels);
   2761     DCHECK_EQ(labels.size(), profiles.size());
   2762     const std::string app_locale = g_browser_process->GetApplicationLocale();
   2763     for (size_t i = 0; i < profiles.size(); ++i) {
   2764       const AutofillProfile& profile = *profiles[i];
   2765       if (!HasCompleteAndVerifiedData(profile, requested_shipping_fields_) ||
   2766           HasInvalidAddress(*profiles[i])) {
   2767         continue;
   2768       }
   2769 
   2770       // Don't add variants for addresses: name is part of credit card and we'll
   2771       // just ignore email and phone number variants.
   2772       suggested_shipping_.AddKeyedItem(profile.guid(), labels[i]);
   2773       if (!profile.GetRawInfo(EMAIL_ADDRESS).empty() &&
   2774           !profile.IsPresentButInvalid(EMAIL_ADDRESS)) {
   2775         suggested_billing_.AddKeyedItem(profile.guid(), labels[i]);
   2776       }
   2777     }
   2778 
   2779     suggested_cc_.AddKeyedItem(
   2780         kAddNewItemKey,
   2781         l10n_util::GetStringUTF16(IDS_AUTOFILL_DIALOG_ADD_CREDIT_CARD));
   2782     suggested_cc_.AddKeyedItem(
   2783         kManageItemsKey,
   2784         l10n_util::GetStringUTF16(IDS_AUTOFILL_DIALOG_MANAGE_CREDIT_CARD));
   2785     suggested_billing_.AddKeyedItem(
   2786         kAddNewItemKey,
   2787         l10n_util::GetStringUTF16(IDS_AUTOFILL_DIALOG_ADD_BILLING_ADDRESS));
   2788     suggested_billing_.AddKeyedItem(
   2789         kManageItemsKey,
   2790         l10n_util::GetStringUTF16(IDS_AUTOFILL_DIALOG_MANAGE_BILLING_ADDRESS));
   2791   }
   2792 
   2793   suggested_shipping_.AddKeyedItem(
   2794       kAddNewItemKey,
   2795       l10n_util::GetStringUTF16(IDS_AUTOFILL_DIALOG_ADD_SHIPPING_ADDRESS));
   2796   if (!IsPayingWithWallet()) {
   2797     suggested_shipping_.AddKeyedItem(
   2798         kManageItemsKey,
   2799         l10n_util::GetStringUTF16(IDS_AUTOFILL_DIALOG_MANAGE_SHIPPING_ADDRESS));
   2800   } else if (!wallet_items_->HasRequiredAction(wallet::SETUP_WALLET)) {
   2801     suggested_shipping_.AddKeyedItemWithMinorText(
   2802         kManageItemsKey,
   2803         l10n_util::GetStringUTF16(IDS_AUTOFILL_DIALOG_MANAGE_SHIPPING_ADDRESS),
   2804         UTF8ToUTF16(wallet::GetManageAddressesUrl(0U).host()));
   2805   }
   2806 
   2807   if (!IsPayingWithWallet()) {
   2808     for (size_t i = SECTION_MIN; i <= SECTION_MAX; ++i) {
   2809       DialogSection section = static_cast<DialogSection>(i);
   2810       if (!SectionIsActive(section))
   2811         continue;
   2812 
   2813       // Set the starting choice for the menu. First set to the default in case
   2814       // the GUID saved in prefs refers to a profile that no longer exists.
   2815       std::string guid;
   2816       GetDefaultAutofillChoice(section, &guid);
   2817       SuggestionsMenuModel* model = SuggestionsMenuModelForSection(section);
   2818       model->SetCheckedItem(guid);
   2819       if (GetAutofillChoice(section, &guid))
   2820         model->SetCheckedItem(guid);
   2821     }
   2822   }
   2823 
   2824   if (view_)
   2825     view_->ModelChanged();
   2826 
   2827   for (size_t i = SECTION_MIN; i <= SECTION_MAX; ++i) {
   2828     ResetSectionInput(static_cast<DialogSection>(i));
   2829   }
   2830 
   2831   RestoreUserInputFromSnapshot(snapshot);
   2832 
   2833   for (size_t i = SECTION_MIN; i <= SECTION_MAX; ++i) {
   2834     DialogSection section = static_cast<DialogSection>(i);
   2835     if (!SectionIsActive(section))
   2836       continue;
   2837 
   2838     ShowEditUiIfBadSuggestion(section);
   2839     UpdateSection(section);
   2840   }
   2841 
   2842   UpdateForErrors();
   2843 }
   2844 
   2845 void AutofillDialogControllerImpl::FillOutputForSectionWithComparator(
   2846     DialogSection section,
   2847     const InputFieldComparator& compare) {
   2848   const DetailInputs& inputs = RequestedFieldsForSection(section);
   2849 
   2850   if (!SectionIsActive(section))
   2851     return;
   2852 
   2853   scoped_ptr<DataModelWrapper> wrapper = CreateWrapper(section);
   2854   if (wrapper) {
   2855     // Only fill in data that is associated with this section.
   2856     const DetailInputs& inputs = RequestedFieldsForSection(section);
   2857     wrapper->FillFormStructure(inputs, compare, &form_structure_);
   2858 
   2859     // CVC needs special-casing because the CreditCard class doesn't store or
   2860     // handle them. This isn't necessary when filling the combined CC and
   2861     // billing section as CVC comes from |full_wallet_| in this case.
   2862     if (section == SECTION_CC)
   2863       SetOutputForFieldsOfType(CREDIT_CARD_VERIFICATION_CODE, view_->GetCvc());
   2864 
   2865     // When filling from Wallet data, use the email address associated with the
   2866     // account. There is no other email address stored as part of a Wallet
   2867     // address.
   2868     if (section == SECTION_CC_BILLING) {
   2869       SetOutputForFieldsOfType(
   2870           EMAIL_ADDRESS, account_chooser_model_->GetActiveWalletAccountName());
   2871     }
   2872   } else {
   2873     // The user manually input data. If using Autofill, save the info as new or
   2874     // edited data. Always fill local data into |form_structure_|.
   2875     FieldValueMap output;
   2876     view_->GetUserInput(section, &output);
   2877 
   2878     if (section == SECTION_CC) {
   2879       CreditCard card;
   2880       card.set_origin(kAutofillDialogOrigin);
   2881       FillFormGroupFromOutputs(output, &card);
   2882 
   2883       // The card holder name comes from the billing address section.
   2884       card.SetRawInfo(CREDIT_CARD_NAME,
   2885                       GetValueFromSection(SECTION_BILLING, NAME_BILLING_FULL));
   2886 
   2887       if (ShouldSaveDetailsLocally()) {
   2888         std::string guid = GetManager()->SaveImportedCreditCard(card);
   2889         newly_saved_data_model_guids_[section] = guid;
   2890         DCHECK(!profile()->IsOffTheRecord());
   2891         newly_saved_card_.reset(new CreditCard(card));
   2892       }
   2893 
   2894       AutofillCreditCardWrapper card_wrapper(&card);
   2895       card_wrapper.FillFormStructure(inputs, compare, &form_structure_);
   2896 
   2897       // Again, CVC needs special-casing. Fill it in directly from |output|.
   2898       SetOutputForFieldsOfType(
   2899           CREDIT_CARD_VERIFICATION_CODE,
   2900           output[CREDIT_CARD_VERIFICATION_CODE]);
   2901     } else {
   2902       AutofillProfile profile;
   2903       profile.set_origin(kAutofillDialogOrigin);
   2904       FillFormGroupFromOutputs(output, &profile);
   2905 
   2906       if (ShouldSaveDetailsLocally()) {
   2907         std::string guid = GetManager()->SaveImportedProfile(profile);
   2908         newly_saved_data_model_guids_[section] = guid;
   2909       }
   2910 
   2911       AutofillProfileWrapper profile_wrapper(&profile);
   2912       profile_wrapper.FillFormStructure(inputs, compare, &form_structure_);
   2913     }
   2914   }
   2915 }
   2916 
   2917 void AutofillDialogControllerImpl::FillOutputForSection(DialogSection section) {
   2918   FillOutputForSectionWithComparator(
   2919       section, base::Bind(common::DetailInputMatchesField, section));
   2920 }
   2921 
   2922 bool AutofillDialogControllerImpl::FormStructureCaresAboutSection(
   2923     DialogSection section) const {
   2924   // For now, only SECTION_SHIPPING may be omitted due to a site not asking for
   2925   // any of the fields.
   2926   if (section == SECTION_SHIPPING)
   2927     return cares_about_shipping_;
   2928 
   2929   return true;
   2930 }
   2931 
   2932 void AutofillDialogControllerImpl::SetOutputForFieldsOfType(
   2933     ServerFieldType type,
   2934     const base::string16& output) {
   2935   for (size_t i = 0; i < form_structure_.field_count(); ++i) {
   2936     AutofillField* field = form_structure_.field(i);
   2937     if (field->Type().GetStorableType() == type)
   2938       field->value = output;
   2939   }
   2940 }
   2941 
   2942 base::string16 AutofillDialogControllerImpl::GetValueFromSection(
   2943     DialogSection section,
   2944     ServerFieldType type) {
   2945   DCHECK(SectionIsActive(section));
   2946 
   2947   scoped_ptr<DataModelWrapper> wrapper = CreateWrapper(section);
   2948   if (wrapper)
   2949     return wrapper->GetInfo(AutofillType(type));
   2950 
   2951   FieldValueMap output;
   2952   view_->GetUserInput(section, &output);
   2953   return output[type];
   2954 }
   2955 
   2956 SuggestionsMenuModel* AutofillDialogControllerImpl::
   2957     SuggestionsMenuModelForSection(DialogSection section) {
   2958   switch (section) {
   2959     case SECTION_CC:
   2960       return &suggested_cc_;
   2961     case SECTION_BILLING:
   2962       return &suggested_billing_;
   2963     case SECTION_SHIPPING:
   2964       return &suggested_shipping_;
   2965     case SECTION_CC_BILLING:
   2966       return &suggested_cc_billing_;
   2967   }
   2968 
   2969   NOTREACHED();
   2970   return NULL;
   2971 }
   2972 
   2973 const SuggestionsMenuModel* AutofillDialogControllerImpl::
   2974     SuggestionsMenuModelForSection(DialogSection section) const {
   2975   return const_cast<AutofillDialogControllerImpl*>(this)->
   2976       SuggestionsMenuModelForSection(section);
   2977 }
   2978 
   2979 DialogSection AutofillDialogControllerImpl::SectionForSuggestionsMenuModel(
   2980     const SuggestionsMenuModel& model) {
   2981   if (&model == &suggested_cc_)
   2982     return SECTION_CC;
   2983 
   2984   if (&model == &suggested_billing_)
   2985     return SECTION_BILLING;
   2986 
   2987   if (&model == &suggested_cc_billing_)
   2988     return SECTION_CC_BILLING;
   2989 
   2990   DCHECK_EQ(&model, &suggested_shipping_);
   2991   return SECTION_SHIPPING;
   2992 }
   2993 
   2994 DetailInputs* AutofillDialogControllerImpl::MutableRequestedFieldsForSection(
   2995     DialogSection section) {
   2996   return const_cast<DetailInputs*>(&RequestedFieldsForSection(section));
   2997 }
   2998 
   2999 void AutofillDialogControllerImpl::HidePopup() {
   3000   if (popup_controller_.get())
   3001     popup_controller_->Hide();
   3002   input_showing_popup_ = NULL;
   3003 }
   3004 
   3005 void AutofillDialogControllerImpl::SetEditingExistingData(
   3006     DialogSection section, bool editing) {
   3007   if (editing)
   3008     section_editing_state_.insert(section);
   3009   else
   3010     section_editing_state_.erase(section);
   3011 }
   3012 
   3013 bool AutofillDialogControllerImpl::IsASuggestionItemKey(
   3014     const std::string& key) const {
   3015   return !key.empty() &&
   3016       key != kAddNewItemKey &&
   3017       key != kManageItemsKey &&
   3018       key != kSameAsBillingKey;
   3019 }
   3020 
   3021 bool AutofillDialogControllerImpl::IsManuallyEditingAnySection() const {
   3022   for (size_t section = SECTION_MIN; section <= SECTION_MAX; ++section) {
   3023     if (IsManuallyEditingSection(static_cast<DialogSection>(section)))
   3024       return true;
   3025   }
   3026   return false;
   3027 }
   3028 
   3029 base::string16 AutofillDialogControllerImpl::CreditCardNumberValidityMessage(
   3030     const base::string16& number) const {
   3031   if (!number.empty() && !autofill::IsValidCreditCardNumber(number)) {
   3032     return l10n_util::GetStringUTF16(
   3033         IDS_AUTOFILL_DIALOG_VALIDATION_INVALID_CREDIT_CARD_NUMBER);
   3034   }
   3035 
   3036   base::string16 message;
   3037   if (IsPayingWithWallet() && !wallet_items_->SupportsCard(number, &message))
   3038     return message;
   3039 
   3040   // Card number is good and supported.
   3041   return base::string16();
   3042 }
   3043 
   3044 bool AutofillDialogControllerImpl::AllSectionsAreValid() {
   3045   for (size_t section = SECTION_MIN; section <= SECTION_MAX; ++section) {
   3046     if (!SectionIsValid(static_cast<DialogSection>(section)))
   3047       return false;
   3048   }
   3049   return true;
   3050 }
   3051 
   3052 bool AutofillDialogControllerImpl::SectionIsValid(
   3053     DialogSection section) {
   3054   if (!IsManuallyEditingSection(section))
   3055     return true;
   3056 
   3057   FieldValueMap detail_outputs;
   3058   view_->GetUserInput(section, &detail_outputs);
   3059   return !InputsAreValid(section, detail_outputs).HasSureErrors();
   3060 }
   3061 
   3062 bool AutofillDialogControllerImpl::IsCreditCardExpirationValid(
   3063     const base::string16& year,
   3064     const base::string16& month) const {
   3065   // If the expiration is in the past as per the local clock, it's invalid.
   3066   base::Time now = base::Time::Now();
   3067   if (!autofill::IsValidCreditCardExpirationDate(year, month, now))
   3068     return false;
   3069 
   3070   if (IsPayingWithWallet() && IsEditingExistingData(SECTION_CC_BILLING)) {
   3071     const wallet::WalletItems::MaskedInstrument* instrument =
   3072         ActiveInstrument();
   3073     const std::string& locale = g_browser_process->GetApplicationLocale();
   3074     int month_int;
   3075     if (base::StringToInt(month, &month_int) &&
   3076         instrument->status() ==
   3077             wallet::WalletItems::MaskedInstrument::EXPIRED &&
   3078         year ==
   3079             instrument->GetInfo(
   3080                 AutofillType(CREDIT_CARD_EXP_4_DIGIT_YEAR), locale) &&
   3081         month_int == instrument->expiration_month()) {
   3082       // Otherwise, if the user is editing an instrument that's deemed expired
   3083       // by the Online Wallet server, mark it invalid on selection.
   3084       return false;
   3085     }
   3086   }
   3087 
   3088   return true;
   3089 }
   3090 
   3091 bool AutofillDialogControllerImpl::ShouldUseBillingForShipping() {
   3092   return SectionIsActive(SECTION_SHIPPING) &&
   3093       suggested_shipping_.GetItemKeyForCheckedItem() == kSameAsBillingKey;
   3094 }
   3095 
   3096 bool AutofillDialogControllerImpl::ShouldSaveDetailsLocally() {
   3097   // It's possible that the user checked [X] Save details locally before
   3098   // switching payment methods, so only ask the view whether to save details
   3099   // locally if that checkbox is showing (currently if not paying with wallet).
   3100   // Also, if the user isn't editing any sections, there's no data to save
   3101   // locally.
   3102   return ShouldOfferToSaveInChrome() && view_->SaveDetailsLocally();
   3103 }
   3104 
   3105 void AutofillDialogControllerImpl::SetIsSubmitting(bool submitting) {
   3106   is_submitting_ = submitting;
   3107 
   3108   if (!submitting)
   3109     full_wallet_.reset();
   3110 
   3111   if (view_) {
   3112     ScopedViewUpdates updates(view_.get());
   3113     view_->UpdateButtonStrip();
   3114     view_->UpdateOverlay();
   3115     view_->UpdateNotificationArea();
   3116   }
   3117 }
   3118 
   3119 bool AutofillDialogControllerImpl::AreLegalDocumentsCurrent() const {
   3120   return has_accepted_legal_documents_ ||
   3121       (wallet_items_ && wallet_items_->legal_documents().empty());
   3122 }
   3123 
   3124 void AutofillDialogControllerImpl::AcceptLegalTerms() {
   3125   content::BrowserThread::PostTask(
   3126       content::BrowserThread::IO, FROM_HERE,
   3127       base::Bind(&UserDidOptIntoLocationServices));
   3128   PrefService* local_state = g_browser_process->local_state();
   3129   ListPrefUpdate accepted(
   3130       local_state, ::prefs::kAutofillDialogWalletLocationAcceptance);
   3131   accepted->AppendIfNotPresent(new base::StringValue(
   3132       account_chooser_model_->GetActiveWalletAccountName()));
   3133 
   3134   if (AreLegalDocumentsCurrent()) {
   3135     LoadRiskFingerprintData();
   3136   } else {
   3137     GetWalletClient()->AcceptLegalDocuments(
   3138         wallet_items_->legal_documents(),
   3139         wallet_items_->google_transaction_id());
   3140   }
   3141 }
   3142 
   3143 void AutofillDialogControllerImpl::SubmitWithWallet() {
   3144   active_instrument_id_.clear();
   3145   active_address_id_.clear();
   3146   full_wallet_.reset();
   3147 
   3148   const wallet::WalletItems::MaskedInstrument* active_instrument =
   3149       ActiveInstrument();
   3150   if (!IsManuallyEditingSection(SECTION_CC_BILLING)) {
   3151     active_instrument_id_ = active_instrument->object_id();
   3152     DCHECK(!active_instrument_id_.empty());
   3153   }
   3154 
   3155   const wallet::Address* active_address = ActiveShippingAddress();
   3156   if (!IsManuallyEditingSection(SECTION_SHIPPING) &&
   3157       !ShouldUseBillingForShipping() &&
   3158       IsShippingAddressRequired()) {
   3159     active_address_id_ = active_address->object_id();
   3160     DCHECK(!active_address_id_.empty());
   3161   }
   3162 
   3163   scoped_ptr<wallet::Instrument> inputted_instrument =
   3164       CreateTransientInstrument();
   3165 
   3166   scoped_ptr<wallet::Address> inputted_address;
   3167   if (active_address_id_.empty() && IsShippingAddressRequired()) {
   3168     if (ShouldUseBillingForShipping()) {
   3169       const wallet::Address& address = inputted_instrument ?
   3170           *inputted_instrument->address() : active_instrument->address();
   3171       // Try to find an exact matched shipping address and use it for shipping,
   3172       // otherwise save it as a new shipping address. http://crbug.com/225442
   3173       const wallet::Address* duplicated_address =
   3174           FindDuplicateAddress(wallet_items_->addresses(), address);
   3175       if (duplicated_address) {
   3176         active_address_id_ = duplicated_address->object_id();
   3177         DCHECK(!active_address_id_.empty());
   3178       } else {
   3179         inputted_address.reset(new wallet::Address(address));
   3180         DCHECK(inputted_address->object_id().empty());
   3181       }
   3182     } else {
   3183       inputted_address = CreateTransientAddress();
   3184     }
   3185   }
   3186 
   3187   // If there's neither an address nor instrument to save, |GetFullWallet()|
   3188   // is called when the risk fingerprint is loaded.
   3189   if (!active_instrument_id_.empty() &&
   3190       (!active_address_id_.empty() || !IsShippingAddressRequired())) {
   3191     GetFullWallet();
   3192     return;
   3193   }
   3194 
   3195   GetWalletClient()->SaveToWallet(
   3196       inputted_instrument.Pass(),
   3197       inputted_address.Pass(),
   3198       IsEditingExistingData(SECTION_CC_BILLING) ? active_instrument : NULL,
   3199       IsEditingExistingData(SECTION_SHIPPING) ? active_address : NULL);
   3200 }
   3201 
   3202 scoped_ptr<wallet::Instrument> AutofillDialogControllerImpl::
   3203     CreateTransientInstrument() {
   3204   if (!active_instrument_id_.empty())
   3205     return scoped_ptr<wallet::Instrument>();
   3206 
   3207   FieldValueMap output;
   3208   view_->GetUserInput(SECTION_CC_BILLING, &output);
   3209 
   3210   CreditCard card;
   3211   AutofillProfile profile;
   3212   base::string16 cvc;
   3213   GetBillingInfoFromOutputs(output, &card, &cvc, &profile);
   3214 
   3215   return scoped_ptr<wallet::Instrument>(
   3216       new wallet::Instrument(card, cvc, profile));
   3217 }
   3218 
   3219 scoped_ptr<wallet::Address>AutofillDialogControllerImpl::
   3220     CreateTransientAddress() {
   3221   // If not using billing for shipping, just scrape the view.
   3222   FieldValueMap output;
   3223   view_->GetUserInput(SECTION_SHIPPING, &output);
   3224 
   3225   AutofillProfile profile;
   3226   FillFormGroupFromOutputs(output, &profile);
   3227 
   3228   return scoped_ptr<wallet::Address>(new wallet::Address(profile));
   3229 }
   3230 
   3231 void AutofillDialogControllerImpl::GetFullWallet() {
   3232   DCHECK(is_submitting_);
   3233   DCHECK(IsPayingWithWallet());
   3234   DCHECK(wallet_items_);
   3235   DCHECK(!active_instrument_id_.empty());
   3236   DCHECK(!active_address_id_.empty() || !IsShippingAddressRequired());
   3237 
   3238   std::vector<wallet::WalletClient::RiskCapability> capabilities;
   3239   capabilities.push_back(wallet::WalletClient::VERIFY_CVC);
   3240 
   3241   GetWalletClient()->GetFullWallet(wallet::WalletClient::FullWalletRequest(
   3242       active_instrument_id_,
   3243       active_address_id_,
   3244       wallet_items_->google_transaction_id(),
   3245       capabilities,
   3246       wallet_items_->HasRequiredAction(wallet::SETUP_WALLET)));
   3247 }
   3248 
   3249 void AutofillDialogControllerImpl::HandleSaveOrUpdateRequiredActions(
   3250     const std::vector<wallet::RequiredAction>& required_actions) {
   3251   DCHECK(!required_actions.empty());
   3252 
   3253   // TODO(ahutter): Investigate if we need to support more generic actions on
   3254   // this call such as GAIA_AUTH. See crbug.com/243457.
   3255   for (std::vector<wallet::RequiredAction>::const_iterator iter =
   3256            required_actions.begin();
   3257        iter != required_actions.end(); ++iter) {
   3258     if (*iter != wallet::INVALID_FORM_FIELD) {
   3259       // TODO(dbeam): handle this more gracefully.
   3260       DisableWallet(wallet::WalletClient::UNKNOWN_ERROR);
   3261     }
   3262   }
   3263   SetIsSubmitting(false);
   3264 }
   3265 
   3266 void AutofillDialogControllerImpl::FinishSubmit() {
   3267   if (IsPayingWithWallet()) {
   3268     ScopedViewUpdates updates(view_.get());
   3269     view_->UpdateOverlay();
   3270 
   3271     card_generated_animation_.Start();
   3272     return;
   3273   }
   3274   DoFinishSubmit();
   3275 }
   3276 
   3277 void AutofillDialogControllerImpl::AnimationProgressed(
   3278     const gfx::Animation* animation) {
   3279   DCHECK_EQ(animation, &card_generated_animation_);
   3280   PushOverlayUpdate();
   3281 }
   3282 
   3283 void AutofillDialogControllerImpl::AnimationEnded(
   3284     const gfx::Animation* animation) {
   3285   DCHECK_EQ(animation, &card_generated_animation_);
   3286   DoFinishSubmit();
   3287 }
   3288 
   3289 void AutofillDialogControllerImpl::DoFinishSubmit() {
   3290   FillOutputForSection(SECTION_CC);
   3291   FillOutputForSection(SECTION_BILLING);
   3292   FillOutputForSection(SECTION_CC_BILLING);
   3293 
   3294   if (ShouldUseBillingForShipping()) {
   3295     FillOutputForSectionWithComparator(
   3296         SECTION_BILLING,
   3297         base::Bind(DetailInputMatchesShippingField));
   3298     FillOutputForSectionWithComparator(
   3299         SECTION_CC,
   3300         base::Bind(DetailInputMatchesShippingField));
   3301     FillOutputForSectionWithComparator(
   3302         SECTION_CC_BILLING,
   3303         base::Bind(DetailInputMatchesShippingField));
   3304   } else {
   3305     FillOutputForSection(SECTION_SHIPPING);
   3306   }
   3307 
   3308   if (IsPayingWithWallet()) {
   3309     if (SectionIsActive(SECTION_SHIPPING)) {
   3310       profile_->GetPrefs()->SetBoolean(
   3311           ::prefs::kAutofillDialogWalletShippingSameAsBilling,
   3312           suggested_shipping_.GetItemKeyForCheckedItem() == kSameAsBillingKey);
   3313     }
   3314   } else {
   3315     for (size_t i = SECTION_MIN; i <= SECTION_MAX; ++i) {
   3316       DialogSection section = static_cast<DialogSection>(i);
   3317       if (!SectionIsActive(section))
   3318         continue;
   3319 
   3320       SuggestionsMenuModel* model = SuggestionsMenuModelForSection(section);
   3321       std::string item_key = model->GetItemKeyForCheckedItem();
   3322       if (IsASuggestionItemKey(item_key) || item_key == kSameAsBillingKey) {
   3323         PersistAutofillChoice(section, item_key);
   3324       } else if (item_key == kAddNewItemKey && ShouldSaveDetailsLocally()) {
   3325         DCHECK(newly_saved_data_model_guids_.count(section));
   3326         PersistAutofillChoice(section, newly_saved_data_model_guids_[section]);
   3327       }
   3328     }
   3329 
   3330     profile_->GetPrefs()->SetBoolean(::prefs::kAutofillDialogSaveData,
   3331                                      view_->SaveDetailsLocally());
   3332   }
   3333 
   3334   // On a successful submit, if the user manually selected "pay without wallet",
   3335   // stop trying to pay with Wallet on future runs of the dialog. On the other
   3336   // hand, if there was an error that prevented the user from having the choice
   3337   // of using Wallet, leave the pref alone.
   3338   if (!wallet_error_notification_ &&
   3339       account_chooser_model_->HasAccountsToChoose()) {
   3340     profile_->GetPrefs()->SetBoolean(
   3341         ::prefs::kAutofillDialogPayWithoutWallet,
   3342         !account_chooser_model_->WalletIsSelected());
   3343   }
   3344 
   3345   LogOnFinishSubmitMetrics();
   3346 
   3347   // Callback should be called as late as possible.
   3348   callback_.Run(&form_structure_);
   3349   data_was_passed_back_ = true;
   3350 
   3351   // This might delete us.
   3352   Hide();
   3353 }
   3354 
   3355 void AutofillDialogControllerImpl::PersistAutofillChoice(
   3356     DialogSection section,
   3357     const std::string& guid) {
   3358   DCHECK(!IsPayingWithWallet());
   3359   scoped_ptr<base::DictionaryValue> value(new base::DictionaryValue());
   3360   value->SetString(kGuidPrefKey, guid);
   3361 
   3362   DictionaryPrefUpdate updater(profile()->GetPrefs(),
   3363                                ::prefs::kAutofillDialogAutofillDefault);
   3364   base::DictionaryValue* autofill_choice = updater.Get();
   3365   autofill_choice->Set(SectionToPrefString(section), value.release());
   3366 }
   3367 
   3368 void AutofillDialogControllerImpl::GetDefaultAutofillChoice(
   3369     DialogSection section,
   3370     std::string* guid) {
   3371   DCHECK(!IsPayingWithWallet());
   3372   // The default choice is the first thing in the menu that is a suggestion
   3373   // item.
   3374   SuggestionsMenuModel* model = SuggestionsMenuModelForSection(section);
   3375   for (int i = 0; i < model->GetItemCount(); ++i) {
   3376     if (IsASuggestionItemKey(model->GetItemKeyAt(i))) {
   3377       *guid = model->GetItemKeyAt(i);
   3378       break;
   3379     }
   3380   }
   3381 }
   3382 
   3383 bool AutofillDialogControllerImpl::GetAutofillChoice(DialogSection section,
   3384                                                      std::string* guid) {
   3385   DCHECK(!IsPayingWithWallet());
   3386   const base::DictionaryValue* choices = profile()->GetPrefs()->GetDictionary(
   3387       ::prefs::kAutofillDialogAutofillDefault);
   3388   if (!choices)
   3389     return false;
   3390 
   3391   const base::DictionaryValue* choice = NULL;
   3392   if (!choices->GetDictionary(SectionToPrefString(section), &choice))
   3393     return false;
   3394 
   3395   choice->GetString(kGuidPrefKey, guid);
   3396   return true;
   3397 }
   3398 
   3399 void AutofillDialogControllerImpl::LogOnFinishSubmitMetrics() {
   3400   GetMetricLogger().LogDialogUiDuration(
   3401       base::Time::Now() - dialog_shown_timestamp_,
   3402       AutofillMetrics::DIALOG_ACCEPTED);
   3403 
   3404   GetMetricLogger().LogDialogUiEvent(AutofillMetrics::DIALOG_UI_ACCEPTED);
   3405 
   3406   AutofillMetrics::DialogDismissalState dismissal_state;
   3407   if (!IsManuallyEditingAnySection())
   3408     dismissal_state = AutofillMetrics::DIALOG_ACCEPTED_EXISTING_DATA;
   3409   else if (IsPayingWithWallet())
   3410     dismissal_state = AutofillMetrics::DIALOG_ACCEPTED_SAVE_TO_WALLET;
   3411   else if (ShouldSaveDetailsLocally())
   3412     dismissal_state = AutofillMetrics::DIALOG_ACCEPTED_SAVE_TO_AUTOFILL;
   3413   else
   3414     dismissal_state = AutofillMetrics::DIALOG_ACCEPTED_NO_SAVE;
   3415 
   3416   GetMetricLogger().LogDialogDismissalState(dismissal_state);
   3417 }
   3418 
   3419 void AutofillDialogControllerImpl::LogOnCancelMetrics() {
   3420   GetMetricLogger().LogDialogUiEvent(AutofillMetrics::DIALOG_UI_CANCELED);
   3421 
   3422   AutofillMetrics::DialogDismissalState dismissal_state;
   3423   if (ShouldShowSignInWebView())
   3424     dismissal_state = AutofillMetrics::DIALOG_CANCELED_DURING_SIGNIN;
   3425   else if (!IsManuallyEditingAnySection())
   3426     dismissal_state = AutofillMetrics::DIALOG_CANCELED_NO_EDITS;
   3427   else if (AllSectionsAreValid())
   3428     dismissal_state = AutofillMetrics::DIALOG_CANCELED_NO_INVALID_FIELDS;
   3429   else
   3430     dismissal_state = AutofillMetrics::DIALOG_CANCELED_WITH_INVALID_FIELDS;
   3431 
   3432   GetMetricLogger().LogDialogDismissalState(dismissal_state);
   3433 
   3434   GetMetricLogger().LogDialogUiDuration(
   3435       base::Time::Now() - dialog_shown_timestamp_,
   3436       AutofillMetrics::DIALOG_CANCELED);
   3437 }
   3438 
   3439 void AutofillDialogControllerImpl::LogSuggestionItemSelectedMetric(
   3440     const SuggestionsMenuModel& model) {
   3441   DialogSection section = SectionForSuggestionsMenuModel(model);
   3442 
   3443   AutofillMetrics::DialogUiEvent dialog_ui_event;
   3444   if (model.GetItemKeyForCheckedItem() == kAddNewItemKey) {
   3445     // Selected to add a new item.
   3446     dialog_ui_event = common::DialogSectionToUiItemAddedEvent(section);
   3447   } else if (IsASuggestionItemKey(model.GetItemKeyForCheckedItem())) {
   3448     // Selected an existing item.
   3449     dialog_ui_event = common::DialogSectionToUiSelectionChangedEvent(section);
   3450   } else {
   3451     // TODO(estade): add logging for "Manage items" or "Use billing for
   3452     // shipping"?
   3453     return;
   3454   }
   3455 
   3456   GetMetricLogger().LogDialogUiEvent(dialog_ui_event);
   3457 }
   3458 
   3459 void AutofillDialogControllerImpl::LogDialogLatencyToShow() {
   3460   if (was_ui_latency_logged_)
   3461     return;
   3462 
   3463   GetMetricLogger().LogDialogLatencyToShow(
   3464       base::Time::Now() - dialog_shown_timestamp_);
   3465   was_ui_latency_logged_ = true;
   3466 }
   3467 
   3468 AutofillMetrics::DialogInitialUserStateMetric
   3469     AutofillDialogControllerImpl::GetInitialUserState() const {
   3470   // Consider a user to be an Autofill user if the user has any credit cards
   3471   // or addresses saved. Check that the item count is greater than 2 because
   3472   // an "empty" menu still has the "add new" menu item and "manage" menu item.
   3473   const bool has_autofill_profiles =
   3474       suggested_cc_.GetItemCount() > 2 ||
   3475       suggested_billing_.GetItemCount() > 2;
   3476 
   3477   if (SignedInState() != SIGNED_IN) {
   3478     // Not signed in.
   3479     return has_autofill_profiles ?
   3480         AutofillMetrics::DIALOG_USER_NOT_SIGNED_IN_HAS_AUTOFILL :
   3481         AutofillMetrics::DIALOG_USER_NOT_SIGNED_IN_NO_AUTOFILL;
   3482   }
   3483 
   3484   // Signed in.
   3485   if (wallet_items_->instruments().empty()) {
   3486     // No Wallet items.
   3487     return has_autofill_profiles ?
   3488         AutofillMetrics::DIALOG_USER_SIGNED_IN_NO_WALLET_HAS_AUTOFILL :
   3489         AutofillMetrics::DIALOG_USER_SIGNED_IN_NO_WALLET_NO_AUTOFILL;
   3490   }
   3491 
   3492   // Has Wallet items.
   3493   return has_autofill_profiles ?
   3494       AutofillMetrics::DIALOG_USER_SIGNED_IN_HAS_WALLET_HAS_AUTOFILL :
   3495       AutofillMetrics::DIALOG_USER_SIGNED_IN_HAS_WALLET_NO_AUTOFILL;
   3496 }
   3497 
   3498 void AutofillDialogControllerImpl::MaybeShowCreditCardBubble() {
   3499   if (!data_was_passed_back_)
   3500     return;
   3501 
   3502   if (newly_saved_card_) {
   3503     scoped_ptr<AutofillProfile> billing_profile;
   3504     if (IsManuallyEditingSection(SECTION_BILLING)) {
   3505       // Scrape the view as the user's entering or updating information.
   3506       FieldValueMap outputs;
   3507       view_->GetUserInput(SECTION_BILLING, &outputs);
   3508       billing_profile.reset(new AutofillProfile);
   3509       FillFormGroupFromOutputs(outputs, billing_profile.get());
   3510     } else {
   3511       // Just snag the currently suggested profile.
   3512       std::string item_key = SuggestionsMenuModelForSection(SECTION_BILLING)->
   3513           GetItemKeyForCheckedItem();
   3514       AutofillProfile* profile = GetManager()->GetProfileByGUID(item_key);
   3515       billing_profile.reset(new AutofillProfile(*profile));
   3516     }
   3517 
   3518     ShowNewCreditCardBubble(newly_saved_card_.Pass(),
   3519                             billing_profile.Pass());
   3520     return;
   3521   }
   3522 
   3523   if (!full_wallet_ || !full_wallet_->billing_address())
   3524     return;
   3525 
   3526 #if !defined(OS_ANDROID)
   3527   GeneratedCreditCardBubbleController::Show(
   3528       web_contents(),
   3529       full_wallet_->TypeAndLastFourDigits(),
   3530       backing_card_last_four_);
   3531 #endif
   3532 }
   3533 
   3534 void AutofillDialogControllerImpl::OnSubmitButtonDelayEnd() {
   3535   if (!view_)
   3536     return;
   3537   ScopedViewUpdates updates(view_.get());
   3538   view_->UpdateButtonStrip();
   3539 }
   3540 
   3541 void AutofillDialogControllerImpl::FetchWalletCookie() {
   3542   net::URLRequestContextGetter* request_context = profile_->GetRequestContext();
   3543   signin_helper_.reset(new wallet::WalletSigninHelper(this, request_context));
   3544   signin_helper_->StartWalletCookieValueFetch();
   3545 }
   3546 
   3547 }  // namespace autofill
   3548