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.
5 #include "components/autofill/content/browser/wallet/wallet_address.h"
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"
21 // Server specified type for address with complete details.
22 const char kFullAddress
[] = "FULL";
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";
35 base::string16 recipient_name
;
36 if (!dictionary
.GetString("postal_address.recipient_name",
38 DLOG(ERROR
) << "Response from Google Wallet missing recipient name";
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";
48 // TODO(estade): what about postal_code_number_extension?
50 base::string16 sorting_code
;
51 if (!dictionary
.GetString("postal_address.sorting_code",
53 DVLOG(1) << "Response from Google Wallet missing sorting code";
56 base::string16 phone_number
;
57 if (!dictionary
.GetString("phone_number", &phone_number
))
58 DVLOG(1) << "Response from Google Wallet missing phone number";
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
) {
65 address_line_list
->GetString(i
, &line
);
66 street_address
.push_back(line
);
69 DVLOG(1) << "Response from Google Wallet missing address lines";
72 base::string16 locality_name
;
73 if (!dictionary
.GetString("postal_address.locality_name",
75 DVLOG(1) << "Response from Google Wallet missing locality name";
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";
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";
90 std::string language_code
;
91 if (!dictionary
.GetString("postal_address.language_code",
93 DVLOG(1) << "Response from Google Wallet missing language code";
96 Address
* address
= new Address(country_name_code
,
100 dependent_locality_name
,
101 administrative_area_name
,
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
);
112 DVLOG(1) << "Response from Google Wallet missing is_minimal_address bit";
119 Address::Address() {}
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()) {
135 profile
.GetRawInfo(ADDRESS_HOME_STREET_ADDRESS
), '\n', &street_address_
);
137 if (!country_name_code_
.empty())
138 phone_object_
= i18n::PhoneObject(phone_number_
, country_name_code_
);
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
) {}
166 Address::~Address() {}
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
>();
176 return scoped_ptr
<Address
>(CreateAddressInternal(dictionary
, object_id
));
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
));
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
>();
197 if (!dictionary
.GetString("name", &name
)) {
198 DLOG(ERROR
) << "Reponse from Google Wallet missing name";
199 return scoped_ptr
<Address
>();
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
>();
208 base::string16 sorting_code
;
209 if (!dictionary
.GetString("sorting_code", &sorting_code
)) {
210 DVLOG(1) << "Reponse from Google Wallet missing sorting code";
213 std::vector
<base::string16
> street_address
;
214 base::string16 address1
;
215 if (dictionary
.GetString("address1", &address1
))
216 street_address
.push_back(address1
);
218 DVLOG(1) << "Reponse from Google Wallet missing address1";
220 base::string16 address2
;
221 if (dictionary
.GetString("address2", &address2
) && !address2
.empty()) {
222 street_address
.resize(2);
223 street_address
[1] = address2
;
225 DVLOG(1) << "Reponse from Google Wallet missing or empty address2";
229 if (!dictionary
.GetString("city", &city
))
230 DVLOG(1) << "Reponse from Google Wallet missing city";
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";
238 base::string16 state
;
239 if (!dictionary
.GetString("state", &state
))
240 DVLOG(1) << "Reponse from Google Wallet missing state";
242 base::string16 phone_number
;
243 if (!dictionary
.GetString("phone_number", &phone_number
))
244 DVLOG(1) << "Reponse from Google Wallet missing phone number";
246 std::string address_state
;
247 if (!dictionary
.GetString("type", &address_state
))
248 DVLOG(1) << "Response from Google Wallet missing type/state of address";
250 std::string language_code
;
251 if (!dictionary
.GetString("language_code", &language_code
))
252 DVLOG(1) << "Response from Google Wallet missing language code";
254 scoped_ptr
<Address
> address(
255 new Address(country_code
,
259 dependent_locality_name
,
266 address
->set_is_complete_address(address_state
== kFullAddress
);
268 return address
.Pass();
271 scoped_ptr
<base::DictionaryValue
> Address::ToDictionaryWithID() const {
272 scoped_ptr
<base::DictionaryValue
> dict(new base::DictionaryValue());
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());
282 scoped_ptr
<base::DictionaryValue
> Address::ToDictionaryWithoutID() const {
283 scoped_ptr
<base::DictionaryValue
> dict(new base::DictionaryValue());
285 scoped_ptr
<base::ListValue
> address_lines(new base::ListValue());
286 address_lines
->AppendStrings(street_address_
);
287 dict
->Set("address_line", address_lines
.release());
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_
);
302 base::string16
Address::DisplayName() const {
303 #if defined(OS_ANDROID)
304 // TODO(aruslan): improve this stub implementation.
305 return recipient_name();
307 // TODO(estade): improve this stub implementation + l10n.
308 return recipient_name() + base::ASCIIToUTF16(", ") + GetStreetAddressLine(0);
312 base::string16
Address::DisplayNameDetail() const {
313 #if defined(OS_ANDROID)
314 // TODO(aruslan): improve this stub implementation.
315 return GetStreetAddressLine(0);
317 return base::string16();
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();
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());
337 switch (type
.GetStorableType()) {
339 return recipient_name();
341 case ADDRESS_HOME_STREET_ADDRESS
:
342 return JoinString(street_address_
, base::ASCIIToUTF16("\n"));
344 case ADDRESS_HOME_LINE1
:
345 return GetStreetAddressLine(0);
347 case ADDRESS_HOME_LINE2
:
348 return GetStreetAddressLine(1);
350 case ADDRESS_HOME_CITY
:
351 return locality_name();
353 case ADDRESS_HOME_STATE
:
354 return administrative_area_name();
356 case ADDRESS_HOME_ZIP
:
357 return postal_code_number();
359 case ADDRESS_HOME_COUNTRY
: {
360 AutofillCountry
country(country_name_code(), app_locale
);
361 return country
.name();
364 case PHONE_HOME_WHOLE_NUMBER
:
365 // Wallet doesn't store user phone number formatting, so just strip all
367 return phone_object_
.GetWholeNumber();
369 case ADDRESS_HOME_DEPENDENT_LOCALITY
:
370 return dependent_locality_name_
;
372 case ADDRESS_HOME_SORTING_CODE
:
373 return sorting_code_
;
376 // A field that Wallet doesn't support. TODO(dbeam): can it be supported?
377 return base::string16();
381 return base::string16();
385 void Address::SetPhoneNumber(const base::string16
& phone_number
) {
386 phone_number_
= phone_number
;
387 phone_object_
= i18n::PhoneObject(phone_number_
, country_name_code_
);
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_
;
403 base::string16
Address::GetStreetAddressLine(size_t line
) const {
404 return street_address_
.size() > line
? street_address_
[line
] :
408 bool Address::operator==(const Address
& other
) const {
409 return object_id_
== other
.object_id_
&&
410 language_code_
== other
.language_code_
&&
411 EqualsIgnoreID(other
);
414 bool Address::operator!=(const Address
& other
) const {
415 return !(*this == other
);
418 } // namespace wallet
419 } // namespace autofill