| // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "chrome/browser/autofill/phone_number.h" |
| |
| #include "base/basictypes.h" |
| #include "base/string_number_conversions.h" |
| #include "base/string_util.h" |
| #include "base/utf_string_conversions.h" |
| #include "chrome/browser/autofill/autofill_profile.h" |
| #include "chrome/browser/autofill/autofill_type.h" |
| #include "chrome/browser/autofill/field_types.h" |
| #include "chrome/browser/autofill/phone_number_i18n.h" |
| |
| namespace { |
| |
| const char16 kPhoneNumberSeparators[] = { ' ', '.', '(', ')', '-', 0 }; |
| |
| // The number of digits in a phone number. |
| const size_t kPhoneNumberLength = 7; |
| |
| // The number of digits in an area code. |
| const size_t kPhoneCityCodeLength = 3; |
| |
| void StripPunctuation(string16* number) { |
| RemoveChars(*number, kPhoneNumberSeparators, number); |
| } |
| |
| } // namespace |
| |
| PhoneNumber::PhoneNumber(AutofillProfile* profile) |
| : profile_(profile) { |
| } |
| |
| PhoneNumber::PhoneNumber(const PhoneNumber& number) |
| : FormGroup(), |
| profile_(NULL) { |
| *this = number; |
| } |
| |
| PhoneNumber::~PhoneNumber() {} |
| |
| PhoneNumber& PhoneNumber::operator=(const PhoneNumber& number) { |
| if (this == &number) |
| return *this; |
| |
| number_ = number.number_; |
| profile_ = number.profile_; |
| cached_parsed_phone_ = number.cached_parsed_phone_; |
| return *this; |
| } |
| |
| void PhoneNumber::GetSupportedTypes(FieldTypeSet* supported_types) const { |
| supported_types->insert(PHONE_HOME_WHOLE_NUMBER); |
| supported_types->insert(PHONE_HOME_NUMBER); |
| supported_types->insert(PHONE_HOME_CITY_CODE); |
| supported_types->insert(PHONE_HOME_CITY_AND_NUMBER); |
| supported_types->insert(PHONE_HOME_COUNTRY_CODE); |
| } |
| |
| string16 PhoneNumber::GetInfo(AutofillFieldType type) const { |
| if (type == PHONE_HOME_WHOLE_NUMBER) |
| return number_; |
| |
| UpdateCacheIfNeeded(); |
| if (!cached_parsed_phone_.IsValidNumber()) |
| return string16(); |
| |
| if (type == PHONE_HOME_NUMBER) |
| return cached_parsed_phone_.GetNumber(); |
| |
| if (type == PHONE_HOME_CITY_CODE) |
| return cached_parsed_phone_.GetCityCode(); |
| |
| if (type == PHONE_HOME_COUNTRY_CODE) |
| return cached_parsed_phone_.GetCountryCode(); |
| |
| if (type == PHONE_HOME_CITY_AND_NUMBER) { |
| string16 city_and_local(cached_parsed_phone_.GetCityCode()); |
| city_and_local.append(cached_parsed_phone_.GetNumber()); |
| return city_and_local; |
| } |
| |
| return string16(); |
| } |
| |
| void PhoneNumber::SetInfo(AutofillFieldType type, const string16& value) { |
| if (type != PHONE_HOME_CITY_AND_NUMBER && |
| type != PHONE_HOME_WHOLE_NUMBER) { |
| // Only full phone numbers should be set directly. The remaining field |
| // field types are read-only. |
| return; |
| } |
| |
| number_ = value; |
| cached_parsed_phone_ = autofill_i18n::PhoneObject(number_, GetLocale()); |
| } |
| |
| // Normalize phones if |type| is a whole number: |
| // (650)2345678 -> 6502345678 |
| // 1-800-FLOWERS -> 18003569377 |
| // If the phone cannot be normalized, returns the stored value verbatim. |
| string16 PhoneNumber::GetCanonicalizedInfo(AutofillFieldType type) const { |
| string16 phone = GetInfo(type); |
| if (type != PHONE_HOME_WHOLE_NUMBER) |
| return phone; |
| |
| string16 normalized_phone = autofill_i18n::NormalizePhoneNumber(phone, |
| GetLocale()); |
| if (!normalized_phone.empty()) |
| return normalized_phone; |
| |
| return phone; |
| } |
| |
| bool PhoneNumber::SetCanonicalizedInfo(AutofillFieldType type, |
| const string16& value) { |
| string16 number = value; |
| StripPunctuation(&number); |
| SetInfo(type, number); |
| |
| return NormalizePhone(); |
| } |
| |
| void PhoneNumber::GetMatchingTypes(const string16& text, |
| FieldTypeSet* matching_types) const { |
| string16 stripped_text = text; |
| StripPunctuation(&stripped_text); |
| FormGroup::GetMatchingTypes(stripped_text, matching_types); |
| |
| // For US numbers, also compare to the three-digit prefix and the four-digit |
| // suffix, since web sites often split numbers into these two fields. |
| string16 number = GetCanonicalizedInfo(PHONE_HOME_NUMBER); |
| if (GetLocale() == "US" && number.size() == (kPrefixLength + kSuffixLength)) { |
| string16 prefix = number.substr(kPrefixOffset, kPrefixLength); |
| string16 suffix = number.substr(kSuffixOffset, kSuffixLength); |
| if (text == prefix || text == suffix) |
| matching_types->insert(PHONE_HOME_NUMBER); |
| } |
| |
| string16 whole_number = GetCanonicalizedInfo(PHONE_HOME_WHOLE_NUMBER); |
| if (!whole_number.empty() && |
| autofill_i18n::NormalizePhoneNumber(text, GetLocale()) == whole_number) { |
| matching_types->insert(PHONE_HOME_WHOLE_NUMBER); |
| } |
| } |
| |
| bool PhoneNumber::NormalizePhone() { |
| // Empty number does not need normalization. |
| if (number_.empty()) |
| return true; |
| |
| UpdateCacheIfNeeded(); |
| number_ = cached_parsed_phone_.GetWholeNumber(); |
| return !number_.empty(); |
| } |
| |
| std::string PhoneNumber::GetLocale() const { |
| if (!profile_) { |
| NOTREACHED(); |
| return "US"; |
| } |
| |
| return profile_->CountryCode(); |
| } |
| |
| void PhoneNumber::UpdateCacheIfNeeded() const { |
| std::string locale = GetLocale(); |
| if (!number_.empty() && cached_parsed_phone_.GetLocale() != locale) |
| cached_parsed_phone_ = autofill_i18n::PhoneObject(number_, locale); |
| } |
| |
| PhoneNumber::PhoneCombineHelper::PhoneCombineHelper() { |
| } |
| |
| PhoneNumber::PhoneCombineHelper::~PhoneCombineHelper() { |
| } |
| |
| bool PhoneNumber::PhoneCombineHelper::SetInfo(AutofillFieldType field_type, |
| const string16& value) { |
| if (field_type == PHONE_HOME_COUNTRY_CODE) { |
| country_ = value; |
| return true; |
| } |
| |
| if (field_type == PHONE_HOME_CITY_CODE) { |
| city_ = value; |
| return true; |
| } |
| |
| if (field_type == PHONE_HOME_CITY_AND_NUMBER) { |
| phone_ = value; |
| return true; |
| } |
| |
| if (field_type == PHONE_HOME_WHOLE_NUMBER) { |
| whole_number_ = value; |
| return true; |
| } |
| |
| if (field_type == PHONE_HOME_NUMBER) { |
| phone_.append(value); |
| return true; |
| } |
| |
| return false; |
| } |
| |
| bool PhoneNumber::PhoneCombineHelper::ParseNumber(const std::string& locale, |
| string16* value) { |
| if (!whole_number_.empty()) { |
| *value = whole_number_; |
| return true; |
| } |
| |
| return autofill_i18n::ConstructPhoneNumber( |
| country_, city_, phone_, |
| locale, |
| (country_.empty() ? |
| autofill_i18n::NATIONAL : autofill_i18n::INTERNATIONAL), |
| value); |
| } |
| |
| bool PhoneNumber::PhoneCombineHelper::IsEmpty() const { |
| return phone_.empty() && whole_number_.empty(); |
| } |