Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(291)

Side by Side Diff: chrome/browser/autofill/phone_number.cc

Issue 6877130: These changes *are* for review :) (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 9 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « chrome/browser/autofill/phone_number.h ('k') | chrome/browser/autofill/phone_number_i18n.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/autofill/phone_number.h" 5 #include "chrome/browser/autofill/phone_number.h"
6 6
7 #include "base/basictypes.h" 7 #include "base/basictypes.h"
8 #include "base/string_number_conversions.h"
8 #include "base/string_util.h" 9 #include "base/string_util.h"
10 #include "base/utf_string_conversions.h"
9 #include "chrome/browser/autofill/autofill_profile.h" 11 #include "chrome/browser/autofill/autofill_profile.h"
10 #include "chrome/browser/autofill/autofill_type.h" 12 #include "chrome/browser/autofill/autofill_type.h"
11 #include "chrome/browser/autofill/field_types.h" 13 #include "chrome/browser/autofill/field_types.h"
14 #include "chrome/browser/autofill/phone_number_i18n.h"
12 15
13 namespace { 16 namespace {
14 17
15 const char16 kPhoneNumberSeparators[] = { ' ', '.', '(', ')', '-', 0 }; 18 const char16 kPhoneNumberSeparators[] = { ' ', '.', '(', ')', '-', 0 };
16 19
17 // The number of digits in a phone number. 20 // The number of digits in a phone number.
18 const size_t kPhoneNumberLength = 7; 21 const size_t kPhoneNumberLength = 7;
19 22
20 // The number of digits in an area code. 23 // The number of digits in an area code.
21 const size_t kPhoneCityCodeLength = 3; 24 const size_t kPhoneCityCodeLength = 3;
22 25
23 const AutofillType::FieldTypeSubGroup kAutofillPhoneTypes[] = { 26 const AutofillType::FieldTypeSubGroup kAutofillPhoneTypes[] = {
24 AutofillType::PHONE_NUMBER, 27 AutofillType::PHONE_NUMBER,
25 AutofillType::PHONE_CITY_CODE, 28 AutofillType::PHONE_CITY_CODE,
26 AutofillType::PHONE_COUNTRY_CODE, 29 AutofillType::PHONE_COUNTRY_CODE,
27 AutofillType::PHONE_CITY_AND_NUMBER, 30 AutofillType::PHONE_CITY_AND_NUMBER,
28 AutofillType::PHONE_WHOLE_NUMBER, 31 AutofillType::PHONE_WHOLE_NUMBER,
29 }; 32 };
30 33
31 const int kAutofillPhoneLength = arraysize(kAutofillPhoneTypes); 34 const int kAutofillPhoneLength = arraysize(kAutofillPhoneTypes);
32 35
33 } // namespace 36 } // namespace
34 37
35 PhoneNumber::PhoneNumber() {} 38 PhoneNumber::PhoneNumber()
39 : phone_group_(AutofillType::NO_GROUP) {
40 }
41
42 PhoneNumber::PhoneNumber(AutofillType::FieldTypeGroup phone_group)
43 : phone_group_(phone_group) {
44 }
36 45
37 PhoneNumber::PhoneNumber(const PhoneNumber& number) : FormGroup() { 46 PhoneNumber::PhoneNumber(const PhoneNumber& number) : FormGroup() {
38 *this = number; 47 *this = number;
39 } 48 }
40 49
41 PhoneNumber::~PhoneNumber() {} 50 PhoneNumber::~PhoneNumber() {}
42 51
43 PhoneNumber& PhoneNumber::operator=(const PhoneNumber& number) { 52 PhoneNumber& PhoneNumber::operator=(const PhoneNumber& number) {
44 if (this == &number) 53 if (this == &number)
45 return *this; 54 return *this;
46 country_code_ = number.country_code_;
47 city_code_ = number.city_code_;
48 number_ = number.number_; 55 number_ = number.number_;
49 extension_ = number.extension_; 56 extension_ = number.extension_;
57 phone_group_ = number.phone_group_;
50 return *this; 58 return *this;
51 } 59 }
52 60
53 void PhoneNumber::GetMatchingTypes(const string16& text, 61 void PhoneNumber::GetMatchingTypes(const string16& text,
54 FieldTypeSet* matching_types) const { 62 FieldTypeSet* matching_types) const {
55 string16 stripped_text(text); 63 string16 stripped_text(text);
56 StripPunctuation(&stripped_text); 64 StripPunctuation(&stripped_text);
57 if (!Validate(stripped_text)) 65
66 string16 number;
67 string16 city_code;
68 string16 country_code;
69 // Full number - parse it, split it and re-combine into canonical form.
70 if (!autofill_i18n::ParsePhoneNumber(
71 number_, locale_, &country_code, &city_code, &number))
58 return; 72 return;
59 73
60 if (IsNumber(stripped_text)) 74 if (IsNumber(stripped_text, number))
61 matching_types->insert(GetNumberType()); 75 matching_types->insert(GetNumberType());
62 76
63 if (IsCityCode(stripped_text)) 77 if (stripped_text == city_code)
64 matching_types->insert(GetCityCodeType()); 78 matching_types->insert(GetCityCodeType());
65 79
66 if (IsCountryCode(stripped_text)) 80 if (stripped_text == country_code)
67 matching_types->insert(GetCountryCodeType()); 81 matching_types->insert(GetCountryCodeType());
68 82
69 if (IsCityAndNumber(stripped_text)) 83 city_code.append(number);
84 if (stripped_text == city_code)
70 matching_types->insert(GetCityAndNumberType()); 85 matching_types->insert(GetCityAndNumberType());
71 86
72 if (IsWholeNumber(stripped_text)) 87 // Whole number is compared to unfiltered text - it would be parsed for phone
88 // comparision (e.g. 1-800-FLOWERS and 18003569377 are the same)
89 if (IsWholeNumber(text))
73 matching_types->insert(GetWholeNumberType()); 90 matching_types->insert(GetWholeNumberType());
74 } 91 }
75 92
76 void PhoneNumber::GetNonEmptyTypes(FieldTypeSet* non_empty_typess) const { 93 void PhoneNumber::GetNonEmptyTypes(FieldTypeSet* non_empty_types) const {
77 DCHECK(non_empty_typess); 94 DCHECK(non_empty_types);
78 95
79 if (!number().empty()) 96 if (number().empty())
dhollowa 2011/05/19 23:35:02 Let's get rid of |number()|, |set_number()|, |exte
GeorgeY 2011/05/20 00:41:49 Yep, never used. Removed
80 non_empty_typess->insert(GetNumberType()); 97 return;
81 98
82 if (!city_code().empty()) 99 non_empty_types->insert(GetWholeNumberType());
83 non_empty_typess->insert(GetCityCodeType());
84 100
85 if (!country_code().empty()) 101 string16 number;
86 non_empty_typess->insert(GetCountryCodeType()); 102 string16 city_code;
103 string16 country_code;
104 // Full number - parse it, split it and re-combine into canonical form.
105 if (!autofill_i18n::ParsePhoneNumber(
106 number_, locale_, &country_code, &city_code, &number))
107 return;
87 108
88 if (!CityAndNumber().empty()) 109 non_empty_types->insert(GetNumberType());
89 non_empty_typess->insert(GetCityAndNumberType());
90 110
91 if (!WholeNumber().empty()) 111 if (!city_code.empty()) {
92 non_empty_typess->insert(GetWholeNumberType()); 112 non_empty_types->insert(GetCityCodeType());
113 non_empty_types->insert(GetCityAndNumberType());
114 }
115
116 if (!country_code.empty())
117 non_empty_types->insert(GetCountryCodeType());
93 } 118 }
94 119
95 string16 PhoneNumber::GetInfo(AutofillFieldType type) const { 120 string16 PhoneNumber::GetInfo(AutofillFieldType type) const {
96 if (type == GetNumberType()) 121 if (type == GetWholeNumberType())
97 return number(); 122 return number();
98 123
124 string16 number;
125 string16 city_code;
126 string16 country_code;
127 // Full number - parse it, split it and re-combine into canonical form.
128 if (!autofill_i18n::ParsePhoneNumber(
129 number_, locale_, &country_code, &city_code, &number))
130 return string16();
131
132 if (type == GetNumberType())
133 return number;
134
99 if (type == GetCityCodeType()) 135 if (type == GetCityCodeType())
100 return city_code(); 136 return city_code;
101 137
102 if (type == GetCountryCodeType()) 138 if (type == GetCountryCodeType())
103 return country_code(); 139 return country_code;
104 140
141 city_code.append(number);
105 if (type == GetCityAndNumberType()) 142 if (type == GetCityAndNumberType())
106 return CityAndNumber(); 143 return city_code;
107 144
108 if (type == GetWholeNumberType())
109 return WholeNumber();
110 145
dhollowa 2011/05/19 23:35:02 nit: remove extra line.
GeorgeY 2011/05/20 00:41:49 Done.
111 return string16(); 146 return string16();
112 } 147 }
113 148
114 void PhoneNumber::SetInfo(AutofillFieldType type, const string16& value) { 149 void PhoneNumber::SetInfo(AutofillFieldType type, const string16& value) {
115 string16 number(value); 150 string16 number(value);
116 StripPunctuation(&number); 151 StripPunctuation(&number);
117 if (!Validate(number))
118 return;
119 152
120 FieldTypeSubGroup subgroup = AutofillType(type).subgroup(); 153 FieldTypeSubGroup subgroup = AutofillType(type).subgroup();
121 if (subgroup == AutofillType::PHONE_NUMBER) 154 FieldTypeGroup group = AutofillType(type).group();
155 if (phone_group_ == AutofillType::NO_GROUP)
156 phone_group_ = group; // First call on empty phone - set the group.
157 if (subgroup == AutofillType::PHONE_NUMBER) {
158 // Should not be set directly.
159 NOTREACHED();
160 } else if (subgroup == AutofillType::PHONE_CITY_CODE) {
161 // Should not be set directly.
162 NOTREACHED();
163 } else if (subgroup == AutofillType::PHONE_COUNTRY_CODE) {
164 // Should not be set directly.
165 NOTREACHED();
166 } else if (subgroup == AutofillType::PHONE_CITY_AND_NUMBER ||
167 subgroup == AutofillType::PHONE_WHOLE_NUMBER) {
122 set_number(number); 168 set_number(number);
123 else if (subgroup == AutofillType::PHONE_CITY_CODE) 169 } else {
124 set_city_code(number); 170 NOTREACHED();
125 else if (subgroup == AutofillType::PHONE_COUNTRY_CODE) 171 }
126 set_country_code(number); 172 }
127 else if (subgroup == AutofillType::PHONE_CITY_AND_NUMBER || 173
128 subgroup == AutofillType::PHONE_WHOLE_NUMBER) 174 bool PhoneNumber::NormalizePhone() {
129 set_whole_number(number); 175 bool success = true;
176 // Empty number does not need normalization.
177 if (number_.empty())
178 return true;
179
180 string16 number;
181 string16 city_code;
182 string16 country_code;
183 // Full number - parse it, split it and re-combine into canonical form.
184 if (!autofill_i18n::ParsePhoneNumber(
185 number_, locale_, &country_code, &city_code, &number) ||
186 !autofill_i18n::ConstructPhoneNumber(
187 country_code, city_code, number,
188 locale_,
189 (country_code.empty() ?
190 autofill_i18n::NATIONAL : autofill_i18n::INTERNATIONAL),
191 &number_)) {
192 // Parsing failed - do not store phone.
193 number_.clear();
194 success = false;
195 }
196 number_ = autofill_i18n::NormalizePhoneNumber(number_);
197 return success;
198 }
199
200 void PhoneNumber::set_locale(const std::string& locale) {
201 locale_ = locale;
202 }
203
204 AutofillFieldType PhoneNumber::GetNumberType() const {
205 if (phone_group_ == AutofillType::PHONE_HOME)
206 return PHONE_HOME_NUMBER;
207 else if (phone_group_ == AutofillType::PHONE_FAX)
208 return PHONE_FAX_NUMBER;
130 else 209 else
131 NOTREACHED(); 210 NOTREACHED();
211 return UNKNOWN_TYPE;
132 } 212 }
133 213
134 // Static. 214 AutofillFieldType PhoneNumber::GetCityCodeType() const {
135 bool PhoneNumber::ParsePhoneNumber(const string16& value, 215 if (phone_group_ == AutofillType::PHONE_HOME)
136 string16* number, 216 return PHONE_HOME_CITY_CODE;
137 string16* city_code, 217 else if (phone_group_ == AutofillType::PHONE_FAX)
138 string16* country_code) { 218 return PHONE_FAX_CITY_CODE;
139 DCHECK(number); 219 else
140 DCHECK(city_code); 220 NOTREACHED();
141 DCHECK(country_code); 221 return UNKNOWN_TYPE;
142
143 // Make a working copy of value.
144 string16 working = value;
145
146 *number = string16();
147 *city_code = string16();
148 *country_code = string16();
149
150 // First remove any punctuation.
151 StripPunctuation(&working);
152
153 if (working.size() < kPhoneNumberLength)
154 return false;
155
156 // Treat the last 7 digits as the number.
157 *number = working.substr(working.size() - kPhoneNumberLength,
158 kPhoneNumberLength);
159 working.resize(working.size() - kPhoneNumberLength);
160 if (working.size() < kPhoneCityCodeLength)
161 return true;
162
163 // Treat the next three digits as the city code.
164 *city_code = working.substr(working.size() - kPhoneCityCodeLength,
165 kPhoneCityCodeLength);
166 working.resize(working.size() - kPhoneCityCodeLength);
167 if (working.empty())
168 return true;
169
170 // Treat any remaining digits as the country code.
171 *country_code = working;
172 return true;
173 } 222 }
174 223
175 string16 PhoneNumber::WholeNumber() const { 224 AutofillFieldType PhoneNumber::GetCountryCodeType() const {
176 string16 whole_number; 225 if (phone_group_ == AutofillType::PHONE_HOME)
177 if (!country_code_.empty()) 226 return PHONE_HOME_COUNTRY_CODE;
178 whole_number.append(country_code_); 227 else if (phone_group_ == AutofillType::PHONE_FAX)
228 return PHONE_FAX_COUNTRY_CODE;
229 else
230 NOTREACHED();
231 return UNKNOWN_TYPE;
232 }
179 233
180 if (!city_code_.empty()) 234 AutofillFieldType PhoneNumber::GetCityAndNumberType() const {
181 whole_number.append(city_code_); 235 if (phone_group_ == AutofillType::PHONE_HOME)
236 return PHONE_HOME_CITY_AND_NUMBER;
237 else if (phone_group_ == AutofillType::PHONE_FAX)
238 return PHONE_FAX_CITY_AND_NUMBER;
239 else
240 NOTREACHED();
241 return UNKNOWN_TYPE;
242 }
182 243
183 if (!number_.empty()) 244 AutofillFieldType PhoneNumber::GetWholeNumberType() const {
184 whole_number.append(number_); 245 if (phone_group_ == AutofillType::PHONE_HOME)
246 return PHONE_HOME_WHOLE_NUMBER;
247 else if (phone_group_ == AutofillType::PHONE_FAX)
248 return PHONE_FAX_WHOLE_NUMBER;
249 else
250 NOTREACHED();
251 return UNKNOWN_TYPE;
252 }
185 253
186 return whole_number; 254 bool PhoneNumber::PhoneCombineHelper::SetInfo(AutofillFieldType field_type,
255 const string16& value) {
256 PhoneNumber temp(phone_group_);
257
258 if (field_type == temp.GetCountryCodeType()) {
259 country_ = value;
260 return true;
261 } else if (field_type == temp.GetCityCodeType()) {
262 city_ = value;
263 return true;
264 } else if (field_type == temp.GetCityAndNumberType()) {
265 phone_ = value;
266 return true;
267 } else if (field_type == temp.GetNumberType()) {
268 phone_.append(value);
269 return true;
270 } else {
271 return false;
272 }
273 }
274
275 bool PhoneNumber::PhoneCombineHelper::ParseNumber(const std::string& locale,
276 string16* value) {
277 DCHECK(value);
278 return autofill_i18n::ConstructPhoneNumber(
279 country_, city_, phone_,
280 locale,
281 (country_.empty() ?
282 autofill_i18n::NATIONAL : autofill_i18n::INTERNATIONAL),
283 value);
187 } 284 }
188 285
189 void PhoneNumber::set_number(const string16& number) { 286 void PhoneNumber::set_number(const string16& number) {
190 string16 digits(number); 287 number_ = number;
191 StripPunctuation(&digits);
192 number_ = digits;
193 } 288 }
194 289
195 void PhoneNumber::set_whole_number(const string16& whole_number) { 290 bool PhoneNumber::IsNumber(const string16& text, const string16& number) const {
196 string16 number, city_code, country_code; 291 // TODO(georgey): This will need to be updated once we add support for
dhollowa 2011/05/19 23:35:02 I'm confused by this comment. What further work i
GeorgeY 2011/05/20 00:41:49 Not only, some other countries support the splitti
197 ParsePhoneNumber(whole_number, &number, &city_code, &country_code);
198 set_number(number);
199 set_city_code(city_code);
200 set_country_code(country_code);
201 }
202
203 bool PhoneNumber::IsNumber(const string16& text) const {
204 // TODO(isherman): This will need to be updated once we add support for
205 // international phone numbers. 292 // international phone numbers.
206 const size_t kPrefixLength = 3; 293 const size_t kPrefixLength = 3;
207 const size_t kSuffixLength = 4; 294 const size_t kSuffixLength = 4;
208 295
209 if (text == number_) 296 if (text == number)
210 return true; 297 return true;
211 if (text.length() == kPrefixLength && StartsWith(number_, text, true)) 298 if (text.length() == kPrefixLength && StartsWith(number, text, true))
212 return true; 299 return true;
213 if (text.length() == kSuffixLength && EndsWith(number_, text, true)) 300 if (text.length() == kSuffixLength && EndsWith(number, text, true))
214 return true; 301 return true;
215 302
216 return false; 303 return false;
217 } 304 }
218 305
219 bool PhoneNumber::IsCityCode(const string16& text) const {
220 return text == city_code_;
221 }
222
223 bool PhoneNumber::IsCountryCode(const string16& text) const {
224 return text == country_code_;
225 }
226
227 bool PhoneNumber::IsCityAndNumber(const string16& text) const {
228 return text == CityAndNumber();
229 }
230
231 bool PhoneNumber::IsWholeNumber(const string16& text) const { 306 bool PhoneNumber::IsWholeNumber(const string16& text) const {
232 return text == WholeNumber(); 307 return autofill_i18n::ComparePhones(text, number_, locale_) ==
233 } 308 autofill_i18n::PHONES_EQUAL;
234
235 bool PhoneNumber::Validate(const string16& number) const {
236 for (size_t i = 0; i < number.length(); ++i) {
237 if (!IsAsciiDigit(number[i]))
238 return false;
239 }
240
241 return true;
242 } 309 }
243 310
244 // Static. 311 // Static.
245 void PhoneNumber::StripPunctuation(string16* number) { 312 void PhoneNumber::StripPunctuation(string16* number) {
246 RemoveChars(*number, kPhoneNumberSeparators, number); 313 RemoveChars(*number, kPhoneNumberSeparators, number);
247 } 314 }
315
OLDNEW
« no previous file with comments | « chrome/browser/autofill/phone_number.h ('k') | chrome/browser/autofill/phone_number_i18n.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698