blob: 1eca43a2710d7af687e40366bc91c2cbd21d9c52 [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]43897242011-03-09 03:52:1157 return *this;
58}
59
[email protected]1308c2832011-05-09 18:30:2360void PhoneNumber::GetMatchingTypes(const string16& text,
61 FieldTypeSet* matching_types) const {
[email protected]3db3ff62010-01-07 00:35:3962 string16 stripped_text(text);
63 StripPunctuation(&stripped_text);
[email protected]11c2bdd12011-05-23 18:24:3264
65 string16 number;
66 string16 city_code;
67 string16 country_code;
68 // Full number - parse it, split it and re-combine into canonical form.
69 if (!autofill_i18n::ParsePhoneNumber(
70 number_, locale_, &country_code, &city_code, &number))
[email protected]3db3ff62010-01-07 00:35:3971 return;
72
[email protected]11c2bdd12011-05-23 18:24:3273 if (IsNumber(stripped_text, number))
[email protected]1308c2832011-05-09 18:30:2374 matching_types->insert(GetNumberType());
[email protected]3db3ff62010-01-07 00:35:3975
[email protected]11c2bdd12011-05-23 18:24:3276 if (stripped_text == city_code)
[email protected]1308c2832011-05-09 18:30:2377 matching_types->insert(GetCityCodeType());
[email protected]3db3ff62010-01-07 00:35:3978
[email protected]11c2bdd12011-05-23 18:24:3279 if (stripped_text == country_code)
[email protected]1308c2832011-05-09 18:30:2380 matching_types->insert(GetCountryCodeType());
[email protected]3db3ff62010-01-07 00:35:3981
[email protected]11c2bdd12011-05-23 18:24:3282 city_code.append(number);
83 if (stripped_text == city_code)
[email protected]1308c2832011-05-09 18:30:2384 matching_types->insert(GetCityAndNumberType());
[email protected]3db3ff62010-01-07 00:35:3985
[email protected]11c2bdd12011-05-23 18:24:3286 // Whole number is compared to unfiltered text - it would be parsed for phone
87 // comparision (e.g. 1-800-FLOWERS and 18003569377 are the same)
88 if (IsWholeNumber(text))
[email protected]1308c2832011-05-09 18:30:2389 matching_types->insert(GetWholeNumberType());
[email protected]3db3ff62010-01-07 00:35:3990}
91
[email protected]11c2bdd12011-05-23 18:24:3292void PhoneNumber::GetNonEmptyTypes(FieldTypeSet* non_empty_types) const {
93 DCHECK(non_empty_types);
[email protected]cea1d112010-07-01 00:57:3394
[email protected]11c2bdd12011-05-23 18:24:3295 if (number_.empty())
96 return;
[email protected]cea1d112010-07-01 00:57:3397
[email protected]11c2bdd12011-05-23 18:24:3298 non_empty_types->insert(GetWholeNumberType());
[email protected]cea1d112010-07-01 00:57:3399
[email protected]11c2bdd12011-05-23 18:24:32100 string16 number;
101 string16 city_code;
102 string16 country_code;
103 // Full number - parse it, split it and re-combine into canonical form.
104 if (!autofill_i18n::ParsePhoneNumber(
105 number_, locale_, &country_code, &city_code, &number))
106 return;
[email protected]cea1d112010-07-01 00:57:33107
[email protected]11c2bdd12011-05-23 18:24:32108 non_empty_types->insert(GetNumberType());
[email protected]cea1d112010-07-01 00:57:33109
[email protected]11c2bdd12011-05-23 18:24:32110 if (!city_code.empty()) {
111 non_empty_types->insert(GetCityCodeType());
112 non_empty_types->insert(GetCityAndNumberType());
113 }
114
115 if (!country_code.empty())
116 non_empty_types->insert(GetCountryCodeType());
[email protected]cea1d112010-07-01 00:57:33117}
118
[email protected]3b3a0ca72011-03-17 23:04:55119string16 PhoneNumber::GetInfo(AutofillFieldType type) const {
[email protected]11c2bdd12011-05-23 18:24:32120 if (type == GetWholeNumberType())
121 return number_;
122
123 string16 number;
124 string16 city_code;
125 string16 country_code;
126 // Full number - parse it, split it and re-combine into canonical form.
127 if (!autofill_i18n::ParsePhoneNumber(
128 number_, locale_, &country_code, &city_code, &number))
129 return string16();
130
[email protected]1ffe8e992011-03-17 06:26:29131 if (type == GetNumberType())
[email protected]11c2bdd12011-05-23 18:24:32132 return number;
[email protected]3db3ff62010-01-07 00:35:39133
[email protected]1ffe8e992011-03-17 06:26:29134 if (type == GetCityCodeType())
[email protected]11c2bdd12011-05-23 18:24:32135 return city_code;
[email protected]3db3ff62010-01-07 00:35:39136
[email protected]1ffe8e992011-03-17 06:26:29137 if (type == GetCountryCodeType())
[email protected]11c2bdd12011-05-23 18:24:32138 return country_code;
[email protected]3db3ff62010-01-07 00:35:39139
[email protected]11c2bdd12011-05-23 18:24:32140 city_code.append(number);
[email protected]1ffe8e992011-03-17 06:26:29141 if (type == GetCityAndNumberType())
[email protected]11c2bdd12011-05-23 18:24:32142 return city_code;
[email protected]3db3ff62010-01-07 00:35:39143
[email protected]cea1d112010-07-01 00:57:33144 return string16();
[email protected]3db3ff62010-01-07 00:35:39145}
146
[email protected]1ffe8e992011-03-17 06:26:29147void PhoneNumber::SetInfo(AutofillFieldType type, const string16& value) {
[email protected]1ffe8e992011-03-17 06:26:29148 FieldTypeSubGroup subgroup = AutofillType(type).subgroup();
[email protected]11c2bdd12011-05-23 18:24:32149 FieldTypeGroup group = AutofillType(type).group();
150 if (phone_group_ == AutofillType::NO_GROUP)
151 phone_group_ = group; // First call on empty phone - set the group.
152 if (subgroup == AutofillType::PHONE_NUMBER) {
153 // Should not be set directly.
154 NOTREACHED();
155 } else if (subgroup == AutofillType::PHONE_CITY_CODE) {
156 // Should not be set directly.
157 NOTREACHED();
158 } else if (subgroup == AutofillType::PHONE_COUNTRY_CODE) {
159 // Should not be set directly.
160 NOTREACHED();
161 } else if (subgroup == AutofillType::PHONE_CITY_AND_NUMBER ||
162 subgroup == AutofillType::PHONE_WHOLE_NUMBER) {
163 number_ = value;
164 StripPunctuation(&number_);
165 } else {
166 NOTREACHED();
167 }
168}
169
170bool PhoneNumber::NormalizePhone() {
171 bool success = true;
172 // Empty number does not need normalization.
173 if (number_.empty())
174 return true;
175
176 string16 number;
177 string16 city_code;
178 string16 country_code;
179 // Full number - parse it, split it and re-combine into canonical form.
180 if (!autofill_i18n::ParsePhoneNumber(
181 number_, locale_, &country_code, &city_code, &number) ||
182 !autofill_i18n::ConstructPhoneNumber(
183 country_code, city_code, number,
184 locale_,
185 (country_code.empty() ?
186 autofill_i18n::NATIONAL : autofill_i18n::INTERNATIONAL),
187 &number_)) {
188 // Parsing failed - do not store phone.
189 number_.clear();
190 success = false;
191 }
192 number_ = autofill_i18n::NormalizePhoneNumber(number_);
193 return success;
194}
195
196void PhoneNumber::set_locale(const std::string& locale) {
197 locale_ = locale;
198}
199
200AutofillFieldType PhoneNumber::GetNumberType() const {
201 if (phone_group_ == AutofillType::PHONE_HOME)
202 return PHONE_HOME_NUMBER;
203 else if (phone_group_ == AutofillType::PHONE_FAX)
204 return PHONE_FAX_NUMBER;
[email protected]3db3ff62010-01-07 00:35:39205 else
206 NOTREACHED();
[email protected]11c2bdd12011-05-23 18:24:32207 return UNKNOWN_TYPE;
[email protected]3db3ff62010-01-07 00:35:39208}
209
[email protected]11c2bdd12011-05-23 18:24:32210AutofillFieldType PhoneNumber::GetCityCodeType() const {
211 if (phone_group_ == AutofillType::PHONE_HOME)
212 return PHONE_HOME_CITY_CODE;
213 else if (phone_group_ == AutofillType::PHONE_FAX)
214 return PHONE_FAX_CITY_CODE;
215 else
216 NOTREACHED();
217 return UNKNOWN_TYPE;
218}
[email protected]9b435be92010-03-04 21:20:15219
[email protected]11c2bdd12011-05-23 18:24:32220AutofillFieldType PhoneNumber::GetCountryCodeType() const {
221 if (phone_group_ == AutofillType::PHONE_HOME)
222 return PHONE_HOME_COUNTRY_CODE;
223 else if (phone_group_ == AutofillType::PHONE_FAX)
224 return PHONE_FAX_COUNTRY_CODE;
225 else
226 NOTREACHED();
227 return UNKNOWN_TYPE;
228}
[email protected]9b435be92010-03-04 21:20:15229
[email protected]11c2bdd12011-05-23 18:24:32230AutofillFieldType PhoneNumber::GetCityAndNumberType() const {
231 if (phone_group_ == AutofillType::PHONE_HOME)
232 return PHONE_HOME_CITY_AND_NUMBER;
233 else if (phone_group_ == AutofillType::PHONE_FAX)
234 return PHONE_FAX_CITY_AND_NUMBER;
235 else
236 NOTREACHED();
237 return UNKNOWN_TYPE;
238}
[email protected]9b435be92010-03-04 21:20:15239
[email protected]11c2bdd12011-05-23 18:24:32240AutofillFieldType PhoneNumber::GetWholeNumberType() const {
241 if (phone_group_ == AutofillType::PHONE_HOME)
242 return PHONE_HOME_WHOLE_NUMBER;
243 else if (phone_group_ == AutofillType::PHONE_FAX)
244 return PHONE_FAX_WHOLE_NUMBER;
245 else
246 NOTREACHED();
247 return UNKNOWN_TYPE;
248}
[email protected]9b435be92010-03-04 21:20:15249
[email protected]11c2bdd12011-05-23 18:24:32250bool PhoneNumber::PhoneCombineHelper::SetInfo(AutofillFieldType field_type,
251 const string16& value) {
252 PhoneNumber temp(phone_group_);
253
254 if (field_type == temp.GetCountryCodeType()) {
255 country_ = value;
256 return true;
257 } else if (field_type == temp.GetCityCodeType()) {
258 city_ = value;
259 return true;
260 } else if (field_type == temp.GetCityAndNumberType()) {
261 phone_ = value;
262 return true;
263 } else if (field_type == temp.GetNumberType()) {
264 phone_.append(value);
265 return true;
266 } else {
[email protected]f8e7b62d2010-06-03 18:12:54267 return false;
[email protected]11c2bdd12011-05-23 18:24:32268 }
[email protected]9b435be92010-03-04 21:20:15269}
270
[email protected]11c2bdd12011-05-23 18:24:32271bool PhoneNumber::PhoneCombineHelper::ParseNumber(const std::string& locale,
272 string16* value) {
273 DCHECK(value);
274 return autofill_i18n::ConstructPhoneNumber(
275 country_, city_, phone_,
276 locale,
277 (country_.empty() ?
278 autofill_i18n::NATIONAL : autofill_i18n::INTERNATIONAL),
279 value);
[email protected]3db3ff62010-01-07 00:35:39280}
281
[email protected]11c2bdd12011-05-23 18:24:32282bool PhoneNumber::IsNumber(const string16& text, const string16& number) const {
283 // TODO(georgey): This will need to be updated once we add support for
[email protected]c13014b2011-04-18 20:04:00284 // international phone numbers.
[email protected]4605a132011-04-29 00:42:40285 const size_t kPrefixLength = 3;
286 const size_t kSuffixLength = 4;
287
[email protected]11c2bdd12011-05-23 18:24:32288 if (text == number)
[email protected]4605a132011-04-29 00:42:40289 return true;
[email protected]11c2bdd12011-05-23 18:24:32290 if (text.length() == kPrefixLength && StartsWith(number, text, true))
[email protected]4605a132011-04-29 00:42:40291 return true;
[email protected]11c2bdd12011-05-23 18:24:32292 if (text.length() == kSuffixLength && EndsWith(number, text, true))
[email protected]4605a132011-04-29 00:42:40293 return true;
294
295 return false;
[email protected]3db3ff62010-01-07 00:35:39296}
297
[email protected]3db3ff62010-01-07 00:35:39298bool PhoneNumber::IsWholeNumber(const string16& text) const {
[email protected]11c2bdd12011-05-23 18:24:32299 return autofill_i18n::ComparePhones(text, number_, locale_) ==
300 autofill_i18n::PHONES_EQUAL;
[email protected]3db3ff62010-01-07 00:35:39301}
302
[email protected]9b435be92010-03-04 21:20:15303// Static.
304void PhoneNumber::StripPunctuation(string16* number) {
305 RemoveChars(*number, kPhoneNumberSeparators, number);
[email protected]3db3ff62010-01-07 00:35:39306}
[email protected]11c2bdd12011-05-23 18:24:32307