Home | History | Annotate | Download | only in options
      1 // Copyright (c) 2012 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/webui/options/autofill_options_handler.h"
      6 
      7 #include <vector>
      8 
      9 #include "base/bind.h"
     10 #include "base/bind_helpers.h"
     11 #include "base/guid.h"
     12 #include "base/logging.h"
     13 #include "base/strings/string16.h"
     14 #include "base/strings/string_number_conversions.h"
     15 #include "base/strings/utf_string_conversions.h"
     16 #include "base/values.h"
     17 #include "chrome/browser/autofill/personal_data_manager_factory.h"
     18 #include "chrome/browser/browser_process.h"
     19 #include "chrome/browser/profiles/profile.h"
     20 #include "chrome/browser/ui/autofill/country_combobox_model.h"
     21 #include "chrome/common/url_constants.h"
     22 #include "components/autofill/core/browser/autofill_country.h"
     23 #include "components/autofill/core/browser/autofill_profile.h"
     24 #include "components/autofill/core/browser/credit_card.h"
     25 #include "components/autofill/core/browser/personal_data_manager.h"
     26 #include "components/autofill/core/browser/phone_number_i18n.h"
     27 #include "components/autofill/core/common/autofill_constants.h"
     28 #include "content/public/browser/web_ui.h"
     29 #include "grit/components_strings.h"
     30 #include "grit/generated_resources.h"
     31 #include "grit/libaddressinput_strings.h"
     32 #include "third_party/libaddressinput/chromium/cpp/include/libaddressinput/address_ui.h"
     33 #include "third_party/libaddressinput/chromium/cpp/include/libaddressinput/address_ui_component.h"
     34 #include "ui/base/l10n/l10n_util.h"
     35 #include "ui/base/webui/web_ui_util.h"
     36 
     37 using autofill::AutofillCountry;
     38 using autofill::ServerFieldType;
     39 using autofill::AutofillProfile;
     40 using autofill::CreditCard;
     41 using autofill::PersonalDataManager;
     42 using i18n::addressinput::AddressUiComponent;
     43 
     44 namespace {
     45 
     46 const char kSettingsOrigin[] = "Chrome settings";
     47 
     48 static const char kFullNameField[] = "fullName";
     49 static const char kCompanyNameField[] = "companyName";
     50 static const char kAddressLineField[] = "addrLines";
     51 static const char kDependentLocalityField[] = "dependentLocality";
     52 static const char kCityField[] = "city";
     53 static const char kStateField[] = "state";
     54 static const char kPostalCodeField[] = "postalCode";
     55 static const char kSortingCodeField[] = "sortingCode";
     56 static const char kCountryField[] = "country";
     57 
     58 static const char kComponents[] = "components";
     59 static const char kLanguageCode[] = "languageCode";
     60 
     61 // Fills |components| with the address UI components that should be used to
     62 // input an address for |country_code| when UI BCP 47 language code is
     63 // |ui_language_code|. If |components_language_code| is not NULL, then sets it
     64 // to the BCP 47 language code that should be used to format the address for
     65 // display.
     66 void GetAddressComponents(const std::string& country_code,
     67                           const std::string& ui_language_code,
     68                           base::ListValue* address_components,
     69                           std::string* components_language_code) {
     70   DCHECK(address_components);
     71 
     72   std::vector<AddressUiComponent> components =
     73       i18n::addressinput::BuildComponents(
     74           country_code, ui_language_code, components_language_code);
     75   if (components.empty()) {
     76     static const char kDefaultCountryCode[] = "US";
     77     components = i18n::addressinput::BuildComponents(
     78         kDefaultCountryCode, ui_language_code, components_language_code);
     79   }
     80   DCHECK(!components.empty());
     81 
     82   base::ListValue* line = NULL;
     83   static const char kField[] = "field";
     84   static const char kLength[] = "length";
     85   for (size_t i = 0; i < components.size(); ++i) {
     86     if (i == 0 ||
     87         components[i - 1].length_hint == AddressUiComponent::HINT_LONG ||
     88         components[i].length_hint == AddressUiComponent::HINT_LONG) {
     89       line = new base::ListValue;
     90       address_components->Append(line);
     91     }
     92 
     93     scoped_ptr<base::DictionaryValue> component(new base::DictionaryValue);
     94     component->SetString(
     95         "name", l10n_util::GetStringUTF16(components[i].name_id));
     96 
     97     switch (components[i].field) {
     98       case i18n::addressinput::COUNTRY:
     99         component->SetString(kField, kCountryField);
    100         break;
    101       case i18n::addressinput::ADMIN_AREA:
    102         component->SetString(kField, kStateField);
    103         break;
    104       case i18n::addressinput::LOCALITY:
    105         component->SetString(kField, kCityField);
    106         break;
    107       case i18n::addressinput::DEPENDENT_LOCALITY:
    108         component->SetString(kField, kDependentLocalityField);
    109         break;
    110       case i18n::addressinput::SORTING_CODE:
    111         component->SetString(kField, kSortingCodeField);
    112         break;
    113       case i18n::addressinput::POSTAL_CODE:
    114         component->SetString(kField, kPostalCodeField);
    115         break;
    116       case i18n::addressinput::STREET_ADDRESS:
    117         component->SetString(kField, kAddressLineField);
    118         break;
    119       case i18n::addressinput::ORGANIZATION:
    120         component->SetString(kField, kCompanyNameField);
    121         break;
    122       case i18n::addressinput::RECIPIENT:
    123         component->SetString(kField, kFullNameField);
    124         component->SetString(
    125             "placeholder",
    126             l10n_util::GetStringUTF16(IDS_AUTOFILL_FIELD_LABEL_ADD_NAME));
    127         break;
    128     }
    129 
    130     switch (components[i].length_hint) {
    131       case AddressUiComponent::HINT_LONG:
    132         component->SetString(kLength, "long");
    133         break;
    134       case AddressUiComponent::HINT_SHORT:
    135         component->SetString(kLength, "short");
    136         break;
    137     }
    138 
    139     line->Append(component.release());
    140   }
    141 }
    142 
    143 // Sets data related to the country <select>.
    144 void SetCountryData(const PersonalDataManager& manager,
    145                     base::DictionaryValue* localized_strings) {
    146   autofill::CountryComboboxModel model(
    147       manager, base::Callback<bool(const std::string&)>());
    148   const std::vector<AutofillCountry*>& countries = model.countries();
    149   localized_strings->SetString("defaultCountryCode",
    150                                countries.front()->country_code());
    151 
    152   // An ordered list of options to show in the <select>.
    153   scoped_ptr<base::ListValue> country_list(new base::ListValue());
    154   for (size_t i = 0; i < countries.size(); ++i) {
    155     scoped_ptr<base::DictionaryValue> option_details(
    156         new base::DictionaryValue());
    157     option_details->SetString("name", model.GetItemAt(i));
    158     option_details->SetString(
    159         "value",
    160         countries[i] ? countries[i]->country_code() : "separator");
    161     country_list->Append(option_details.release());
    162   }
    163   localized_strings->Set("autofillCountrySelectList", country_list.release());
    164 
    165   scoped_ptr<base::ListValue> default_country_components(new base::ListValue);
    166   std::string default_country_language_code;
    167   GetAddressComponents(countries.front()->country_code(),
    168                        g_browser_process->GetApplicationLocale(),
    169                        default_country_components.get(),
    170                        &default_country_language_code);
    171   localized_strings->Set("autofillDefaultCountryComponents",
    172                          default_country_components.release());
    173   localized_strings->SetString("autofillDefaultCountryLanguageCode",
    174                                default_country_language_code);
    175 }
    176 
    177 // Get the multi-valued element for |type| and return it in |ListValue| form.
    178 void GetValueList(const AutofillProfile& profile,
    179                   ServerFieldType type,
    180                   scoped_ptr<base::ListValue>* list) {
    181   list->reset(new base::ListValue);
    182 
    183   std::vector<base::string16> values;
    184   profile.GetRawMultiInfo(type, &values);
    185 
    186   // |GetRawMultiInfo()| always returns at least one, potentially empty, item.
    187   if (values.size() == 1 && values.front().empty())
    188     return;
    189 
    190   for (size_t i = 0; i < values.size(); ++i) {
    191     (*list)->Set(i, new base::StringValue(values[i]));
    192   }
    193 }
    194 
    195 // Set the multi-valued element for |type| from input |list| values.
    196 void SetValueList(const base::ListValue* list,
    197                   ServerFieldType type,
    198                   AutofillProfile* profile) {
    199   std::vector<base::string16> values(list->GetSize());
    200   for (size_t i = 0; i < list->GetSize(); ++i) {
    201     base::string16 value;
    202     if (list->GetString(i, &value))
    203       values[i] = value;
    204   }
    205   profile->SetRawMultiInfo(type, values);
    206 }
    207 
    208 // Pulls the phone number |index|, |phone_number_list|, and |country_code| from
    209 // the |args| input.
    210 void ExtractPhoneNumberInformation(const base::ListValue* args,
    211                                    size_t* index,
    212                                    const base::ListValue** phone_number_list,
    213                                    std::string* country_code) {
    214   // Retrieve index as a |double|, as that is how it comes across from
    215   // JavaScript.
    216   double number = 0.0;
    217   if (!args->GetDouble(0, &number)) {
    218     NOTREACHED();
    219     return;
    220   }
    221   *index = number;
    222 
    223   if (!args->GetList(1, phone_number_list)) {
    224     NOTREACHED();
    225     return;
    226   }
    227 
    228   if (!args->GetString(2, country_code)) {
    229     NOTREACHED();
    230     return;
    231   }
    232 }
    233 
    234 // Searches the |list| for the value at |index|.  If this value is present
    235 // in any of the rest of the list, then the item (at |index|) is removed.
    236 // The comparison of phone number values is done on normalized versions of the
    237 // phone number values.
    238 void RemoveDuplicatePhoneNumberAtIndex(size_t index,
    239                                        const std::string& country_code,
    240                                        base::ListValue* list) {
    241   base::string16 new_value;
    242   if (!list->GetString(index, &new_value)) {
    243     NOTREACHED() << "List should have a value at index " << index;
    244     return;
    245   }
    246 
    247   bool is_duplicate = false;
    248   std::string app_locale = g_browser_process->GetApplicationLocale();
    249   for (size_t i = 0; i < list->GetSize() && !is_duplicate; ++i) {
    250     if (i == index)
    251       continue;
    252 
    253     base::string16 existing_value;
    254     if (!list->GetString(i, &existing_value)) {
    255       NOTREACHED() << "List should have a value at index " << i;
    256       continue;
    257     }
    258     is_duplicate = autofill::i18n::PhoneNumbersMatch(
    259         new_value, existing_value, country_code, app_locale);
    260   }
    261 
    262   if (is_duplicate)
    263     list->Remove(index, NULL);
    264 }
    265 
    266 scoped_ptr<base::ListValue> ValidatePhoneArguments(
    267     const base::ListValue* args) {
    268   size_t index = 0;
    269   std::string country_code;
    270   const base::ListValue* extracted_list = NULL;
    271   ExtractPhoneNumberInformation(args, &index, &extracted_list, &country_code);
    272 
    273   scoped_ptr<base::ListValue> list(extracted_list->DeepCopy());
    274   RemoveDuplicatePhoneNumberAtIndex(index, country_code, list.get());
    275   return list.Pass();
    276 }
    277 
    278 }  // namespace
    279 
    280 namespace options {
    281 
    282 AutofillOptionsHandler::AutofillOptionsHandler()
    283     : personal_data_(NULL) {}
    284 
    285 AutofillOptionsHandler::~AutofillOptionsHandler() {
    286   if (personal_data_)
    287     personal_data_->RemoveObserver(this);
    288 }
    289 
    290 /////////////////////////////////////////////////////////////////////////////
    291 // OptionsPageUIHandler implementation:
    292 void AutofillOptionsHandler::GetLocalizedValues(
    293     base::DictionaryValue* localized_strings) {
    294   DCHECK(localized_strings);
    295 
    296   static OptionsStringResource resources[] = {
    297     { "autofillAddresses", IDS_AUTOFILL_ADDRESSES_GROUP_NAME },
    298     { "autofillCreditCards", IDS_AUTOFILL_CREDITCARDS_GROUP_NAME },
    299     { "autofillAddAddress", IDS_AUTOFILL_ADD_ADDRESS_BUTTON },
    300     { "autofillAddCreditCard", IDS_AUTOFILL_ADD_CREDITCARD_BUTTON },
    301     { "autofillEditProfileButton", IDS_AUTOFILL_EDIT_PROFILE_BUTTON },
    302     { "helpButton", IDS_AUTOFILL_HELP_LABEL },
    303     { "addAddressTitle", IDS_AUTOFILL_ADD_ADDRESS_CAPTION },
    304     { "editAddressTitle", IDS_AUTOFILL_EDIT_ADDRESS_CAPTION },
    305     { "addCreditCardTitle", IDS_AUTOFILL_ADD_CREDITCARD_CAPTION },
    306     { "editCreditCardTitle", IDS_AUTOFILL_EDIT_CREDITCARD_CAPTION },
    307 #if defined(OS_MACOSX)
    308     { "auxiliaryProfilesEnabled", IDS_AUTOFILL_USE_MAC_ADDRESS_BOOK },
    309 #endif  // defined(OS_MACOSX)
    310   };
    311 
    312   RegisterStrings(localized_strings, resources, arraysize(resources));
    313   RegisterTitle(localized_strings, "autofillOptionsPage",
    314                 IDS_AUTOFILL_OPTIONS_TITLE);
    315 
    316   localized_strings->SetString("helpUrl", autofill::kHelpURL);
    317   SetAddressOverlayStrings(localized_strings);
    318   SetCreditCardOverlayStrings(localized_strings);
    319 }
    320 
    321 void AutofillOptionsHandler::InitializeHandler() {
    322   // personal_data_ is NULL in guest mode on Chrome OS.
    323   if (personal_data_)
    324     personal_data_->AddObserver(this);
    325 }
    326 
    327 void AutofillOptionsHandler::InitializePage() {
    328   if (personal_data_)
    329     LoadAutofillData();
    330 }
    331 
    332 void AutofillOptionsHandler::RegisterMessages() {
    333   personal_data_ = autofill::PersonalDataManagerFactory::GetForProfile(
    334       Profile::FromWebUI(web_ui()));
    335 
    336 #if defined(OS_MACOSX) && !defined(OS_IOS)
    337   web_ui()->RegisterMessageCallback(
    338       "accessAddressBook",
    339       base::Bind(&AutofillOptionsHandler::AccessAddressBook,
    340                  base::Unretained(this)));
    341 #endif  // defined(OS_MACOSX) && !defined(OS_IOS)
    342   web_ui()->RegisterMessageCallback(
    343       "removeData",
    344       base::Bind(&AutofillOptionsHandler::RemoveData,
    345                  base::Unretained(this)));
    346   web_ui()->RegisterMessageCallback(
    347       "loadAddressEditor",
    348       base::Bind(&AutofillOptionsHandler::LoadAddressEditor,
    349                  base::Unretained(this)));
    350   web_ui()->RegisterMessageCallback(
    351       "loadAddressEditorComponents",
    352       base::Bind(&AutofillOptionsHandler::LoadAddressEditorComponents,
    353                  base::Unretained(this)));
    354   web_ui()->RegisterMessageCallback(
    355       "loadCreditCardEditor",
    356       base::Bind(&AutofillOptionsHandler::LoadCreditCardEditor,
    357                  base::Unretained(this)));
    358   web_ui()->RegisterMessageCallback(
    359       "setAddress",
    360       base::Bind(&AutofillOptionsHandler::SetAddress, base::Unretained(this)));
    361   web_ui()->RegisterMessageCallback(
    362       "setCreditCard",
    363       base::Bind(&AutofillOptionsHandler::SetCreditCard,
    364                  base::Unretained(this)));
    365   web_ui()->RegisterMessageCallback(
    366       "validatePhoneNumbers",
    367       base::Bind(&AutofillOptionsHandler::ValidatePhoneNumbers,
    368                  base::Unretained(this)));
    369 }
    370 
    371 /////////////////////////////////////////////////////////////////////////////
    372 // PersonalDataManagerObserver implementation:
    373 void AutofillOptionsHandler::OnPersonalDataChanged() {
    374   LoadAutofillData();
    375 }
    376 
    377 void AutofillOptionsHandler::SetAddressOverlayStrings(
    378     base::DictionaryValue* localized_strings) {
    379   localized_strings->SetString("autofillEditAddressTitle",
    380       l10n_util::GetStringUTF16(IDS_AUTOFILL_EDIT_ADDRESS_CAPTION));
    381   localized_strings->SetString("autofillCountryLabel",
    382       l10n_util::GetStringUTF16(IDS_LIBADDRESSINPUT_I18N_COUNTRY_LABEL));
    383   localized_strings->SetString("autofillPhoneLabel",
    384       l10n_util::GetStringUTF16(IDS_AUTOFILL_FIELD_LABEL_PHONE));
    385   localized_strings->SetString("autofillEmailLabel",
    386       l10n_util::GetStringUTF16(IDS_AUTOFILL_FIELD_LABEL_EMAIL));
    387   localized_strings->SetString("autofillAddPhonePlaceholder",
    388       l10n_util::GetStringUTF16(IDS_AUTOFILL_FIELD_LABEL_ADD_PHONE));
    389   localized_strings->SetString("autofillAddEmailPlaceholder",
    390       l10n_util::GetStringUTF16(IDS_AUTOFILL_FIELD_LABEL_ADD_EMAIL));
    391   SetCountryData(*personal_data_, localized_strings);
    392 }
    393 
    394 void AutofillOptionsHandler::SetCreditCardOverlayStrings(
    395     base::DictionaryValue* localized_strings) {
    396   localized_strings->SetString("autofillEditCreditCardTitle",
    397       l10n_util::GetStringUTF16(IDS_AUTOFILL_EDIT_CREDITCARD_CAPTION));
    398   localized_strings->SetString("nameOnCardLabel",
    399       l10n_util::GetStringUTF16(IDS_AUTOFILL_FIELD_LABEL_NAME_ON_CARD));
    400   localized_strings->SetString("creditCardNumberLabel",
    401       l10n_util::GetStringUTF16(IDS_AUTOFILL_FIELD_LABEL_CREDIT_CARD_NUMBER));
    402   localized_strings->SetString("creditCardExpirationDateLabel",
    403       l10n_util::GetStringUTF16(IDS_AUTOFILL_FIELD_LABEL_EXPIRATION_DATE));
    404 }
    405 
    406 void AutofillOptionsHandler::LoadAutofillData() {
    407   if (!IsPersonalDataLoaded())
    408     return;
    409 
    410   const std::vector<AutofillProfile*>& profiles =
    411       personal_data_->web_profiles();
    412   std::vector<base::string16> labels;
    413   AutofillProfile::CreateDifferentiatingLabels(profiles, &labels);
    414   DCHECK_EQ(labels.size(), profiles.size());
    415 
    416   base::ListValue addresses;
    417   for (size_t i = 0; i < profiles.size(); ++i) {
    418     base::ListValue* entry = new base::ListValue();
    419     entry->Append(new base::StringValue(profiles[i]->guid()));
    420     entry->Append(new base::StringValue(labels[i]));
    421     addresses.Append(entry);
    422   }
    423 
    424   web_ui()->CallJavascriptFunction("AutofillOptions.setAddressList", addresses);
    425 
    426   base::ListValue credit_cards;
    427   const std::vector<CreditCard*>& cards = personal_data_->GetCreditCards();
    428   for (std::vector<CreditCard*>::const_iterator iter = cards.begin();
    429        iter != cards.end(); ++iter) {
    430     const CreditCard* card = *iter;
    431     // TODO(estade): this should be a dictionary.
    432     base::ListValue* entry = new base::ListValue();
    433     entry->Append(new base::StringValue(card->guid()));
    434     entry->Append(new base::StringValue(card->Label()));
    435     entry->Append(new base::StringValue(
    436         webui::GetBitmapDataUrlFromResource(
    437             CreditCard::IconResourceId(card->type()))));
    438     entry->Append(new base::StringValue(card->TypeForDisplay()));
    439     credit_cards.Append(entry);
    440   }
    441 
    442   web_ui()->CallJavascriptFunction("AutofillOptions.setCreditCardList",
    443                                    credit_cards);
    444 }
    445 
    446 #if defined(OS_MACOSX) && !defined(OS_IOS)
    447 void AutofillOptionsHandler::AccessAddressBook(const base::ListValue* args) {
    448   personal_data_->AccessAddressBook();
    449 }
    450 #endif  // defined(OS_MACOSX) && !defined(OS_IOS)
    451 
    452 void AutofillOptionsHandler::RemoveData(const base::ListValue* args) {
    453   DCHECK(IsPersonalDataLoaded());
    454 
    455   std::string guid;
    456   if (!args->GetString(0, &guid)) {
    457     NOTREACHED();
    458     return;
    459   }
    460 
    461   personal_data_->RemoveByGUID(guid);
    462 }
    463 
    464 void AutofillOptionsHandler::LoadAddressEditor(const base::ListValue* args) {
    465   DCHECK(IsPersonalDataLoaded());
    466 
    467   std::string guid;
    468   if (!args->GetString(0, &guid)) {
    469     NOTREACHED();
    470     return;
    471   }
    472 
    473   AutofillProfile* profile = personal_data_->GetProfileByGUID(guid);
    474   if (!profile) {
    475     // There is a race where a user can click once on the close button and
    476     // quickly click again on the list item before the item is removed (since
    477     // the list is not updated until the model tells the list an item has been
    478     // removed). This will activate the editor for a profile that has been
    479     // removed. Do nothing in that case.
    480     return;
    481   }
    482 
    483   base::DictionaryValue address;
    484   address.SetString("guid", profile->guid());
    485   scoped_ptr<base::ListValue> list;
    486   GetValueList(*profile, autofill::NAME_FULL, &list);
    487   address.Set(kFullNameField, list.release());
    488   address.SetString(
    489       kCompanyNameField, profile->GetRawInfo(autofill::COMPANY_NAME));
    490   address.SetString(kAddressLineField,
    491                     profile->GetRawInfo(autofill::ADDRESS_HOME_STREET_ADDRESS));
    492   address.SetString(
    493       kCityField, profile->GetRawInfo(autofill::ADDRESS_HOME_CITY));
    494   address.SetString(
    495       kStateField, profile->GetRawInfo(autofill::ADDRESS_HOME_STATE));
    496   address.SetString(
    497       kDependentLocalityField,
    498       profile->GetRawInfo(autofill::ADDRESS_HOME_DEPENDENT_LOCALITY));
    499   address.SetString(kSortingCodeField,
    500                     profile->GetRawInfo(autofill::ADDRESS_HOME_SORTING_CODE));
    501   address.SetString(kPostalCodeField,
    502                     profile->GetRawInfo(autofill::ADDRESS_HOME_ZIP));
    503   address.SetString(kCountryField,
    504                     profile->GetRawInfo(autofill::ADDRESS_HOME_COUNTRY));
    505   GetValueList(*profile, autofill::PHONE_HOME_WHOLE_NUMBER, &list);
    506   address.Set("phone", list.release());
    507   GetValueList(*profile, autofill::EMAIL_ADDRESS, &list);
    508   address.Set("email", list.release());
    509   address.SetString(kLanguageCode, profile->language_code());
    510 
    511   scoped_ptr<base::ListValue> components(new base::ListValue);
    512   GetAddressComponents(
    513       base::UTF16ToUTF8(profile->GetRawInfo(autofill::ADDRESS_HOME_COUNTRY)),
    514       profile->language_code(), components.get(), NULL);
    515   address.Set(kComponents, components.release());
    516 
    517   web_ui()->CallJavascriptFunction("AutofillOptions.editAddress", address);
    518 }
    519 
    520 void AutofillOptionsHandler::LoadAddressEditorComponents(
    521     const base::ListValue* args) {
    522   std::string country_code;
    523   if (!args->GetString(0, &country_code)) {
    524     NOTREACHED();
    525     return;
    526   }
    527 
    528   base::DictionaryValue input;
    529   scoped_ptr<base::ListValue> components(new base::ListValue);
    530   std::string language_code;
    531   GetAddressComponents(country_code, g_browser_process->GetApplicationLocale(),
    532                        components.get(), &language_code);
    533   input.Set(kComponents, components.release());
    534   input.SetString(kLanguageCode, language_code);
    535 
    536   web_ui()->CallJavascriptFunction(
    537       "AutofillEditAddressOverlay.loadAddressComponents", input);
    538 }
    539 
    540 void AutofillOptionsHandler::LoadCreditCardEditor(const base::ListValue* args) {
    541   DCHECK(IsPersonalDataLoaded());
    542 
    543   std::string guid;
    544   if (!args->GetString(0, &guid)) {
    545     NOTREACHED();
    546     return;
    547   }
    548 
    549   CreditCard* credit_card = personal_data_->GetCreditCardByGUID(guid);
    550   if (!credit_card) {
    551     // There is a race where a user can click once on the close button and
    552     // quickly click again on the list item before the item is removed (since
    553     // the list is not updated until the model tells the list an item has been
    554     // removed). This will activate the editor for a profile that has been
    555     // removed. Do nothing in that case.
    556     return;
    557   }
    558 
    559   base::DictionaryValue credit_card_data;
    560   credit_card_data.SetString("guid", credit_card->guid());
    561   credit_card_data.SetString(
    562       "nameOnCard",
    563       credit_card->GetRawInfo(autofill::CREDIT_CARD_NAME));
    564   credit_card_data.SetString(
    565       "creditCardNumber",
    566       credit_card->GetRawInfo(autofill::CREDIT_CARD_NUMBER));
    567   credit_card_data.SetString(
    568       "expirationMonth",
    569       credit_card->GetRawInfo(autofill::CREDIT_CARD_EXP_MONTH));
    570   credit_card_data.SetString(
    571       "expirationYear",
    572       credit_card->GetRawInfo(autofill::CREDIT_CARD_EXP_4_DIGIT_YEAR));
    573 
    574   web_ui()->CallJavascriptFunction("AutofillOptions.editCreditCard",
    575                                    credit_card_data);
    576 }
    577 
    578 void AutofillOptionsHandler::SetAddress(const base::ListValue* args) {
    579   if (!IsPersonalDataLoaded())
    580     return;
    581 
    582   int arg_counter = 0;
    583   std::string guid;
    584   if (!args->GetString(arg_counter++, &guid)) {
    585     NOTREACHED();
    586     return;
    587   }
    588 
    589   AutofillProfile profile(guid, kSettingsOrigin);
    590 
    591   base::string16 value;
    592   const base::ListValue* list_value;
    593   if (args->GetList(arg_counter++, &list_value))
    594     SetValueList(list_value, autofill::NAME_FULL, &profile);
    595 
    596   if (args->GetString(arg_counter++, &value))
    597     profile.SetRawInfo(autofill::COMPANY_NAME, value);
    598 
    599   if (args->GetString(arg_counter++, &value))
    600     profile.SetRawInfo(autofill::ADDRESS_HOME_STREET_ADDRESS, value);
    601 
    602   if (args->GetString(arg_counter++, &value))
    603     profile.SetRawInfo(autofill::ADDRESS_HOME_DEPENDENT_LOCALITY, value);
    604 
    605   if (args->GetString(arg_counter++, &value))
    606     profile.SetRawInfo(autofill::ADDRESS_HOME_CITY, value);
    607 
    608   if (args->GetString(arg_counter++, &value))
    609     profile.SetRawInfo(autofill::ADDRESS_HOME_STATE, value);
    610 
    611   if (args->GetString(arg_counter++, &value))
    612     profile.SetRawInfo(autofill::ADDRESS_HOME_ZIP, value);
    613 
    614   if (args->GetString(arg_counter++, &value))
    615     profile.SetRawInfo(autofill::ADDRESS_HOME_SORTING_CODE, value);
    616 
    617   if (args->GetString(arg_counter++, &value))
    618     profile.SetRawInfo(autofill::ADDRESS_HOME_COUNTRY, value);
    619 
    620   if (args->GetList(arg_counter++, &list_value))
    621     SetValueList(list_value, autofill::PHONE_HOME_WHOLE_NUMBER, &profile);
    622 
    623   if (args->GetList(arg_counter++, &list_value))
    624     SetValueList(list_value, autofill::EMAIL_ADDRESS, &profile);
    625 
    626   if (args->GetString(arg_counter++, &value))
    627     profile.set_language_code(base::UTF16ToUTF8(value));
    628 
    629   if (!base::IsValidGUID(profile.guid())) {
    630     profile.set_guid(base::GenerateGUID());
    631     personal_data_->AddProfile(profile);
    632   } else {
    633     personal_data_->UpdateProfile(profile);
    634   }
    635 }
    636 
    637 void AutofillOptionsHandler::SetCreditCard(const base::ListValue* args) {
    638   if (!IsPersonalDataLoaded())
    639     return;
    640 
    641   std::string guid;
    642   if (!args->GetString(0, &guid)) {
    643     NOTREACHED();
    644     return;
    645   }
    646 
    647   CreditCard credit_card(guid, kSettingsOrigin);
    648 
    649   base::string16 value;
    650   if (args->GetString(1, &value))
    651     credit_card.SetRawInfo(autofill::CREDIT_CARD_NAME, value);
    652 
    653   if (args->GetString(2, &value))
    654     credit_card.SetRawInfo(autofill::CREDIT_CARD_NUMBER, value);
    655 
    656   if (args->GetString(3, &value))
    657     credit_card.SetRawInfo(autofill::CREDIT_CARD_EXP_MONTH, value);
    658 
    659   if (args->GetString(4, &value))
    660     credit_card.SetRawInfo(autofill::CREDIT_CARD_EXP_4_DIGIT_YEAR, value);
    661 
    662   if (!base::IsValidGUID(credit_card.guid())) {
    663     credit_card.set_guid(base::GenerateGUID());
    664     personal_data_->AddCreditCard(credit_card);
    665   } else {
    666     personal_data_->UpdateCreditCard(credit_card);
    667   }
    668 }
    669 
    670 void AutofillOptionsHandler::ValidatePhoneNumbers(const base::ListValue* args) {
    671   if (!IsPersonalDataLoaded())
    672     return;
    673 
    674   scoped_ptr<base::ListValue> list_value = ValidatePhoneArguments(args);
    675 
    676   web_ui()->CallJavascriptFunction(
    677     "AutofillEditAddressOverlay.setValidatedPhoneNumbers", *list_value);
    678 }
    679 
    680 bool AutofillOptionsHandler::IsPersonalDataLoaded() const {
    681   return personal_data_ && personal_data_->IsDataLoaded();
    682 }
    683 
    684 }  // namespace options
    685