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