blob: d4263969e4e9961117a0b25305204063d4c27bca [file] [log] [blame]
[email protected]7b37fbb2011-03-07 16:16:031// Copyright (c) 2011 The Chromium Authors. All rights reserved.
[email protected]3db3ff62010-01-07 00:35:392// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "chrome/browser/autofill/phone_number.h"
6
7#include "base/basictypes.h"
[email protected]11c2bdd12011-05-23 18:24:328#include "base/string_number_conversions.h"
[email protected]3db3ff62010-01-07 00:35:399#include "base/string_util.h"
[email protected]11c2bdd12011-05-23 18:24:3210#include "base/utf_string_conversions.h"
[email protected]9b435be92010-03-04 21:20:1511#include "chrome/browser/autofill/autofill_profile.h"
[email protected]3db3ff62010-01-07 00:35:3912#include "chrome/browser/autofill/autofill_type.h"
13#include "chrome/browser/autofill/field_types.h"
[email protected]11c2bdd12011-05-23 18:24:3214#include "chrome/browser/autofill/phone_number_i18n.h"
[email protected]3db3ff62010-01-07 00:35:3915
[email protected]9b435be92010-03-04 21:20:1516namespace {
[email protected]3db3ff62010-01-07 00:35:3917
[email protected]9b435be92010-03-04 21:20:1518const char16 kPhoneNumberSeparators[] = { ' ', '.', '(', ')', '-', 0 };
19
20// The number of digits in a phone number.
21const size_t kPhoneNumberLength = 7;
22
23// The number of digits in an area code.
24const size_t kPhoneCityCodeLength = 3;
25
[email protected]663bd9e2011-03-21 01:07:0126const AutofillType::FieldTypeSubGroup kAutofillPhoneTypes[] = {
[email protected]7b37fbb2011-03-07 16:16:0327 AutofillType::PHONE_NUMBER,
28 AutofillType::PHONE_CITY_CODE,
29 AutofillType::PHONE_COUNTRY_CODE,
30 AutofillType::PHONE_CITY_AND_NUMBER,
31 AutofillType::PHONE_WHOLE_NUMBER,
[email protected]3db3ff62010-01-07 00:35:3932};
33
[email protected]663bd9e2011-03-21 01:07:0134const int kAutofillPhoneLength = arraysize(kAutofillPhoneTypes);
[email protected]9b435be92010-03-04 21:20:1535
36} // namespace
[email protected]3db3ff62010-01-07 00:35:3937
[email protected]11c2bdd12011-05-23 18:24:3238PhoneNumber::PhoneNumber()
39 : phone_group_(AutofillType::NO_GROUP) {
40}
41
42PhoneNumber::PhoneNumber(AutofillType::FieldTypeGroup phone_group)
43 : phone_group_(phone_group) {
44}
[email protected]8e383412010-10-19 16:57:0345
[email protected]43897242011-03-09 03:52:1146PhoneNumber::PhoneNumber(const PhoneNumber& number) : FormGroup() {
47 *this = number;
48}
49
[email protected]8e383412010-10-19 16:57:0350PhoneNumber::~PhoneNumber() {}
51
[email protected]43897242011-03-09 03:52:1152PhoneNumber& PhoneNumber::operator=(const PhoneNumber& number) {
53 if (this == &number)
54 return *this;
[email protected]43897242011-03-09 03:52:1155 number_ = number.number_;
[email protected]11c2bdd12011-05-23 18:24:3256 phone_group_ = number.phone_group_;
[email protected]6f113af2011-06-03 05:10:4357 ClearCachedNumbers();
[email protected]43897242011-03-09 03:52:1158 return *this;
59}
60
[email protected]1308c2832011-05-09 18:30:2361void PhoneNumber::GetMatchingTypes(const string16& text,
62 FieldTypeSet* matching_types) const {
[email protected]3db3ff62010-01-07 00:35:3963 string16 stripped_text(text);
64 StripPunctuation(&stripped_text);
[email protected]11c2bdd12011-05-23 18:24:3265
[email protected]6f113af2011-06-03 05:10:4366 if (!UpdateCacheIfNeeded())
[email protected]3db3ff62010-01-07 00:35:3967 return;
68
[email protected]6f113af2011-06-03 05:10:4369 if (IsNumber(stripped_text, cached_local_number_))
[email protected]1308c2832011-05-09 18:30:2370 matching_types->insert(GetNumberType());
[email protected]3db3ff62010-01-07 00:35:3971
[email protected]6f113af2011-06-03 05:10:4372 if (stripped_text == cached_city_code_)
[email protected]1308c2832011-05-09 18:30:2373 matching_types->insert(GetCityCodeType());
[email protected]3db3ff62010-01-07 00:35:3974
[email protected]6f113af2011-06-03 05:10:4375 if (stripped_text == cached_country_code_)
[email protected]1308c2832011-05-09 18:30:2376 matching_types->insert(GetCountryCodeType());
[email protected]3db3ff62010-01-07 00:35:3977
[email protected]6f113af2011-06-03 05:10:4378 string16 city_and_local(cached_city_code_);
79 city_and_local.append(cached_local_number_);
80 if (stripped_text == city_and_local)
[email protected]1308c2832011-05-09 18:30:2381 matching_types->insert(GetCityAndNumberType());
[email protected]3db3ff62010-01-07 00:35:3982
[email protected]11c2bdd12011-05-23 18:24:3283 // Whole number is compared to unfiltered text - it would be parsed for phone
84 // comparision (e.g. 1-800-FLOWERS and 18003569377 are the same)
85 if (IsWholeNumber(text))
[email protected]1308c2832011-05-09 18:30:2386 matching_types->insert(GetWholeNumberType());
[email protected]3db3ff62010-01-07 00:35:3987}
88
[email protected]11c2bdd12011-05-23 18:24:3289void PhoneNumber::GetNonEmptyTypes(FieldTypeSet* non_empty_types) const {
90 DCHECK(non_empty_types);
[email protected]cea1d112010-07-01 00:57:3391
[email protected]11c2bdd12011-05-23 18:24:3292 if (number_.empty())
93 return;
[email protected]cea1d112010-07-01 00:57:3394
[email protected]11c2bdd12011-05-23 18:24:3295 non_empty_types->insert(GetWholeNumberType());
[email protected]cea1d112010-07-01 00:57:3396
[email protected]6f113af2011-06-03 05:10:4397 if (!UpdateCacheIfNeeded())
[email protected]11c2bdd12011-05-23 18:24:3298 return;
[email protected]cea1d112010-07-01 00:57:3399
[email protected]11c2bdd12011-05-23 18:24:32100 non_empty_types->insert(GetNumberType());
[email protected]cea1d112010-07-01 00:57:33101
[email protected]6f113af2011-06-03 05:10:43102 if (!cached_city_code_.empty()) {
[email protected]11c2bdd12011-05-23 18:24:32103 non_empty_types->insert(GetCityCodeType());
104 non_empty_types->insert(GetCityAndNumberType());
105 }
106
[email protected]6f113af2011-06-03 05:10:43107 if (!cached_country_code_.empty())
[email protected]11c2bdd12011-05-23 18:24:32108 non_empty_types->insert(GetCountryCodeType());
[email protected]cea1d112010-07-01 00:57:33109}
110
[email protected]3b3a0ca72011-03-17 23:04:55111string16 PhoneNumber::GetInfo(AutofillFieldType type) const {
[email protected]11c2bdd12011-05-23 18:24:32112 if (type == GetWholeNumberType())
113 return number_;
[email protected]6f113af2011-06-03 05:10:43114 if (!UpdateCacheIfNeeded())
[email protected]11c2bdd12011-05-23 18:24:32115 return string16();
116
[email protected]1ffe8e992011-03-17 06:26:29117 if (type == GetNumberType())
[email protected]6f113af2011-06-03 05:10:43118 return cached_local_number_;
[email protected]3db3ff62010-01-07 00:35:39119
[email protected]1ffe8e992011-03-17 06:26:29120 if (type == GetCityCodeType())
[email protected]6f113af2011-06-03 05:10:43121 return cached_city_code_;
[email protected]3db3ff62010-01-07 00:35:39122
[email protected]1ffe8e992011-03-17 06:26:29123 if (type == GetCountryCodeType())
[email protected]6f113af2011-06-03 05:10:43124 return cached_country_code_;
[email protected]3db3ff62010-01-07 00:35:39125
[email protected]6f113af2011-06-03 05:10:43126 string16 city_and_local(cached_city_code_);
127 city_and_local.append(cached_local_number_);
[email protected]1ffe8e992011-03-17 06:26:29128 if (type == GetCityAndNumberType())
[email protected]6f113af2011-06-03 05:10:43129 return city_and_local;
[email protected]3db3ff62010-01-07 00:35:39130
[email protected]cea1d112010-07-01 00:57:33131 return string16();
[email protected]3db3ff62010-01-07 00:35:39132}
133
[email protected]1ffe8e992011-03-17 06:26:29134void PhoneNumber::SetInfo(AutofillFieldType type, const string16& value) {
[email protected]1ffe8e992011-03-17 06:26:29135 FieldTypeSubGroup subgroup = AutofillType(type).subgroup();
[email protected]11c2bdd12011-05-23 18:24:32136 FieldTypeGroup group = AutofillType(type).group();
137 if (phone_group_ == AutofillType::NO_GROUP)
138 phone_group_ = group; // First call on empty phone - set the group.
[email protected]6f113af2011-06-03 05:10:43139 ClearCachedNumbers();
[email protected]11c2bdd12011-05-23 18:24:32140 if (subgroup == AutofillType::PHONE_NUMBER) {
141 // Should not be set directly.
142 NOTREACHED();
143 } else if (subgroup == AutofillType::PHONE_CITY_CODE) {
144 // Should not be set directly.
145 NOTREACHED();
146 } else if (subgroup == AutofillType::PHONE_COUNTRY_CODE) {
147 // Should not be set directly.
148 NOTREACHED();
149 } else if (subgroup == AutofillType::PHONE_CITY_AND_NUMBER ||
150 subgroup == AutofillType::PHONE_WHOLE_NUMBER) {
151 number_ = value;
152 StripPunctuation(&number_);
153 } else {
154 NOTREACHED();
155 }
156}
157
158bool PhoneNumber::NormalizePhone() {
[email protected]11c2bdd12011-05-23 18:24:32159 // Empty number does not need normalization.
160 if (number_.empty())
161 return true;
162
[email protected]6f113af2011-06-03 05:10:43163 ClearCachedNumbers();
[email protected]f4672472011-05-27 07:21:01164 number_ = autofill_i18n::NormalizePhoneNumber(number_, locale_);
165 return !number_.empty();
[email protected]11c2bdd12011-05-23 18:24:32166}
167
168void PhoneNumber::set_locale(const std::string& locale) {
169 locale_ = locale;
[email protected]6f113af2011-06-03 05:10:43170 ClearCachedNumbers();
[email protected]11c2bdd12011-05-23 18:24:32171}
172
173AutofillFieldType PhoneNumber::GetNumberType() const {
174 if (phone_group_ == AutofillType::PHONE_HOME)
175 return PHONE_HOME_NUMBER;
176 else if (phone_group_ == AutofillType::PHONE_FAX)
177 return PHONE_FAX_NUMBER;
[email protected]3db3ff62010-01-07 00:35:39178 else
179 NOTREACHED();
[email protected]11c2bdd12011-05-23 18:24:32180 return UNKNOWN_TYPE;
[email protected]3db3ff62010-01-07 00:35:39181}
182
[email protected]11c2bdd12011-05-23 18:24:32183AutofillFieldType PhoneNumber::GetCityCodeType() const {
184 if (phone_group_ == AutofillType::PHONE_HOME)
185 return PHONE_HOME_CITY_CODE;
186 else if (phone_group_ == AutofillType::PHONE_FAX)
187 return PHONE_FAX_CITY_CODE;
188 else
189 NOTREACHED();
190 return UNKNOWN_TYPE;
191}
[email protected]9b435be92010-03-04 21:20:15192
[email protected]11c2bdd12011-05-23 18:24:32193AutofillFieldType PhoneNumber::GetCountryCodeType() const {
194 if (phone_group_ == AutofillType::PHONE_HOME)
195 return PHONE_HOME_COUNTRY_CODE;
196 else if (phone_group_ == AutofillType::PHONE_FAX)
197 return PHONE_FAX_COUNTRY_CODE;
198 else
199 NOTREACHED();
200 return UNKNOWN_TYPE;
201}
[email protected]9b435be92010-03-04 21:20:15202
[email protected]11c2bdd12011-05-23 18:24:32203AutofillFieldType PhoneNumber::GetCityAndNumberType() const {
204 if (phone_group_ == AutofillType::PHONE_HOME)
205 return PHONE_HOME_CITY_AND_NUMBER;
206 else if (phone_group_ == AutofillType::PHONE_FAX)
207 return PHONE_FAX_CITY_AND_NUMBER;
208 else
209 NOTREACHED();
210 return UNKNOWN_TYPE;
211}
[email protected]9b435be92010-03-04 21:20:15212
[email protected]11c2bdd12011-05-23 18:24:32213AutofillFieldType PhoneNumber::GetWholeNumberType() const {
214 if (phone_group_ == AutofillType::PHONE_HOME)
215 return PHONE_HOME_WHOLE_NUMBER;
216 else if (phone_group_ == AutofillType::PHONE_FAX)
217 return PHONE_FAX_WHOLE_NUMBER;
218 else
219 NOTREACHED();
220 return UNKNOWN_TYPE;
221}
[email protected]9b435be92010-03-04 21:20:15222
[email protected]11c2bdd12011-05-23 18:24:32223bool PhoneNumber::PhoneCombineHelper::SetInfo(AutofillFieldType field_type,
224 const string16& value) {
225 PhoneNumber temp(phone_group_);
226
227 if (field_type == temp.GetCountryCodeType()) {
228 country_ = value;
229 return true;
230 } else if (field_type == temp.GetCityCodeType()) {
231 city_ = value;
232 return true;
233 } else if (field_type == temp.GetCityAndNumberType()) {
234 phone_ = value;
235 return true;
236 } else if (field_type == temp.GetNumberType()) {
237 phone_.append(value);
238 return true;
239 } else {
[email protected]f8e7b62d2010-06-03 18:12:54240 return false;
[email protected]11c2bdd12011-05-23 18:24:32241 }
[email protected]9b435be92010-03-04 21:20:15242}
243
[email protected]11c2bdd12011-05-23 18:24:32244bool PhoneNumber::PhoneCombineHelper::ParseNumber(const std::string& locale,
245 string16* value) {
246 DCHECK(value);
247 return autofill_i18n::ConstructPhoneNumber(
248 country_, city_, phone_,
249 locale,
250 (country_.empty() ?
251 autofill_i18n::NATIONAL : autofill_i18n::INTERNATIONAL),
252 value);
[email protected]3db3ff62010-01-07 00:35:39253}
254
[email protected]11c2bdd12011-05-23 18:24:32255bool PhoneNumber::IsNumber(const string16& text, const string16& number) const {
256 // TODO(georgey): This will need to be updated once we add support for
[email protected]c13014b2011-04-18 20:04:00257 // international phone numbers.
[email protected]4605a132011-04-29 00:42:40258 const size_t kPrefixLength = 3;
259 const size_t kSuffixLength = 4;
260
[email protected]11c2bdd12011-05-23 18:24:32261 if (text == number)
[email protected]4605a132011-04-29 00:42:40262 return true;
[email protected]11c2bdd12011-05-23 18:24:32263 if (text.length() == kPrefixLength && StartsWith(number, text, true))
[email protected]4605a132011-04-29 00:42:40264 return true;
[email protected]11c2bdd12011-05-23 18:24:32265 if (text.length() == kSuffixLength && EndsWith(number, text, true))
[email protected]4605a132011-04-29 00:42:40266 return true;
267
268 return false;
[email protected]3db3ff62010-01-07 00:35:39269}
270
[email protected]3db3ff62010-01-07 00:35:39271bool PhoneNumber::IsWholeNumber(const string16& text) const {
[email protected]11c2bdd12011-05-23 18:24:32272 return autofill_i18n::ComparePhones(text, number_, locale_) ==
273 autofill_i18n::PHONES_EQUAL;
[email protected]3db3ff62010-01-07 00:35:39274}
275
[email protected]9b435be92010-03-04 21:20:15276// Static.
277void PhoneNumber::StripPunctuation(string16* number) {
278 RemoveChars(*number, kPhoneNumberSeparators, number);
[email protected]3db3ff62010-01-07 00:35:39279}
[email protected]11c2bdd12011-05-23 18:24:32280
[email protected]6f113af2011-06-03 05:10:43281void PhoneNumber::ClearCachedNumbers() const {
282 cached_country_code_.clear();
283 cached_city_code_.clear();
284 cached_local_number_.clear();
285}
286
287bool PhoneNumber::UpdateCacheIfNeeded() const {
288 if (cached_local_number_.empty() && !number_.empty()) {
289 return autofill_i18n::ParsePhoneNumber(
290 number_, locale_, &cached_country_code_, &cached_city_code_,
291 &cached_local_number_);
292 } else {
293 return true;
294 }
295}