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