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