blob: 4c78cc427a31f787bbaf1a763b24ad45da3b12a4 [file] [log] [blame] [edit]
// 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();
}