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