// Copyright 2013 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "components/autofill/content/browser/wallet/wallet_address.h" #include "base/logging.h" #include "base/strings/string_split.h" #include "base/strings/string_util.h" #include "base/strings/utf_string_conversions.h" #include "base/values.h" #include "components/autofill/core/browser/autofill_country.h" #include "components/autofill/core/browser/autofill_profile.h" #include "components/autofill/core/browser/autofill_type.h" #include "components/autofill/core/browser/phone_number.h" #include "components/autofill/core/browser/state_names.h" namespace autofill { namespace wallet { // Server specified type for address with complete details. const char kFullAddress[] = "FULL"; namespace { Address* CreateAddressInternal(const base::DictionaryValue& dictionary, const std::string& object_id) { std::string country_name_code; if (!dictionary.GetString("postal_address.country_name_code", &country_name_code)) { DLOG(ERROR) << "Response from Google Wallet missing country name"; return NULL; } base::string16 recipient_name; if (!dictionary.GetString("postal_address.recipient_name", &recipient_name)) { DLOG(ERROR) << "Response from Google Wallet missing recipient name"; return NULL; } base::string16 postal_code_number; if (!dictionary.GetString("postal_address.postal_code_number", &postal_code_number)) { DLOG(ERROR) << "Response from Google Wallet missing postal code number"; return NULL; } // TODO(estade): what about postal_code_number_extension? base::string16 sorting_code; if (!dictionary.GetString("postal_address.sorting_code", &sorting_code)) { DVLOG(1) << "Response from Google Wallet missing sorting code"; } base::string16 phone_number; if (!dictionary.GetString("phone_number", &phone_number)) DVLOG(1) << "Response from Google Wallet missing phone number"; std::vector street_address; const base::ListValue* address_line_list; if (dictionary.GetList("postal_address.address_line", &address_line_list)) { for (size_t i = 0; i < address_line_list->GetSize(); ++i) { base::string16 line; address_line_list->GetString(i, &line); street_address.push_back(line); } } else { DVLOG(1) << "Response from Google Wallet missing address lines"; } base::string16 locality_name; if (!dictionary.GetString("postal_address.locality_name", &locality_name)) { DVLOG(1) << "Response from Google Wallet missing locality name"; } base::string16 dependent_locality_name; if (!dictionary.GetString("postal_address.dependent_locality_name", &dependent_locality_name)) { DVLOG(1) << "Response from Google Wallet missing dependent locality name"; } base::string16 administrative_area_name; if (!dictionary.GetString("postal_address.administrative_area_name", &administrative_area_name)) { DVLOG(1) << "Response from Google Wallet missing administrative area name"; } std::string language_code; if (!dictionary.GetString("postal_address.language_code", &language_code)) { DVLOG(1) << "Response from Google Wallet missing language code"; } Address* address = new Address(country_name_code, recipient_name, street_address, locality_name, dependent_locality_name, administrative_area_name, postal_code_number, sorting_code, phone_number, object_id, language_code); bool is_minimal_address = false; if (dictionary.GetBoolean("is_minimal_address", &is_minimal_address)) address->set_is_complete_address(!is_minimal_address); else DVLOG(1) << "Response from Google Wallet missing is_minimal_address bit"; return address; } } // namespace Address::Address() {} Address::Address(const AutofillProfile& profile) : country_name_code_( base::UTF16ToASCII(profile.GetRawInfo(ADDRESS_HOME_COUNTRY))), recipient_name_(profile.GetRawInfo(NAME_FULL)), locality_name_(profile.GetRawInfo(ADDRESS_HOME_CITY)), dependent_locality_name_( profile.GetRawInfo(ADDRESS_HOME_DEPENDENT_LOCALITY)), administrative_area_name_(profile.GetRawInfo(ADDRESS_HOME_STATE)), postal_code_number_(profile.GetRawInfo(ADDRESS_HOME_ZIP)), sorting_code_(profile.GetRawInfo(ADDRESS_HOME_SORTING_CODE)), phone_number_(profile.GetRawInfo(PHONE_HOME_WHOLE_NUMBER)), is_complete_address_(true), language_code_(profile.language_code()) { base::SplitString( profile.GetRawInfo(ADDRESS_HOME_STREET_ADDRESS), '\n', &street_address_); if (!country_name_code_.empty()) phone_object_ = i18n::PhoneObject(phone_number_, country_name_code_); } Address::Address(const std::string& country_name_code, const base::string16& recipient_name, const std::vector& street_address, const base::string16& locality_name, const base::string16& dependent_locality_name, const base::string16& administrative_area_name, const base::string16& postal_code_number, const base::string16& sorting_code, const base::string16& phone_number, const std::string& object_id, const std::string& language_code) : country_name_code_(country_name_code), recipient_name_(recipient_name), street_address_(street_address), locality_name_(locality_name), dependent_locality_name_(dependent_locality_name), administrative_area_name_(administrative_area_name), postal_code_number_(postal_code_number), sorting_code_(sorting_code), phone_number_(phone_number), phone_object_(phone_number, country_name_code), object_id_(object_id), is_complete_address_(true), language_code_(language_code) {} Address::~Address() {} // static scoped_ptr
Address::CreateAddressWithID( const base::DictionaryValue& dictionary) { std::string object_id; if (!dictionary.GetString("id", &object_id)) { DLOG(ERROR) << "Response from Google Wallet missing object id"; return scoped_ptr
(); } return scoped_ptr
(CreateAddressInternal(dictionary, object_id)); } // static scoped_ptr
Address::CreateAddress( const base::DictionaryValue& dictionary) { std::string object_id; dictionary.GetString("id", &object_id); return scoped_ptr
(CreateAddressInternal(dictionary, object_id)); } // static scoped_ptr
Address::CreateDisplayAddress( const base::DictionaryValue& dictionary) { std::string country_code; if (!dictionary.GetString("country_code", &country_code)) { DLOG(ERROR) << "Reponse from Google Wallet missing country code"; return scoped_ptr
(); } base::string16 name; if (!dictionary.GetString("name", &name)) { DLOG(ERROR) << "Reponse from Google Wallet missing name"; return scoped_ptr
(); } base::string16 postal_code; if (!dictionary.GetString("postal_code", &postal_code)) { DLOG(ERROR) << "Reponse from Google Wallet missing postal code"; return scoped_ptr
(); } base::string16 sorting_code; if (!dictionary.GetString("sorting_code", &sorting_code)) { DVLOG(1) << "Reponse from Google Wallet missing sorting code"; } std::vector street_address; base::string16 address1; if (dictionary.GetString("address1", &address1)) street_address.push_back(address1); else DVLOG(1) << "Reponse from Google Wallet missing address1"; base::string16 address2; if (dictionary.GetString("address2", &address2) && !address2.empty()) { street_address.resize(2); street_address[1] = address2; } else { DVLOG(1) << "Reponse from Google Wallet missing or empty address2"; } base::string16 city; if (!dictionary.GetString("city", &city)) DVLOG(1) << "Reponse from Google Wallet missing city"; base::string16 dependent_locality_name; if (!dictionary.GetString("dependent_locality_name", &dependent_locality_name)) { DVLOG(1) << "Reponse from Google Wallet missing district"; } base::string16 state; if (!dictionary.GetString("state", &state)) DVLOG(1) << "Reponse from Google Wallet missing state"; base::string16 phone_number; if (!dictionary.GetString("phone_number", &phone_number)) DVLOG(1) << "Reponse from Google Wallet missing phone number"; std::string address_state; if (!dictionary.GetString("type", &address_state)) DVLOG(1) << "Response from Google Wallet missing type/state of address"; std::string language_code; if (!dictionary.GetString("language_code", &language_code)) DVLOG(1) << "Response from Google Wallet missing language code"; scoped_ptr
address( new Address(country_code, name, street_address, city, dependent_locality_name, state, postal_code, sorting_code, phone_number, std::string(), language_code)); address->set_is_complete_address(address_state == kFullAddress); return address.Pass(); } scoped_ptr Address::ToDictionaryWithID() const { scoped_ptr dict(new base::DictionaryValue()); if (!object_id_.empty()) dict->SetString("id", object_id_); dict->SetString("phone_number", phone_number_); dict->Set("postal_address", ToDictionaryWithoutID().release()); return dict.Pass(); } scoped_ptr Address::ToDictionaryWithoutID() const { scoped_ptr dict(new base::DictionaryValue()); scoped_ptr address_lines(new base::ListValue()); address_lines->AppendStrings(street_address_); dict->Set("address_line", address_lines.release()); dict->SetString("country_name_code", country_name_code_); dict->SetString("recipient_name", recipient_name_); dict->SetString("locality_name", locality_name_); dict->SetString("dependent_locality_name", dependent_locality_name_); dict->SetString("administrative_area_name", administrative_area_name_); dict->SetString("postal_code_number", postal_code_number_); dict->SetString("sorting_code", sorting_code_); dict->SetString("language_code", language_code_); return dict.Pass(); } base::string16 Address::DisplayName() const { #if defined(OS_ANDROID) // TODO(aruslan): improve this stub implementation. return recipient_name(); #else // TODO(estade): improve this stub implementation + l10n. return recipient_name() + base::ASCIIToUTF16(", ") + GetStreetAddressLine(0); #endif } base::string16 Address::DisplayNameDetail() const { #if defined(OS_ANDROID) // TODO(aruslan): improve this stub implementation. return GetStreetAddressLine(0); #else return base::string16(); #endif } base::string16 Address::DisplayPhoneNumber() const { // Return a formatted phone number. Wallet doesn't store user formatting, so // impose our own. phone_number() always includes a country code, so using // PhoneObject to format it would result in an internationalized format. Since // Wallet only supports the US right now, stick to national formatting. return i18n::PhoneObject(phone_number(), country_name_code()). GetNationallyFormattedNumber(); } base::string16 Address::GetInfo(const AutofillType& type, const std::string& app_locale) const { if (type.html_type() == HTML_TYPE_COUNTRY_CODE) { DCHECK(base::IsStringASCII(country_name_code())); return base::ASCIIToUTF16(country_name_code()); } switch (type.GetStorableType()) { case NAME_FULL: return recipient_name(); case ADDRESS_HOME_STREET_ADDRESS: return JoinString(street_address_, base::ASCIIToUTF16("\n")); case ADDRESS_HOME_LINE1: return GetStreetAddressLine(0); case ADDRESS_HOME_LINE2: return GetStreetAddressLine(1); case ADDRESS_HOME_CITY: return locality_name(); case ADDRESS_HOME_STATE: return administrative_area_name(); case ADDRESS_HOME_ZIP: return postal_code_number(); case ADDRESS_HOME_COUNTRY: { AutofillCountry country(country_name_code(), app_locale); return country.name(); } case PHONE_HOME_WHOLE_NUMBER: // Wallet doesn't store user phone number formatting, so just strip all // formatting. return phone_object_.GetWholeNumber(); case ADDRESS_HOME_DEPENDENT_LOCALITY: return dependent_locality_name_; case ADDRESS_HOME_SORTING_CODE: return sorting_code_; case COMPANY_NAME: // A field that Wallet doesn't support. TODO(dbeam): can it be supported? return base::string16(); default: NOTREACHED(); return base::string16(); } } void Address::SetPhoneNumber(const base::string16& phone_number) { phone_number_ = phone_number; phone_object_ = i18n::PhoneObject(phone_number_, country_name_code_); } bool Address::EqualsIgnoreID(const Address& other) const { return country_name_code_ == other.country_name_code_ && recipient_name_ == other.recipient_name_ && street_address_ == other.street_address_ && locality_name_ == other.locality_name_ && dependent_locality_name_ == other.dependent_locality_name_ && administrative_area_name_ == other.administrative_area_name_ && postal_code_number_ == other.postal_code_number_ && sorting_code_ == other.sorting_code_ && phone_number_ == other.phone_number_ && is_complete_address_ == other.is_complete_address_; } base::string16 Address::GetStreetAddressLine(size_t line) const { return street_address_.size() > line ? street_address_[line] : base::string16(); } bool Address::operator==(const Address& other) const { return object_id_ == other.object_id_ && language_code_ == other.language_code_ && EqualsIgnoreID(other); } bool Address::operator!=(const Address& other) const { return !(*this == other); } } // namespace wallet } // namespace autofill