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