blob: e7ab050227ca3942056d508478e605e6026fc911 [file] [log] [blame]
// 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_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;
}
base::string16 phone_number;
if (!dictionary.GetString("phone_number", &phone_number))
DVLOG(1) << "Response from Google Wallet missing phone number";
base::string16 address_line_1;
base::string16 address_line_2;
const ListValue* address_line_list;
if (dictionary.GetList("postal_address.address_line", &address_line_list)) {
if (!address_line_list->GetString(0, &address_line_1))
DVLOG(1) << "Response from Google Wallet missing address line 1";
if (!address_line_list->GetString(1, &address_line_2))
DVLOG(1) << "Response from Google Wallet missing address line 2";
} 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 administrative_area_name;
if (!dictionary.GetString("postal_address.administrative_area_name",
&administrative_area_name)) {
DVLOG(1) << "Response from Google Wallet missing administrative area name";
}
Address* address = new Address(country_name_code,
recipient_name,
address_line_1,
address_line_2,
locality_name,
administrative_area_name,
postal_code_number,
phone_number,
object_id);
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_(
UTF16ToASCII(profile.GetRawInfo(ADDRESS_HOME_COUNTRY))),
recipient_name_(profile.GetRawInfo(NAME_FULL)),
address_line_1_(profile.GetRawInfo(ADDRESS_HOME_LINE1)),
address_line_2_(profile.GetRawInfo(ADDRESS_HOME_LINE2)),
locality_name_(profile.GetRawInfo(ADDRESS_HOME_CITY)),
postal_code_number_(profile.GetRawInfo(ADDRESS_HOME_ZIP)),
phone_number_(profile.GetRawInfo(PHONE_HOME_WHOLE_NUMBER)),
is_complete_address_(true) {
state_names::GetNameAndAbbreviation(profile.GetRawInfo(ADDRESS_HOME_STATE),
NULL,
&administrative_area_name_);
StringToUpperASCII(&administrative_area_name_);
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 base::string16& address_line_1,
const base::string16& address_line_2,
const base::string16& locality_name,
const base::string16& administrative_area_name,
const base::string16& postal_code_number,
const base::string16& phone_number,
const std::string& object_id)
: country_name_code_(country_name_code),
recipient_name_(recipient_name),
address_line_1_(address_line_1),
address_line_2_(address_line_2),
locality_name_(locality_name),
administrative_area_name_(administrative_area_name),
postal_code_number_(postal_code_number),
phone_number_(phone_number),
phone_object_(phone_number, country_name_code),
object_id_(object_id),
is_complete_address_(true) {}
Address::~Address() {}
// static
scoped_ptr<Address> 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<Address>();
}
return scoped_ptr<Address>(CreateAddressInternal(dictionary, object_id));
}
// static
scoped_ptr<Address> Address::CreateAddress(
const base::DictionaryValue& dictionary) {
std::string object_id;
dictionary.GetString("id", &object_id);
return scoped_ptr<Address>(CreateAddressInternal(dictionary, object_id));
}
// static
scoped_ptr<Address> 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<Address>();
}
base::string16 name;
if (!dictionary.GetString("name", &name)) {
DLOG(ERROR) << "Reponse from Google Wallet missing name";
return scoped_ptr<Address>();
}
base::string16 postal_code;
if (!dictionary.GetString("postal_code", &postal_code)) {
DLOG(ERROR) << "Reponse from Google Wallet missing postal code";
return scoped_ptr<Address>();
}
base::string16 address1;
if (!dictionary.GetString("address1", &address1))
DVLOG(1) << "Reponse from Google Wallet missing address1";
base::string16 address2;
if (!dictionary.GetString("address2", &address2))
DVLOG(1) << "Reponse from Google Wallet missing address2";
base::string16 city;
if (!dictionary.GetString("city", &city))
DVLOG(1) << "Reponse from Google Wallet missing city";
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";
scoped_ptr<Address> address(
new Address(country_code,
name,
address1,
address2,
city,
state,
postal_code,
phone_number,
std::string()));
address->set_is_complete_address(address_state == kFullAddress);
return address.Pass();
}
scoped_ptr<base::DictionaryValue> Address::ToDictionaryWithID() const {
scoped_ptr<base::DictionaryValue> 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<base::DictionaryValue> Address::ToDictionaryWithoutID() const {
scoped_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
scoped_ptr<base::ListValue> address_lines(new base::ListValue());
address_lines->AppendString(address_line_1_);
if (!address_line_2_.empty())
address_lines->AppendString(address_line_2_);
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("administrative_area_name",
administrative_area_name_);
dict->SetString("postal_code_number", postal_code_number_);
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() + ASCIIToUTF16(", ") + address_line_1();
#endif
}
base::string16 Address::DisplayNameDetail() const {
#if defined(OS_ANDROID)
// TODO(aruslan): improve this stub implementation.
return address_line_1();
#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(IsStringASCII(country_name_code()));
return ASCIIToUTF16(country_name_code());
} else if (type.html_type() == HTML_TYPE_STREET_ADDRESS) {
base::string16 address = address_line_1();
if (!address_line_2().empty())
address += ASCIIToUTF16(", ") + address_line_2();
return address;
}
switch (type.GetStorableType()) {
case NAME_FULL:
return recipient_name();
case ADDRESS_HOME_LINE1:
return address_line_1();
case ADDRESS_HOME_LINE2:
return address_line_2();
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:
case ADDRESS_HOME_SORTING_CODE:
case COMPANY_NAME:
// Fields that some countries request but Wallet doesn't support.
// TODO(dbeam): can these be supported by Wallet?
return base::string16();
// TODO(estade): implement more.
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_ &&
address_line_1_ == other.address_line_1_ &&
address_line_2_ == other.address_line_2_ &&
locality_name_ == other.locality_name_ &&
administrative_area_name_ == other.administrative_area_name_ &&
postal_code_number_ == other.postal_code_number_ &&
phone_number_ == other.phone_number_ &&
is_complete_address_ == other.is_complete_address_;
}
bool Address::operator==(const Address& other) const {
return object_id_ == other.object_id_ && EqualsIgnoreID(other);
}
bool Address::operator!=(const Address& other) const {
return !(*this == other);
}
} // namespace wallet
} // namespace autofill