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

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 phone_group_ = number.phone_group_;
50 return *this; 57 return *this;
51 } 58 }
52 59
53 void PhoneNumber::GetMatchingTypes(const string16& text, 60 void PhoneNumber::GetMatchingTypes(const string16& text,
54 FieldTypeSet* matching_types) const { 61 FieldTypeSet* matching_types) const {
55 string16 stripped_text(text); 62 string16 stripped_text(text);
56 StripPunctuation(&stripped_text); 63 StripPunctuation(&stripped_text);
57 if (!Validate(stripped_text)) 64
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))
58 return; 71 return;
59 72
60 if (IsNumber(stripped_text)) 73 if (IsNumber(stripped_text, number))
61 matching_types->insert(GetNumberType()); 74 matching_types->insert(GetNumberType());
62 75
63 if (IsCityCode(stripped_text)) 76 if (stripped_text == city_code)
64 matching_types->insert(GetCityCodeType()); 77 matching_types->insert(GetCityCodeType());
65 78
66 if (IsCountryCode(stripped_text)) 79 if (stripped_text == country_code)
67 matching_types->insert(GetCountryCodeType()); 80 matching_types->insert(GetCountryCodeType());
68 81
69 if (IsCityAndNumber(stripped_text)) 82 city_code.append(number);
83 if (stripped_text == city_code)
70 matching_types->insert(GetCityAndNumberType()); 84 matching_types->insert(GetCityAndNumberType());
71 85
72 if (IsWholeNumber(stripped_text)) 86 // 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))
73 matching_types->insert(GetWholeNumberType()); 89 matching_types->insert(GetWholeNumberType());
74 } 90 }
75 91
76 void PhoneNumber::GetNonEmptyTypes(FieldTypeSet* non_empty_typess) const { 92 void PhoneNumber::GetNonEmptyTypes(FieldTypeSet* non_empty_types) const {
77 DCHECK(non_empty_typess); 93 DCHECK(non_empty_types);
78 94
79 if (!number().empty()) 95 if (number_.empty())
80 non_empty_typess->insert(GetNumberType()); 96 return;
81 97
82 if (!city_code().empty()) 98 non_empty_types->insert(GetWholeNumberType());
83 non_empty_typess->insert(GetCityCodeType()); 99
84 100 string16 number;
85 if (!country_code().empty()) 101 string16 city_code;
86 non_empty_typess->insert(GetCountryCodeType()); 102 string16 country_code;
87 103 // Full number - parse it, split it and re-combine into canonical form.
88 if (!CityAndNumber().empty()) 104 if (!autofill_i18n::ParsePhoneNumber(
89 non_empty_typess->insert(GetCityAndNumberType()); 105 number_, locale_, &country_code, &city_code, &number))
90 106 return;
91 if (!WholeNumber().empty()) 107
92 non_empty_typess->insert(GetWholeNumberType()); 108 non_empty_types->insert(GetNumberType());
109
110 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());
93 } 117 }
94 118
95 string16 PhoneNumber::GetInfo(AutofillFieldType type) const { 119 string16 PhoneNumber::GetInfo(AutofillFieldType type) const {
120 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
96 if (type == GetNumberType()) 131 if (type == GetNumberType())
97 return number(); 132 return number;
98 133
99 if (type == GetCityCodeType()) 134 if (type == GetCityCodeType())
100 return city_code(); 135 return city_code;
101 136
102 if (type == GetCountryCodeType()) 137 if (type == GetCountryCodeType())
103 return country_code(); 138 return country_code;
104 139
140 city_code.append(number);
105 if (type == GetCityAndNumberType()) 141 if (type == GetCityAndNumberType())
106 return CityAndNumber(); 142 return city_code;
107
108 if (type == GetWholeNumberType())
109 return WholeNumber();
110 143
111 return string16(); 144 return string16();
112 } 145 }
113 146
114 void PhoneNumber::SetInfo(AutofillFieldType type, const string16& value) { 147 void PhoneNumber::SetInfo(AutofillFieldType type, const string16& value) {
115 string16 number(value);
116 StripPunctuation(&number);
117 if (!Validate(number))
118 return;
119
120 FieldTypeSubGroup subgroup = AutofillType(type).subgroup(); 148 FieldTypeSubGroup subgroup = AutofillType(type).subgroup();
121 if (subgroup == AutofillType::PHONE_NUMBER) 149 FieldTypeGroup group = AutofillType(type).group();
122 set_number(number); 150 if (phone_group_ == AutofillType::NO_GROUP)
123 else if (subgroup == AutofillType::PHONE_CITY_CODE) 151 phone_group_ = group; // First call on empty phone - set the group.
124 set_city_code(number); 152 if (subgroup == AutofillType::PHONE_NUMBER) {
125 else if (subgroup == AutofillType::PHONE_COUNTRY_CODE) 153 // Should not be set directly.
126 set_country_code(number); 154 NOTREACHED();
127 else if (subgroup == AutofillType::PHONE_CITY_AND_NUMBER || 155 } else if (subgroup == AutofillType::PHONE_CITY_CODE) {
128 subgroup == AutofillType::PHONE_WHOLE_NUMBER) 156 // Should not be set directly.
129 set_whole_number(number); 157 NOTREACHED();
130 else 158 } else if (subgroup == AutofillType::PHONE_COUNTRY_CODE) {
131 NOTREACHED(); 159 // Should not be set directly.
132 } 160 NOTREACHED();
133 161 } else if (subgroup == AutofillType::PHONE_CITY_AND_NUMBER ||
134 // Static. 162 subgroup == AutofillType::PHONE_WHOLE_NUMBER) {
135 bool PhoneNumber::ParsePhoneNumber(const string16& value, 163 number_ = value;
136 string16* number, 164 StripPunctuation(&number_);
137 string16* city_code, 165 } else {
138 string16* country_code) { 166 NOTREACHED();
139 DCHECK(number); 167 }
140 DCHECK(city_code); 168 }
141 DCHECK(country_code); 169
142 170 bool PhoneNumber::NormalizePhone() {
143 // Make a working copy of value. 171 bool success = true;
144 string16 working = value; 172 // Empty number does not need normalization.
145 173 if (number_.empty())
146 *number = string16(); 174 return true;
147 *city_code = string16(); 175
148 *country_code = string16(); 176 string16 number;
149 177 string16 city_code;
150 // First remove any punctuation. 178 string16 country_code;
151 StripPunctuation(&working); 179 // Full number - parse it, split it and re-combine into canonical form.
152 180 if (!autofill_i18n::ParsePhoneNumber(
153 if (working.size() < kPhoneNumberLength) 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
196 void PhoneNumber::set_locale(const std::string& locale) {
197 locale_ = locale;
198 }
199
200 AutofillFieldType 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;
205 else
206 NOTREACHED();
207 return UNKNOWN_TYPE;
208 }
209
210 AutofillFieldType 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 }
219
220 AutofillFieldType 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 }
229
230 AutofillFieldType 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 }
239
240 AutofillFieldType 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 }
249
250 bool 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 {
154 return false; 267 return false;
155 268 }
156 // Treat the last 7 digits as the number. 269 }
157 *number = working.substr(working.size() - kPhoneNumberLength, 270
158 kPhoneNumberLength); 271 bool PhoneNumber::PhoneCombineHelper::ParseNumber(const std::string& locale,
159 working.resize(working.size() - kPhoneNumberLength); 272 string16* value) {
160 if (working.size() < kPhoneCityCodeLength) 273 DCHECK(value);
161 return true; 274 return autofill_i18n::ConstructPhoneNumber(
162 275 country_, city_, phone_,
163 // Treat the next three digits as the city code. 276 locale,
164 *city_code = working.substr(working.size() - kPhoneCityCodeLength, 277 (country_.empty() ?
165 kPhoneCityCodeLength); 278 autofill_i18n::NATIONAL : autofill_i18n::INTERNATIONAL),
166 working.resize(working.size() - kPhoneCityCodeLength); 279 value);
167 if (working.empty()) 280 }
168 return true; 281
169 282 bool PhoneNumber::IsNumber(const string16& text, const string16& number) const {
170 // Treat any remaining digits as the country code. 283 // TODO(georgey): This will need to be updated once we add support for
171 *country_code = working;
172 return true;
173 }
174
175 string16 PhoneNumber::WholeNumber() const {
176 string16 whole_number;
177 if (!country_code_.empty())
178 whole_number.append(country_code_);
179
180 if (!city_code_.empty())
181 whole_number.append(city_code_);
182
183 if (!number_.empty())
184 whole_number.append(number_);
185
186 return whole_number;
187 }
188
189 void PhoneNumber::set_number(const string16& number) {
190 string16 digits(number);
191 StripPunctuation(&digits);
192 number_ = digits;
193 }
194
195 void PhoneNumber::set_whole_number(const string16& whole_number) {
196 string16 number, city_code, country_code;
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. 284 // international phone numbers.
206 const size_t kPrefixLength = 3; 285 const size_t kPrefixLength = 3;
207 const size_t kSuffixLength = 4; 286 const size_t kSuffixLength = 4;
208 287
209 if (text == number_) 288 if (text == number)
210 return true; 289 return true;
211 if (text.length() == kPrefixLength && StartsWith(number_, text, true)) 290 if (text.length() == kPrefixLength && StartsWith(number, text, true))
212 return true; 291 return true;
213 if (text.length() == kSuffixLength && EndsWith(number_, text, true)) 292 if (text.length() == kSuffixLength && EndsWith(number, text, true))
214 return true; 293 return true;
215 294
216 return false; 295 return false;
217 } 296 }
218 297
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 { 298 bool PhoneNumber::IsWholeNumber(const string16& text) const {
232 return text == WholeNumber(); 299 return autofill_i18n::ComparePhones(text, number_, locale_) ==
233 } 300 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 } 301 }
243 302
244 // Static. 303 // Static.
245 void PhoneNumber::StripPunctuation(string16* number) { 304 void PhoneNumber::StripPunctuation(string16* number) {
246 RemoveChars(*number, kPhoneNumberSeparators, number); 305 RemoveChars(*number, kPhoneNumberSeparators, number);
247 } 306 }
307
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