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

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
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"
15 #include "third_party/libphonenumber/cpp/src/phonenumberutil.h"
dhollowa 2011/05/13 18:55:35 This breaks encapsulation of our phone_number_i18n
GeorgeY 2011/05/18 17:41:45 Forgot to remove it. Done.
12 16
13 namespace { 17 namespace {
14 18
15 const char16 kPhoneNumberSeparators[] = { ' ', '.', '(', ')', '-', 0 }; 19 const char16 kPhoneNumberSeparators[] = { ' ', '.', '(', ')', '-', 0 };
16 20
17 // The number of digits in a phone number. 21 // The number of digits in a phone number.
18 const size_t kPhoneNumberLength = 7; 22 const size_t kPhoneNumberLength = 7;
19 23
20 // The number of digits in an area code. 24 // The number of digits in an area code.
21 const size_t kPhoneCityCodeLength = 3; 25 const size_t kPhoneCityCodeLength = 3;
22 26
23 const AutofillType::FieldTypeSubGroup kAutofillPhoneTypes[] = { 27 const AutofillType::FieldTypeSubGroup kAutofillPhoneTypes[] = {
24 AutofillType::PHONE_NUMBER, 28 AutofillType::PHONE_NUMBER,
25 AutofillType::PHONE_CITY_CODE, 29 AutofillType::PHONE_CITY_CODE,
26 AutofillType::PHONE_COUNTRY_CODE, 30 AutofillType::PHONE_COUNTRY_CODE,
27 AutofillType::PHONE_CITY_AND_NUMBER, 31 AutofillType::PHONE_CITY_AND_NUMBER,
28 AutofillType::PHONE_WHOLE_NUMBER, 32 AutofillType::PHONE_WHOLE_NUMBER,
29 }; 33 };
30 34
31 const int kAutofillPhoneLength = arraysize(kAutofillPhoneTypes); 35 const int kAutofillPhoneLength = arraysize(kAutofillPhoneTypes);
32 36
33 } // namespace 37 } // namespace
34 38
35 PhoneNumber::PhoneNumber() {} 39 PhoneNumber::PhoneNumber()
40 : phone_group_(AutofillType::NO_GROUP) {
41 }
42
43 PhoneNumber::PhoneNumber(AutofillType::FieldTypeGroup phone_group)
44 : phone_group_(phone_group) {
45 }
36 46
37 PhoneNumber::PhoneNumber(const PhoneNumber& number) : FormGroup() { 47 PhoneNumber::PhoneNumber(const PhoneNumber& number) : FormGroup() {
38 *this = number; 48 *this = number;
39 } 49 }
40 50
41 PhoneNumber::~PhoneNumber() {} 51 PhoneNumber::~PhoneNumber() {}
42 52
43 PhoneNumber& PhoneNumber::operator=(const PhoneNumber& number) { 53 PhoneNumber& PhoneNumber::operator=(const PhoneNumber& number) {
44 if (this == &number) 54 if (this == &number)
45 return *this; 55 return *this;
46 country_code_ = number.country_code_;
47 city_code_ = number.city_code_;
48 number_ = number.number_; 56 number_ = number.number_;
49 extension_ = number.extension_; 57 extension_ = number.extension_;
58 phone_group_ = number.phone_group_;
50 return *this; 59 return *this;
51 } 60 }
52 61
53 void PhoneNumber::GetMatchingTypes(const string16& text, 62 void PhoneNumber::GetMatchingTypes(const string16& text,
54 FieldTypeSet* matching_types) const { 63 FieldTypeSet* matching_types) const {
55 string16 stripped_text(text); 64 string16 stripped_text(text);
56 StripPunctuation(&stripped_text); 65 StripPunctuation(&stripped_text);
57 if (!Validate(stripped_text)) 66
67 string16 number;
68 string16 city_code;
69 string16 country_code;
70 // Full number - parse it, split it and re-combine into canonical form.
71 if (!autofill_i18n::ParsePhoneNumber(
72 number_, locale_, &country_code, &city_code, &number))
58 return; 73 return;
59 74
60 if (IsNumber(stripped_text)) 75 if (IsNumber(stripped_text, number))
61 matching_types->insert(GetNumberType()); 76 matching_types->insert(GetNumberType());
62 77
63 if (IsCityCode(stripped_text)) 78 if (stripped_text == city_code)
64 matching_types->insert(GetCityCodeType()); 79 matching_types->insert(GetCityCodeType());
65 80
66 if (IsCountryCode(stripped_text)) 81 if (stripped_text == country_code)
67 matching_types->insert(GetCountryCodeType()); 82 matching_types->insert(GetCountryCodeType());
68 83
69 if (IsCityAndNumber(stripped_text)) 84 city_code.append(number);
85 if (stripped_text == city_code)
70 matching_types->insert(GetCityAndNumberType()); 86 matching_types->insert(GetCityAndNumberType());
71 87
72 if (IsWholeNumber(stripped_text)) 88 // Whole number is compared to unfiltered text - it would be parsed for phone
89 // comparision (e.g. 1-800-FLOWERS and 18003569377 are the same)
90 if (IsWholeNumber(text))
73 matching_types->insert(GetWholeNumberType()); 91 matching_types->insert(GetWholeNumberType());
74 } 92 }
75 93
76 void PhoneNumber::GetNonEmptyTypes(FieldTypeSet* non_empty_typess) const { 94 void PhoneNumber::GetNonEmptyTypes(FieldTypeSet* non_empty_types) const {
77 DCHECK(non_empty_typess); 95 DCHECK(non_empty_types);
78 96
79 if (!number().empty()) 97 if (number().empty())
80 non_empty_typess->insert(GetNumberType()); 98 return;
81 99
82 if (!city_code().empty()) 100 non_empty_types->insert(GetWholeNumberType());
83 non_empty_typess->insert(GetCityCodeType());
84 101
85 if (!country_code().empty()) 102 string16 number;
86 non_empty_typess->insert(GetCountryCodeType()); 103 string16 city_code;
104 string16 country_code;
105 // Full number - parse it, split it and re-combine into canonical form.
106 if (!autofill_i18n::ParsePhoneNumber(
107 number_, locale_, &country_code, &city_code, &number))
108 return;
87 109
88 if (!CityAndNumber().empty()) 110 non_empty_types->insert(GetNumberType());
89 non_empty_typess->insert(GetCityAndNumberType());
90 111
91 if (!WholeNumber().empty()) 112 if (!city_code.empty()) {
92 non_empty_typess->insert(GetWholeNumberType()); 113 non_empty_types->insert(GetCityCodeType());
114 non_empty_types->insert(GetCityAndNumberType());
115 }
116
117 if (!country_code.empty())
118 non_empty_types->insert(GetCountryCodeType());
93 } 119 }
94 120
95 string16 PhoneNumber::GetInfo(AutofillFieldType type) const { 121 string16 PhoneNumber::GetInfo(AutofillFieldType type) const {
96 if (type == GetNumberType()) 122 if (type == GetWholeNumberType())
97 return number(); 123 return number();
98 124
125 string16 number;
126 string16 city_code;
127 string16 country_code;
128 // Full number - parse it, split it and re-combine into canonical form.
129 if (!autofill_i18n::ParsePhoneNumber(
130 number_, locale_, &country_code, &city_code, &number))
131 return string16();
132
133 if (type == GetNumberType())
134 return number;
135
99 if (type == GetCityCodeType()) 136 if (type == GetCityCodeType())
100 return city_code(); 137 return city_code;
101 138
102 if (type == GetCountryCodeType()) 139 if (type == GetCountryCodeType())
103 return country_code(); 140 return country_code;
104 141
142 city_code.append(number);
105 if (type == GetCityAndNumberType()) 143 if (type == GetCityAndNumberType())
106 return CityAndNumber(); 144 return city_code;
107 145
108 if (type == GetWholeNumberType())
109 return WholeNumber();
110 146
111 return string16(); 147 return string16();
112 } 148 }
113 149
114 void PhoneNumber::SetInfo(AutofillFieldType type, const string16& value) { 150 void PhoneNumber::SetInfo(AutofillFieldType type, const string16& value) {
115 string16 number(value); 151 string16 number(value);
116 StripPunctuation(&number); 152 StripPunctuation(&number);
117 if (!Validate(number))
118 return;
119 153
120 FieldTypeSubGroup subgroup = AutofillType(type).subgroup(); 154 FieldTypeSubGroup subgroup = AutofillType(type).subgroup();
121 if (subgroup == AutofillType::PHONE_NUMBER) 155 FieldTypeGroup group = AutofillType(type).group();
156 if (phone_group_ == AutofillType::NO_GROUP)
157 phone_group_ = group; // First call on empty phone - set the group.
158 if (subgroup == AutofillType::PHONE_NUMBER) {
159 // Should not be set directly.
160 NOTREACHED();
161 } else if (subgroup == AutofillType::PHONE_CITY_CODE) {
162 // Should not be set directly.
163 NOTREACHED();
164 } else if (subgroup == AutofillType::PHONE_COUNTRY_CODE) {
165 // Should not be set directly.
166 NOTREACHED();
167 } else if (subgroup == AutofillType::PHONE_CITY_AND_NUMBER ||
168 subgroup == AutofillType::PHONE_WHOLE_NUMBER) {
122 set_number(number); 169 set_number(number);
123 else if (subgroup == AutofillType::PHONE_CITY_CODE) 170 } else {
124 set_city_code(number); 171 NOTREACHED();
125 else if (subgroup == AutofillType::PHONE_COUNTRY_CODE) 172 }
126 set_country_code(number); 173 }
127 else if (subgroup == AutofillType::PHONE_CITY_AND_NUMBER || 174
128 subgroup == AutofillType::PHONE_WHOLE_NUMBER) 175 bool PhoneNumber::NormalizePhone() {
129 set_whole_number(number); 176 if (locale_.empty())
177 locale_ = "US"; // US is a default locale.
178
179 bool success = true;
180 // Empty number does not need normalization.
181 if (number_.empty())
182 return true;
183
184 string16 number;
185 string16 city_code;
186 string16 country_code;
187 // Full number - parse it, split it and re-combine into canonical form.
188 if (!autofill_i18n::ParsePhoneNumber(
189 number_, locale_, &country_code, &city_code, &number) ||
190 !autofill_i18n::ConstructPhoneNumber(
191 country_code, city_code, number,
192 locale_,
193 (country_code.empty() ?
194 autofill_i18n::NATIONAL : autofill_i18n::INTERNATIONAL),
195 &number_)) {
196 // Parsing failed - do not store phone.
197 number_.clear();
198 success = false;
199 }
200 number_ = autofill_i18n::NormalizePhoneNumber(number_);
201 return success;
202 }
203
204 void PhoneNumber::set_locale(const std::string& locale) {
205 locale_ = locale;
206 }
207
208 AutofillFieldType PhoneNumber::GetNumberType() const {
209 if (phone_group_ == AutofillType::PHONE_HOME)
210 return PHONE_HOME_NUMBER;
211 else if (phone_group_ == AutofillType::PHONE_FAX)
212 return PHONE_FAX_NUMBER;
130 else 213 else
131 NOTREACHED(); 214 NOTREACHED();
215 return UNKNOWN_TYPE;
132 } 216 }
133 217
134 // Static. 218 AutofillFieldType PhoneNumber::GetCityCodeType() const {
135 bool PhoneNumber::ParsePhoneNumber(const string16& value, 219 if (phone_group_ == AutofillType::PHONE_HOME)
136 string16* number, 220 return PHONE_HOME_CITY_CODE;
137 string16* city_code, 221 else if (phone_group_ == AutofillType::PHONE_FAX)
138 string16* country_code) { 222 return PHONE_FAX_CITY_CODE;
139 DCHECK(number); 223 else
140 DCHECK(city_code); 224 NOTREACHED();
141 DCHECK(country_code); 225 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 } 226 }
174 227
175 string16 PhoneNumber::WholeNumber() const { 228 AutofillFieldType PhoneNumber::GetCountryCodeType() const {
176 string16 whole_number; 229 if (phone_group_ == AutofillType::PHONE_HOME)
177 if (!country_code_.empty()) 230 return PHONE_HOME_COUNTRY_CODE;
178 whole_number.append(country_code_); 231 else if (phone_group_ == AutofillType::PHONE_FAX)
179 232 return PHONE_FAX_COUNTRY_CODE;
180 if (!city_code_.empty()) 233 else
181 whole_number.append(city_code_); 234 NOTREACHED();
182 235 return UNKNOWN_TYPE;
183 if (!number_.empty())
184 whole_number.append(number_);
185
186 return whole_number;
187 } 236 }
188 237
189 void PhoneNumber::set_number(const string16& number) { 238 AutofillFieldType PhoneNumber::GetCityAndNumberType() const {
190 string16 digits(number); 239 if (phone_group_ == AutofillType::PHONE_HOME)
191 StripPunctuation(&digits); 240 return PHONE_HOME_CITY_AND_NUMBER;
192 number_ = digits; 241 else if (phone_group_ == AutofillType::PHONE_FAX)
242 return PHONE_FAX_CITY_AND_NUMBER;
243 else
244 NOTREACHED();
245 return UNKNOWN_TYPE;
193 } 246 }
194 247
195 void PhoneNumber::set_whole_number(const string16& whole_number) { 248 AutofillFieldType PhoneNumber::GetWholeNumberType() const {
196 string16 number, city_code, country_code; 249 if (phone_group_ == AutofillType::PHONE_HOME)
197 ParsePhoneNumber(whole_number, &number, &city_code, &country_code); 250 return PHONE_HOME_WHOLE_NUMBER;
198 set_number(number); 251 else if (phone_group_ == AutofillType::PHONE_FAX)
199 set_city_code(city_code); 252 return PHONE_FAX_WHOLE_NUMBER;
200 set_country_code(country_code); 253 else
254 NOTREACHED();
255 return UNKNOWN_TYPE;
201 } 256 }
202 257
203 bool PhoneNumber::IsNumber(const string16& text) const { 258
204 // TODO(isherman): This will need to be updated once we add support for 259 void PhoneNumber::set_number(const string16& number) {
260 number_ = number;
261 }
262
263 bool PhoneNumber::IsNumber(const string16& text, const string16& number) const {
264 // TODO(georgey): This will need to be updated once we add support for
205 // international phone numbers. 265 // international phone numbers.
206 const size_t kPrefixLength = 3; 266 const size_t kPrefixLength = 3;
207 const size_t kSuffixLength = 4; 267 const size_t kSuffixLength = 4;
208 268
209 if (text == number_) 269 if (text == number)
210 return true; 270 return true;
211 if (text.length() == kPrefixLength && StartsWith(number_, text, true)) 271 if (text.length() == kPrefixLength && StartsWith(number, text, true))
212 return true; 272 return true;
213 if (text.length() == kSuffixLength && EndsWith(number_, text, true)) 273 if (text.length() == kSuffixLength && EndsWith(number, text, true))
214 return true; 274 return true;
215 275
216 return false; 276 return false;
217 } 277 }
218 278
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 { 279 bool PhoneNumber::IsWholeNumber(const string16& text) const {
232 return text == WholeNumber(); 280 return autofill_i18n::ComparePhones(text, number_, locale_) ==
233 } 281 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 } 282 }
243 283
244 // Static. 284 // Static.
245 void PhoneNumber::StripPunctuation(string16* number) { 285 void PhoneNumber::StripPunctuation(string16* number) {
246 RemoveChars(*number, kPhoneNumberSeparators, number); 286 RemoveChars(*number, kPhoneNumberSeparators, number);
247 } 287 }
288
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698