Home | History | Annotate | Download | only in wallet
      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 "components/autofill/content/browser/wallet/wallet_address.h"
      6 
      7 #include "base/logging.h"
      8 #include "base/strings/string_split.h"
      9 #include "base/strings/string_util.h"
     10 #include "base/strings/utf_string_conversions.h"
     11 #include "base/values.h"
     12 #include "components/autofill/core/browser/autofill_country.h"
     13 #include "components/autofill/core/browser/autofill_profile.h"
     14 #include "components/autofill/core/browser/autofill_type.h"
     15 #include "components/autofill/core/browser/phone_number.h"
     16 #include "components/autofill/core/browser/state_names.h"
     17 
     18 namespace autofill {
     19 namespace wallet {
     20 
     21 // Server specified type for address with complete details.
     22 const char kFullAddress[] = "FULL";
     23 
     24 namespace {
     25 
     26 Address* CreateAddressInternal(const base::DictionaryValue& dictionary,
     27                                const std::string& object_id) {
     28   std::string country_name_code;
     29   if (!dictionary.GetString("postal_address.country_name_code",
     30                             &country_name_code)) {
     31     DLOG(ERROR) << "Response from Google Wallet missing country name";
     32     return NULL;
     33   }
     34 
     35   base::string16 recipient_name;
     36   if (!dictionary.GetString("postal_address.recipient_name",
     37                             &recipient_name)) {
     38     DLOG(ERROR) << "Response from Google Wallet missing recipient name";
     39     return NULL;
     40   }
     41 
     42   base::string16 postal_code_number;
     43   if (!dictionary.GetString("postal_address.postal_code_number",
     44                             &postal_code_number)) {
     45     DLOG(ERROR) << "Response from Google Wallet missing postal code number";
     46     return NULL;
     47   }
     48   // TODO(estade): what about postal_code_number_extension?
     49 
     50   base::string16 sorting_code;
     51   if (!dictionary.GetString("postal_address.sorting_code",
     52                             &sorting_code)) {
     53     DVLOG(1) << "Response from Google Wallet missing sorting code";
     54   }
     55 
     56   base::string16 phone_number;
     57   if (!dictionary.GetString("phone_number", &phone_number))
     58     DVLOG(1) << "Response from Google Wallet missing phone number";
     59 
     60   std::vector<base::string16> street_address;
     61   const base::ListValue* address_line_list;
     62   if (dictionary.GetList("postal_address.address_line", &address_line_list)) {
     63     for (size_t i = 0; i < address_line_list->GetSize(); ++i) {
     64       base::string16 line;
     65       address_line_list->GetString(i, &line);
     66       street_address.push_back(line);
     67     }
     68   } else {
     69     DVLOG(1) << "Response from Google Wallet missing address lines";
     70   }
     71 
     72   base::string16 locality_name;
     73   if (!dictionary.GetString("postal_address.locality_name",
     74                             &locality_name)) {
     75     DVLOG(1) << "Response from Google Wallet missing locality name";
     76   }
     77 
     78   base::string16 dependent_locality_name;
     79   if (!dictionary.GetString("postal_address.dependent_locality_name",
     80                             &dependent_locality_name)) {
     81     DVLOG(1) << "Response from Google Wallet missing dependent locality name";
     82   }
     83 
     84   base::string16 administrative_area_name;
     85   if (!dictionary.GetString("postal_address.administrative_area_name",
     86                             &administrative_area_name)) {
     87     DVLOG(1) << "Response from Google Wallet missing administrative area name";
     88   }
     89 
     90   std::string language_code;
     91   if (!dictionary.GetString("postal_address.language_code",
     92                             &language_code)) {
     93     DVLOG(1) << "Response from Google Wallet missing language code";
     94   }
     95 
     96   Address* address = new Address(country_name_code,
     97                                  recipient_name,
     98                                  street_address,
     99                                  locality_name,
    100                                  dependent_locality_name,
    101                                  administrative_area_name,
    102                                  postal_code_number,
    103                                  sorting_code,
    104                                  phone_number,
    105                                  object_id,
    106                                  language_code);
    107 
    108   bool is_minimal_address = false;
    109   if (dictionary.GetBoolean("is_minimal_address", &is_minimal_address))
    110     address->set_is_complete_address(!is_minimal_address);
    111   else
    112     DVLOG(1) << "Response from Google Wallet missing is_minimal_address bit";
    113 
    114   return address;
    115 }
    116 
    117 }  // namespace
    118 
    119 Address::Address() {}
    120 
    121 Address::Address(const AutofillProfile& profile)
    122     : country_name_code_(
    123           base::UTF16ToASCII(profile.GetRawInfo(ADDRESS_HOME_COUNTRY))),
    124       recipient_name_(profile.GetRawInfo(NAME_FULL)),
    125       locality_name_(profile.GetRawInfo(ADDRESS_HOME_CITY)),
    126       dependent_locality_name_(
    127           profile.GetRawInfo(ADDRESS_HOME_DEPENDENT_LOCALITY)),
    128       administrative_area_name_(profile.GetRawInfo(ADDRESS_HOME_STATE)),
    129       postal_code_number_(profile.GetRawInfo(ADDRESS_HOME_ZIP)),
    130       sorting_code_(profile.GetRawInfo(ADDRESS_HOME_SORTING_CODE)),
    131       phone_number_(profile.GetRawInfo(PHONE_HOME_WHOLE_NUMBER)),
    132       is_complete_address_(true),
    133       language_code_(profile.language_code()) {
    134   base::SplitString(
    135       profile.GetRawInfo(ADDRESS_HOME_STREET_ADDRESS), '\n', &street_address_);
    136 
    137   if (!country_name_code_.empty())
    138     phone_object_ = i18n::PhoneObject(phone_number_, country_name_code_);
    139 }
    140 
    141 Address::Address(const std::string& country_name_code,
    142                  const base::string16& recipient_name,
    143                  const std::vector<base::string16>& street_address,
    144                  const base::string16& locality_name,
    145                  const base::string16& dependent_locality_name,
    146                  const base::string16& administrative_area_name,
    147                  const base::string16& postal_code_number,
    148                  const base::string16& sorting_code,
    149                  const base::string16& phone_number,
    150                  const std::string& object_id,
    151                  const std::string& language_code)
    152     : country_name_code_(country_name_code),
    153       recipient_name_(recipient_name),
    154       street_address_(street_address),
    155       locality_name_(locality_name),
    156       dependent_locality_name_(dependent_locality_name),
    157       administrative_area_name_(administrative_area_name),
    158       postal_code_number_(postal_code_number),
    159       sorting_code_(sorting_code),
    160       phone_number_(phone_number),
    161       phone_object_(phone_number, country_name_code),
    162       object_id_(object_id),
    163       is_complete_address_(true),
    164       language_code_(language_code) {}
    165 
    166 Address::~Address() {}
    167 
    168 // static
    169 scoped_ptr<Address> Address::CreateAddressWithID(
    170     const base::DictionaryValue& dictionary) {
    171   std::string object_id;
    172   if (!dictionary.GetString("id", &object_id)) {
    173     DLOG(ERROR) << "Response from Google Wallet missing object id";
    174     return scoped_ptr<Address>();
    175   }
    176   return scoped_ptr<Address>(CreateAddressInternal(dictionary, object_id));
    177 }
    178 
    179 // static
    180 scoped_ptr<Address> Address::CreateAddress(
    181     const base::DictionaryValue& dictionary) {
    182   std::string object_id;
    183   dictionary.GetString("id", &object_id);
    184   return scoped_ptr<Address>(CreateAddressInternal(dictionary, object_id));
    185 }
    186 
    187 // static
    188 scoped_ptr<Address> Address::CreateDisplayAddress(
    189     const base::DictionaryValue& dictionary) {
    190   std::string country_code;
    191   if (!dictionary.GetString("country_code", &country_code)) {
    192     DLOG(ERROR) << "Reponse from Google Wallet missing country code";
    193     return scoped_ptr<Address>();
    194   }
    195 
    196   base::string16 name;
    197   if (!dictionary.GetString("name", &name)) {
    198     DLOG(ERROR) << "Reponse from Google Wallet missing name";
    199     return scoped_ptr<Address>();
    200   }
    201 
    202   base::string16 postal_code;
    203   if (!dictionary.GetString("postal_code", &postal_code)) {
    204     DLOG(ERROR) << "Reponse from Google Wallet missing postal code";
    205     return scoped_ptr<Address>();
    206   }
    207 
    208   base::string16 sorting_code;
    209   if (!dictionary.GetString("sorting_code", &sorting_code)) {
    210     DVLOG(1) << "Reponse from Google Wallet missing sorting code";
    211   }
    212 
    213   std::vector<base::string16> street_address;
    214   base::string16 address1;
    215   if (dictionary.GetString("address1", &address1))
    216     street_address.push_back(address1);
    217   else
    218     DVLOG(1) << "Reponse from Google Wallet missing address1";
    219 
    220   base::string16 address2;
    221   if (dictionary.GetString("address2", &address2) && !address2.empty()) {
    222     street_address.resize(2);
    223     street_address[1] = address2;
    224   } else {
    225     DVLOG(1) << "Reponse from Google Wallet missing or empty address2";
    226   }
    227 
    228   base::string16 city;
    229   if (!dictionary.GetString("city", &city))
    230     DVLOG(1) << "Reponse from Google Wallet missing city";
    231 
    232   base::string16 dependent_locality_name;
    233   if (!dictionary.GetString("dependent_locality_name",
    234                             &dependent_locality_name)) {
    235     DVLOG(1) << "Reponse from Google Wallet missing district";
    236   }
    237 
    238   base::string16 state;
    239   if (!dictionary.GetString("state", &state))
    240     DVLOG(1) << "Reponse from Google Wallet missing state";
    241 
    242   base::string16 phone_number;
    243   if (!dictionary.GetString("phone_number", &phone_number))
    244     DVLOG(1) << "Reponse from Google Wallet missing phone number";
    245 
    246   std::string address_state;
    247   if (!dictionary.GetString("type", &address_state))
    248     DVLOG(1) << "Response from Google Wallet missing type/state of address";
    249 
    250   std::string language_code;
    251   if (!dictionary.GetString("language_code", &language_code))
    252     DVLOG(1) << "Response from Google Wallet missing language code";
    253 
    254   scoped_ptr<Address> address(
    255       new Address(country_code,
    256                   name,
    257                   street_address,
    258                   city,
    259                   dependent_locality_name,
    260                   state,
    261                   postal_code,
    262                   sorting_code,
    263                   phone_number,
    264                   std::string(),
    265                   language_code));
    266   address->set_is_complete_address(address_state == kFullAddress);
    267 
    268   return address.Pass();
    269 }
    270 
    271 scoped_ptr<base::DictionaryValue> Address::ToDictionaryWithID() const {
    272   scoped_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
    273 
    274   if (!object_id_.empty())
    275     dict->SetString("id", object_id_);
    276   dict->SetString("phone_number", phone_number_);
    277   dict->Set("postal_address", ToDictionaryWithoutID().release());
    278 
    279   return dict.Pass();
    280 }
    281 
    282 scoped_ptr<base::DictionaryValue> Address::ToDictionaryWithoutID() const {
    283   scoped_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
    284 
    285   scoped_ptr<base::ListValue> address_lines(new base::ListValue());
    286   address_lines->AppendStrings(street_address_);
    287   dict->Set("address_line", address_lines.release());
    288 
    289   dict->SetString("country_name_code", country_name_code_);
    290   dict->SetString("recipient_name", recipient_name_);
    291   dict->SetString("locality_name", locality_name_);
    292   dict->SetString("dependent_locality_name", dependent_locality_name_);
    293   dict->SetString("administrative_area_name",
    294                   administrative_area_name_);
    295   dict->SetString("postal_code_number", postal_code_number_);
    296   dict->SetString("sorting_code", sorting_code_);
    297   dict->SetString("language_code", language_code_);
    298 
    299   return dict.Pass();
    300 }
    301 
    302 base::string16 Address::DisplayName() const {
    303 #if defined(OS_ANDROID)
    304   // TODO(aruslan): improve this stub implementation.
    305   return recipient_name();
    306 #else
    307   // TODO(estade): improve this stub implementation + l10n.
    308   return recipient_name() + base::ASCIIToUTF16(", ") + GetStreetAddressLine(0);
    309 #endif
    310 }
    311 
    312 base::string16 Address::DisplayNameDetail() const {
    313 #if defined(OS_ANDROID)
    314   // TODO(aruslan): improve this stub implementation.
    315   return GetStreetAddressLine(0);
    316 #else
    317   return base::string16();
    318 #endif
    319 }
    320 
    321 base::string16 Address::DisplayPhoneNumber() const {
    322   // Return a formatted phone number. Wallet doesn't store user formatting, so
    323   // impose our own. phone_number() always includes a country code, so using
    324   // PhoneObject to format it would result in an internationalized format. Since
    325   // Wallet only supports the US right now, stick to national formatting.
    326   return i18n::PhoneObject(phone_number(), country_name_code()).
    327       GetNationallyFormattedNumber();
    328 }
    329 
    330 base::string16 Address::GetInfo(const AutofillType& type,
    331                                 const std::string& app_locale) const {
    332   if (type.html_type() == HTML_TYPE_COUNTRY_CODE) {
    333     DCHECK(base::IsStringASCII(country_name_code()));
    334     return base::ASCIIToUTF16(country_name_code());
    335   }
    336 
    337   switch (type.GetStorableType()) {
    338     case NAME_FULL:
    339       return recipient_name();
    340 
    341     case ADDRESS_HOME_STREET_ADDRESS:
    342       return JoinString(street_address_, base::ASCIIToUTF16("\n"));
    343 
    344     case ADDRESS_HOME_LINE1:
    345       return GetStreetAddressLine(0);
    346 
    347     case ADDRESS_HOME_LINE2:
    348       return GetStreetAddressLine(1);
    349 
    350     case ADDRESS_HOME_CITY:
    351       return locality_name();
    352 
    353     case ADDRESS_HOME_STATE:
    354       return administrative_area_name();
    355 
    356     case ADDRESS_HOME_ZIP:
    357       return postal_code_number();
    358 
    359     case ADDRESS_HOME_COUNTRY: {
    360       AutofillCountry country(country_name_code(), app_locale);
    361       return country.name();
    362     }
    363 
    364     case PHONE_HOME_WHOLE_NUMBER:
    365       // Wallet doesn't store user phone number formatting, so just strip all
    366       // formatting.
    367       return phone_object_.GetWholeNumber();
    368 
    369     case ADDRESS_HOME_DEPENDENT_LOCALITY:
    370       return dependent_locality_name_;
    371 
    372     case ADDRESS_HOME_SORTING_CODE:
    373       return sorting_code_;
    374 
    375     case COMPANY_NAME:
    376       // A field that Wallet doesn't support. TODO(dbeam): can it be supported?
    377       return base::string16();
    378 
    379     default:
    380       NOTREACHED();
    381       return base::string16();
    382   }
    383 }
    384 
    385 void Address::SetPhoneNumber(const base::string16& phone_number) {
    386   phone_number_ = phone_number;
    387   phone_object_ = i18n::PhoneObject(phone_number_, country_name_code_);
    388 }
    389 
    390 bool Address::EqualsIgnoreID(const Address& other) const {
    391   return country_name_code_ == other.country_name_code_ &&
    392          recipient_name_ == other.recipient_name_ &&
    393          street_address_ == other.street_address_ &&
    394          locality_name_ == other.locality_name_ &&
    395          dependent_locality_name_ == other.dependent_locality_name_ &&
    396          administrative_area_name_ == other.administrative_area_name_ &&
    397          postal_code_number_ == other.postal_code_number_ &&
    398          sorting_code_ == other.sorting_code_ &&
    399          phone_number_ == other.phone_number_ &&
    400          is_complete_address_ == other.is_complete_address_;
    401 }
    402 
    403 base::string16 Address::GetStreetAddressLine(size_t line) const {
    404   return street_address_.size() > line ? street_address_[line] :
    405                                          base::string16();
    406 }
    407 
    408 bool Address::operator==(const Address& other) const {
    409   return object_id_ == other.object_id_ &&
    410          language_code_ == other.language_code_ &&
    411          EqualsIgnoreID(other);
    412 }
    413 
    414 bool Address::operator!=(const Address& other) const {
    415   return !(*this == other);
    416 }
    417 
    418 }  // namespace wallet
    419 }  // namespace autofill
    420