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