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