Torne (Richard Coles) | 868fa2f | 2013-06-11 10:57:03 +0100 | [diff] [blame] | 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" |
Ben Murdoch | eb525c5 | 2013-07-10 11:40:50 +0100 | [diff] [blame] | 11 | #include "components/autofill/core/browser/autofill_country.h" |
| 12 | #include "components/autofill/core/browser/autofill_profile.h" |
Ben Murdoch | 3240926 | 2013-08-07 11:04:47 +0100 | [diff] [blame] | 13 | #include "components/autofill/core/browser/autofill_type.h" |
Ben Murdoch | eb525c5 | 2013-07-10 11:40:50 +0100 | [diff] [blame] | 14 | #include "components/autofill/core/browser/state_names.h" |
Torne (Richard Coles) | 868fa2f | 2013-06-11 10:57:03 +0100 | [diff] [blame] | 15 | |
| 16 | namespace autofill { |
| 17 | namespace wallet { |
| 18 | |
| 19 | // Server specified type for address with complete details. |
| 20 | const char kFullAddress[] = "FULL"; |
| 21 | |
| 22 | namespace { |
| 23 | |
| 24 | Address* CreateAddressInternal(const base::DictionaryValue& dictionary, |
| 25 | const std::string& object_id) { |
| 26 | std::string country_name_code; |
| 27 | if (!dictionary.GetString("postal_address.country_name_code", |
| 28 | &country_name_code)) { |
| 29 | DLOG(ERROR) << "Response from Google Wallet missing country name"; |
| 30 | return NULL; |
| 31 | } |
| 32 | |
| 33 | string16 recipient_name; |
| 34 | if (!dictionary.GetString("postal_address.recipient_name", |
| 35 | &recipient_name)) { |
| 36 | DLOG(ERROR) << "Response from Google Wallet missing recipient name"; |
| 37 | return NULL; |
| 38 | } |
| 39 | |
| 40 | string16 postal_code_number; |
| 41 | if (!dictionary.GetString("postal_address.postal_code_number", |
| 42 | &postal_code_number)) { |
| 43 | DLOG(ERROR) << "Response from Google Wallet missing postal code number"; |
| 44 | return NULL; |
| 45 | } |
| 46 | |
| 47 | string16 phone_number; |
| 48 | if (!dictionary.GetString("phone_number", &phone_number)) |
| 49 | DVLOG(1) << "Response from Google Wallet missing phone number"; |
| 50 | |
| 51 | string16 address_line_1; |
| 52 | string16 address_line_2; |
| 53 | const ListValue* address_line_list; |
| 54 | if (dictionary.GetList("postal_address.address_line", &address_line_list)) { |
| 55 | if (!address_line_list->GetString(0, &address_line_1)) |
| 56 | DVLOG(1) << "Response from Google Wallet missing address line 1"; |
| 57 | if (!address_line_list->GetString(1, &address_line_2)) |
| 58 | DVLOG(1) << "Response from Google Wallet missing address line 2"; |
| 59 | } else { |
| 60 | DVLOG(1) << "Response from Google Wallet missing address lines"; |
| 61 | } |
| 62 | |
| 63 | string16 locality_name; |
| 64 | if (!dictionary.GetString("postal_address.locality_name", |
| 65 | &locality_name)) { |
| 66 | DVLOG(1) << "Response from Google Wallet missing locality name"; |
| 67 | } |
| 68 | |
| 69 | string16 administrative_area_name; |
| 70 | if (!dictionary.GetString("postal_address.administrative_area_name", |
| 71 | &administrative_area_name)) { |
| 72 | DVLOG(1) << "Response from Google Wallet missing administrative area name"; |
| 73 | } |
| 74 | |
| 75 | Address* address = new Address(country_name_code, |
| 76 | recipient_name, |
| 77 | address_line_1, |
| 78 | address_line_2, |
| 79 | locality_name, |
| 80 | administrative_area_name, |
| 81 | postal_code_number, |
| 82 | phone_number, |
| 83 | object_id); |
| 84 | |
| 85 | bool is_minimal_address = false; |
| 86 | if (dictionary.GetBoolean("is_minimal_address", &is_minimal_address)) |
| 87 | address->set_is_complete_address(!is_minimal_address); |
| 88 | else |
| 89 | DVLOG(1) << "Response from Google Wallet missing is_minimal_address bit"; |
| 90 | |
| 91 | return address; |
| 92 | } |
| 93 | |
| 94 | } // namespace |
| 95 | |
| 96 | Address::Address() {} |
| 97 | |
| 98 | Address::Address(const AutofillProfile& profile) |
| 99 | : country_name_code_( |
| 100 | UTF16ToASCII(profile.GetRawInfo(ADDRESS_HOME_COUNTRY))), |
| 101 | recipient_name_(profile.GetRawInfo(NAME_FULL)), |
| 102 | address_line_1_(profile.GetRawInfo(ADDRESS_HOME_LINE1)), |
| 103 | address_line_2_(profile.GetRawInfo(ADDRESS_HOME_LINE2)), |
| 104 | locality_name_(profile.GetRawInfo(ADDRESS_HOME_CITY)), |
Torne (Richard Coles) | 868fa2f | 2013-06-11 10:57:03 +0100 | [diff] [blame] | 105 | postal_code_number_(profile.GetRawInfo(ADDRESS_HOME_ZIP)), |
| 106 | phone_number_(profile.GetRawInfo(PHONE_HOME_WHOLE_NUMBER)), |
Torne (Richard Coles) | 5e3f23d | 2013-06-11 16:24:11 +0100 | [diff] [blame] | 107 | is_complete_address_(true) { |
| 108 | state_names::GetNameAndAbbreviation(profile.GetRawInfo(ADDRESS_HOME_STATE), |
| 109 | NULL, |
| 110 | &administrative_area_name_); |
| 111 | StringToUpperASCII(&administrative_area_name_); |
| 112 | } |
Torne (Richard Coles) | 868fa2f | 2013-06-11 10:57:03 +0100 | [diff] [blame] | 113 | |
| 114 | Address::Address(const std::string& country_name_code, |
| 115 | const string16& recipient_name, |
| 116 | const string16& address_line_1, |
| 117 | const string16& address_line_2, |
| 118 | const string16& locality_name, |
| 119 | const string16& administrative_area_name, |
| 120 | const string16& postal_code_number, |
| 121 | const string16& phone_number, |
| 122 | const std::string& object_id) |
| 123 | : country_name_code_(country_name_code), |
| 124 | recipient_name_(recipient_name), |
| 125 | address_line_1_(address_line_1), |
| 126 | address_line_2_(address_line_2), |
| 127 | locality_name_(locality_name), |
| 128 | administrative_area_name_(administrative_area_name), |
| 129 | postal_code_number_(postal_code_number), |
| 130 | phone_number_(phone_number), |
| 131 | object_id_(object_id), |
Torne (Richard Coles) | 5e3f23d | 2013-06-11 16:24:11 +0100 | [diff] [blame] | 132 | is_complete_address_(true) { |
| 133 | } |
Torne (Richard Coles) | 868fa2f | 2013-06-11 10:57:03 +0100 | [diff] [blame] | 134 | |
| 135 | Address::~Address() {} |
| 136 | |
| 137 | // static |
| 138 | scoped_ptr<Address> Address::CreateAddressWithID( |
| 139 | const base::DictionaryValue& dictionary) { |
| 140 | std::string object_id; |
| 141 | if (!dictionary.GetString("id", &object_id)) { |
| 142 | DLOG(ERROR) << "Response from Google Wallet missing object id"; |
| 143 | return scoped_ptr<Address>(); |
| 144 | } |
| 145 | return scoped_ptr<Address>(CreateAddressInternal(dictionary, object_id)); |
| 146 | } |
| 147 | |
| 148 | // static |
| 149 | scoped_ptr<Address> Address::CreateAddress( |
| 150 | const base::DictionaryValue& dictionary) { |
| 151 | std::string object_id; |
| 152 | dictionary.GetString("id", &object_id); |
| 153 | return scoped_ptr<Address>(CreateAddressInternal(dictionary, object_id)); |
| 154 | } |
| 155 | |
| 156 | // static |
| 157 | scoped_ptr<Address> Address::CreateDisplayAddress( |
| 158 | const base::DictionaryValue& dictionary) { |
| 159 | std::string country_code; |
| 160 | if (!dictionary.GetString("country_code", &country_code)) { |
| 161 | DLOG(ERROR) << "Reponse from Google Wallet missing country code"; |
| 162 | return scoped_ptr<Address>(); |
| 163 | } |
| 164 | |
| 165 | string16 name; |
| 166 | if (!dictionary.GetString("name", &name)) { |
| 167 | DLOG(ERROR) << "Reponse from Google Wallet missing name"; |
| 168 | return scoped_ptr<Address>(); |
| 169 | } |
| 170 | |
| 171 | string16 postal_code; |
| 172 | if (!dictionary.GetString("postal_code", &postal_code)) { |
| 173 | DLOG(ERROR) << "Reponse from Google Wallet missing postal code"; |
| 174 | return scoped_ptr<Address>(); |
| 175 | } |
| 176 | |
| 177 | string16 address1; |
| 178 | if (!dictionary.GetString("address1", &address1)) |
| 179 | DVLOG(1) << "Reponse from Google Wallet missing address1"; |
| 180 | |
| 181 | string16 address2; |
| 182 | if (!dictionary.GetString("address2", &address2)) |
| 183 | DVLOG(1) << "Reponse from Google Wallet missing address2"; |
| 184 | |
| 185 | string16 city; |
| 186 | if (!dictionary.GetString("city", &city)) |
| 187 | DVLOG(1) << "Reponse from Google Wallet missing city"; |
| 188 | |
| 189 | string16 state; |
| 190 | if (!dictionary.GetString("state", &state)) |
| 191 | DVLOG(1) << "Reponse from Google Wallet missing state"; |
| 192 | |
| 193 | string16 phone_number; |
| 194 | if (!dictionary.GetString("phone_number", &phone_number)) |
| 195 | DVLOG(1) << "Reponse from Google Wallet missing phone number"; |
| 196 | |
| 197 | std::string address_state; |
| 198 | if (!dictionary.GetString("type", &address_state)) |
| 199 | DVLOG(1) << "Response from Google Wallet missing type/state of address"; |
| 200 | |
| 201 | scoped_ptr<Address> address( |
| 202 | new Address(country_code, |
| 203 | name, |
| 204 | address1, |
| 205 | address2, |
| 206 | city, |
| 207 | state, |
| 208 | postal_code, |
| 209 | phone_number, |
| 210 | std::string())); |
| 211 | address->set_is_complete_address(address_state == kFullAddress); |
| 212 | |
| 213 | return address.Pass(); |
| 214 | } |
| 215 | |
| 216 | scoped_ptr<base::DictionaryValue> Address::ToDictionaryWithID() const { |
| 217 | scoped_ptr<base::DictionaryValue> dict(new base::DictionaryValue()); |
| 218 | |
| 219 | if (!object_id_.empty()) |
| 220 | dict->SetString("id", object_id_); |
| 221 | dict->SetString("phone_number", phone_number_); |
| 222 | dict->Set("postal_address", ToDictionaryWithoutID().release()); |
| 223 | |
| 224 | return dict.Pass(); |
| 225 | } |
| 226 | |
| 227 | scoped_ptr<base::DictionaryValue> Address::ToDictionaryWithoutID() const { |
| 228 | scoped_ptr<base::DictionaryValue> dict(new base::DictionaryValue()); |
| 229 | |
| 230 | scoped_ptr<base::ListValue> address_lines(new base::ListValue()); |
| 231 | address_lines->AppendString(address_line_1_); |
| 232 | if (!address_line_2_.empty()) |
| 233 | address_lines->AppendString(address_line_2_); |
| 234 | dict->Set("address_line", address_lines.release()); |
| 235 | |
| 236 | dict->SetString("country_name_code", country_name_code_); |
| 237 | dict->SetString("recipient_name", recipient_name_); |
| 238 | dict->SetString("locality_name", locality_name_); |
| 239 | dict->SetString("administrative_area_name", |
| 240 | administrative_area_name_); |
| 241 | dict->SetString("postal_code_number", postal_code_number_); |
| 242 | |
| 243 | return dict.Pass(); |
| 244 | } |
| 245 | |
| 246 | string16 Address::DisplayName() const { |
| 247 | #if defined(OS_ANDROID) |
| 248 | // TODO(aruslan): improve this stub implementation. |
| 249 | return recipient_name(); |
| 250 | #else |
| 251 | // TODO(estade): improve this stub implementation + l10n. |
| 252 | return recipient_name() + ASCIIToUTF16(", ") + address_line_1(); |
| 253 | #endif |
| 254 | } |
| 255 | |
| 256 | string16 Address::DisplayNameDetail() const { |
| 257 | #if defined(OS_ANDROID) |
| 258 | // TODO(aruslan): improve this stub implementation. |
| 259 | return address_line_1(); |
| 260 | #else |
| 261 | return string16(); |
| 262 | #endif |
| 263 | } |
| 264 | |
Ben Murdoch | 3240926 | 2013-08-07 11:04:47 +0100 | [diff] [blame] | 265 | string16 Address::GetInfo(const AutofillType& type, |
Torne (Richard Coles) | 868fa2f | 2013-06-11 10:57:03 +0100 | [diff] [blame] | 266 | const std::string& app_locale) const { |
Ben Murdoch | bb1529c | 2013-08-08 10:24:53 +0100 | [diff] [blame^] | 267 | switch (type.GetStorableType()) { |
Torne (Richard Coles) | 868fa2f | 2013-06-11 10:57:03 +0100 | [diff] [blame] | 268 | case NAME_FULL: |
| 269 | return recipient_name(); |
| 270 | |
| 271 | case ADDRESS_HOME_LINE1: |
| 272 | return address_line_1(); |
| 273 | |
| 274 | case ADDRESS_HOME_LINE2: |
| 275 | return address_line_2(); |
| 276 | |
| 277 | case ADDRESS_HOME_CITY: |
| 278 | return locality_name(); |
| 279 | |
| 280 | case ADDRESS_HOME_STATE: |
| 281 | return administrative_area_name(); |
| 282 | |
| 283 | case ADDRESS_HOME_ZIP: |
| 284 | return postal_code_number(); |
| 285 | |
| 286 | case ADDRESS_HOME_COUNTRY: { |
| 287 | AutofillCountry country(country_name_code(), app_locale); |
| 288 | return country.name(); |
| 289 | } |
| 290 | |
| 291 | case PHONE_HOME_WHOLE_NUMBER: |
| 292 | return phone_number(); |
| 293 | |
| 294 | // TODO(estade): implement more. |
| 295 | default: |
| 296 | NOTREACHED(); |
| 297 | return string16(); |
| 298 | } |
| 299 | } |
| 300 | |
| 301 | bool Address::EqualsIgnoreID(const Address& other) const { |
| 302 | return country_name_code_ == other.country_name_code_ && |
| 303 | recipient_name_ == other.recipient_name_ && |
| 304 | address_line_1_ == other.address_line_1_ && |
| 305 | address_line_2_ == other.address_line_2_ && |
| 306 | locality_name_ == other.locality_name_ && |
| 307 | administrative_area_name_ == other.administrative_area_name_ && |
| 308 | postal_code_number_ == other.postal_code_number_ && |
| 309 | phone_number_ == other.phone_number_ && |
| 310 | is_complete_address_ == other.is_complete_address_; |
| 311 | } |
| 312 | |
| 313 | bool Address::operator==(const Address& other) const { |
| 314 | return object_id_ == other.object_id_ && EqualsIgnoreID(other); |
| 315 | } |
| 316 | |
| 317 | bool Address::operator!=(const Address& other) const { |
| 318 | return !(*this == other); |
| 319 | } |
| 320 | |
| 321 | } // namespace wallet |
| 322 | } // namespace autofill |