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/core/browser/phone_number.h" 6 7 #include "base/basictypes.h" 8 #include "base/strings/string_number_conversions.h" 9 #include "base/strings/string_util.h" 10 #include "base/strings/utf_string_conversions.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/field_types.h" 15 #include "components/autofill/core/browser/phone_number_i18n.h" 16 17 namespace autofill { 18 namespace { 19 20 const char16 kPhoneNumberSeparators[] = { ' ', '.', '(', ')', '-', 0 }; 21 22 void StripPunctuation(base::string16* number) { 23 base::RemoveChars(*number, kPhoneNumberSeparators, number); 24 } 25 26 // Returns the region code for this phone number, which is an ISO 3166 2-letter 27 // country code. The returned value is based on the |profile|; if the |profile| 28 // does not have a country code associated with it, falls back to the country 29 // code corresponding to the |app_locale|. 30 std::string GetRegion(const AutofillProfile& profile, 31 const std::string& app_locale) { 32 base::string16 country_code = profile.GetRawInfo(ADDRESS_HOME_COUNTRY); 33 if (!country_code.empty()) 34 return UTF16ToASCII(country_code); 35 36 return AutofillCountry::CountryCodeForLocale(app_locale); 37 } 38 39 } // namespace 40 41 PhoneNumber::PhoneNumber(AutofillProfile* profile) 42 : profile_(profile) { 43 } 44 45 PhoneNumber::PhoneNumber(const PhoneNumber& number) 46 : profile_(NULL) { 47 *this = number; 48 } 49 50 PhoneNumber::~PhoneNumber() {} 51 52 PhoneNumber& PhoneNumber::operator=(const PhoneNumber& number) { 53 if (this == &number) 54 return *this; 55 56 number_ = number.number_; 57 profile_ = number.profile_; 58 cached_parsed_phone_ = number.cached_parsed_phone_; 59 return *this; 60 } 61 62 void PhoneNumber::GetSupportedTypes(ServerFieldTypeSet* supported_types) const { 63 supported_types->insert(PHONE_HOME_WHOLE_NUMBER); 64 supported_types->insert(PHONE_HOME_NUMBER); 65 supported_types->insert(PHONE_HOME_CITY_CODE); 66 supported_types->insert(PHONE_HOME_CITY_AND_NUMBER); 67 supported_types->insert(PHONE_HOME_COUNTRY_CODE); 68 } 69 70 base::string16 PhoneNumber::GetRawInfo(ServerFieldType type) const { 71 DCHECK_EQ(PHONE_HOME, AutofillType(type).group()); 72 if (type == PHONE_HOME_WHOLE_NUMBER) 73 return number_; 74 75 // Only the whole number is available as raw data. All of the other types are 76 // parsed from this raw info, and parsing requires knowledge of the phone 77 // number's region, which is only available via GetInfo(). 78 return base::string16(); 79 } 80 81 void PhoneNumber::SetRawInfo(ServerFieldType type, 82 const base::string16& value) { 83 DCHECK_EQ(PHONE_HOME, AutofillType(type).group()); 84 if (type != PHONE_HOME_CITY_AND_NUMBER && type != PHONE_HOME_WHOLE_NUMBER) { 85 // Only full phone numbers should be set directly. The remaining field 86 // field types are read-only. 87 return; 88 } 89 90 number_ = value; 91 92 // Invalidate the cached number. 93 cached_parsed_phone_ = i18n::PhoneObject(); 94 } 95 96 // Normalize phones if |type| is a whole number: 97 // (650)2345678 -> 6502345678 98 // 1-800-FLOWERS -> 18003569377 99 // If the phone cannot be normalized, returns the stored value verbatim. 100 base::string16 PhoneNumber::GetInfo(const AutofillType& type, 101 const std::string& app_locale) const { 102 ServerFieldType storable_type = type.GetStorableType(); 103 UpdateCacheIfNeeded(app_locale); 104 105 // Queries for whole numbers will return the non-normalized number if 106 // normalization for the number fails. All other field types require 107 // normalization. 108 if (storable_type != PHONE_HOME_WHOLE_NUMBER && 109 !cached_parsed_phone_.IsValidNumber()) 110 return base::string16(); 111 112 switch (storable_type) { 113 case PHONE_HOME_WHOLE_NUMBER: 114 return cached_parsed_phone_.GetWholeNumber(); 115 116 case PHONE_HOME_NUMBER: 117 return cached_parsed_phone_.number(); 118 119 case PHONE_HOME_CITY_CODE: 120 return cached_parsed_phone_.city_code(); 121 122 case PHONE_HOME_COUNTRY_CODE: 123 return cached_parsed_phone_.country_code(); 124 125 case PHONE_HOME_CITY_AND_NUMBER: 126 return 127 cached_parsed_phone_.city_code() + cached_parsed_phone_.number(); 128 129 default: 130 NOTREACHED(); 131 return base::string16(); 132 } 133 } 134 135 bool PhoneNumber::SetInfo(const AutofillType& type, 136 const base::string16& value, 137 const std::string& app_locale) { 138 SetRawInfo(type.GetStorableType(), value); 139 140 if (number_.empty()) 141 return true; 142 143 // Store a formatted (i.e., pretty printed) version of the number. 144 UpdateCacheIfNeeded(app_locale); 145 number_ = cached_parsed_phone_.GetFormattedNumber(); 146 return !number_.empty(); 147 } 148 149 void PhoneNumber::GetMatchingTypes(const base::string16& text, 150 const std::string& app_locale, 151 ServerFieldTypeSet* matching_types) const { 152 base::string16 stripped_text = text; 153 StripPunctuation(&stripped_text); 154 FormGroup::GetMatchingTypes(stripped_text, app_locale, matching_types); 155 156 // For US numbers, also compare to the three-digit prefix and the four-digit 157 // suffix, since web sites often split numbers into these two fields. 158 base::string16 number = GetInfo(AutofillType(PHONE_HOME_NUMBER), app_locale); 159 if (GetRegion(*profile_, app_locale) == "US" && 160 number.size() == (kPrefixLength + kSuffixLength)) { 161 base::string16 prefix = number.substr(kPrefixOffset, kPrefixLength); 162 base::string16 suffix = number.substr(kSuffixOffset, kSuffixLength); 163 if (text == prefix || text == suffix) 164 matching_types->insert(PHONE_HOME_NUMBER); 165 } 166 167 base::string16 whole_number = 168 GetInfo(AutofillType(PHONE_HOME_WHOLE_NUMBER), app_locale); 169 if (!whole_number.empty()) { 170 base::string16 normalized_number = 171 i18n::NormalizePhoneNumber(text, GetRegion(*profile_, app_locale)); 172 if (normalized_number == whole_number) 173 matching_types->insert(PHONE_HOME_WHOLE_NUMBER); 174 } 175 } 176 177 void PhoneNumber::UpdateCacheIfNeeded(const std::string& app_locale) const { 178 std::string region = GetRegion(*profile_, app_locale); 179 if (!number_.empty() && cached_parsed_phone_.region() != region) 180 cached_parsed_phone_ = i18n::PhoneObject(number_, region); 181 } 182 183 PhoneNumber::PhoneCombineHelper::PhoneCombineHelper() { 184 } 185 186 PhoneNumber::PhoneCombineHelper::~PhoneCombineHelper() { 187 } 188 189 bool PhoneNumber::PhoneCombineHelper::SetInfo(const AutofillType& type, 190 const base::string16& value) { 191 ServerFieldType storable_type = type.GetStorableType(); 192 if (storable_type == PHONE_HOME_COUNTRY_CODE) { 193 country_ = value; 194 return true; 195 } 196 197 if (storable_type == PHONE_HOME_CITY_CODE) { 198 city_ = value; 199 return true; 200 } 201 202 if (storable_type == PHONE_HOME_CITY_AND_NUMBER) { 203 phone_ = value; 204 return true; 205 } 206 207 if (storable_type == PHONE_HOME_WHOLE_NUMBER) { 208 whole_number_ = value; 209 return true; 210 } 211 212 if (storable_type == PHONE_HOME_NUMBER) { 213 phone_.append(value); 214 return true; 215 } 216 217 return false; 218 } 219 220 bool PhoneNumber::PhoneCombineHelper::ParseNumber( 221 const AutofillProfile& profile, 222 const std::string& app_locale, 223 base::string16* value) { 224 if (IsEmpty()) 225 return false; 226 227 if (!whole_number_.empty()) { 228 *value = whole_number_; 229 return true; 230 } 231 232 return i18n::ConstructPhoneNumber( 233 country_, city_, phone_, GetRegion(profile, app_locale), value); 234 } 235 236 bool PhoneNumber::PhoneCombineHelper::IsEmpty() const { 237 return phone_.empty() && whole_number_.empty(); 238 } 239 240 } // namespace autofill 241