OLD | NEW |
| (Empty) |
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 | |
3 // found in the LICENSE file. | |
4 | |
5 #include "chrome/browser/autofill/phone_number.h" | |
6 | |
7 #include "base/basictypes.h" | |
8 #include "base/string_util.h" | |
9 #include "base/strings/string_number_conversions.h" | |
10 #include "base/utf_string_conversions.h" | |
11 #include "chrome/browser/autofill/autofill_country.h" | |
12 #include "chrome/browser/autofill/autofill_profile.h" | |
13 #include "chrome/browser/autofill/autofill_type.h" | |
14 #include "chrome/browser/autofill/field_types.h" | |
15 #include "chrome/browser/autofill/phone_number_i18n.h" | |
16 | |
17 namespace { | |
18 | |
19 const char16 kPhoneNumberSeparators[] = { ' ', '.', '(', ')', '-', 0 }; | |
20 | |
21 // The number of digits in a phone number. | |
22 const size_t kPhoneNumberLength = 7; | |
23 | |
24 // The number of digits in an area code. | |
25 const size_t kPhoneCityCodeLength = 3; | |
26 | |
27 void StripPunctuation(string16* number) { | |
28 RemoveChars(*number, kPhoneNumberSeparators, number); | |
29 } | |
30 | |
31 // Returns the region code for this phone number, which is an ISO 3166 2-letter | |
32 // country code. The returned value is based on the |profile|; if the |profile| | |
33 // does not have a country code associated with it, falls back to the country | |
34 // code corresponding to the |app_locale|. | |
35 std::string GetRegion(const AutofillProfile& profile, | |
36 const std::string& app_locale) { | |
37 std::string country_code = profile.CountryCode(); | |
38 if (!country_code.empty()) | |
39 return country_code; | |
40 | |
41 return AutofillCountry::CountryCodeForLocale(app_locale); | |
42 } | |
43 | |
44 } // namespace | |
45 | |
46 PhoneNumber::PhoneNumber(AutofillProfile* profile) | |
47 : profile_(profile) { | |
48 } | |
49 | |
50 PhoneNumber::PhoneNumber(const PhoneNumber& number) | |
51 : profile_(NULL) { | |
52 *this = number; | |
53 } | |
54 | |
55 PhoneNumber::~PhoneNumber() {} | |
56 | |
57 PhoneNumber& PhoneNumber::operator=(const PhoneNumber& number) { | |
58 if (this == &number) | |
59 return *this; | |
60 | |
61 number_ = number.number_; | |
62 profile_ = number.profile_; | |
63 cached_parsed_phone_ = number.cached_parsed_phone_; | |
64 return *this; | |
65 } | |
66 | |
67 void PhoneNumber::GetSupportedTypes(FieldTypeSet* supported_types) const { | |
68 supported_types->insert(PHONE_HOME_WHOLE_NUMBER); | |
69 supported_types->insert(PHONE_HOME_NUMBER); | |
70 supported_types->insert(PHONE_HOME_CITY_CODE); | |
71 supported_types->insert(PHONE_HOME_CITY_AND_NUMBER); | |
72 supported_types->insert(PHONE_HOME_COUNTRY_CODE); | |
73 } | |
74 | |
75 string16 PhoneNumber::GetRawInfo(AutofillFieldType type) const { | |
76 if (type == PHONE_HOME_WHOLE_NUMBER) | |
77 return number_; | |
78 | |
79 // Only the whole number is available as raw data. All of the other types are | |
80 // parsed from this raw info, and parsing requires knowledge of the phone | |
81 // number's region, which is only available via GetInfo(). | |
82 return string16(); | |
83 } | |
84 | |
85 void PhoneNumber::SetRawInfo(AutofillFieldType type, const string16& value) { | |
86 if (type != PHONE_HOME_CITY_AND_NUMBER && | |
87 type != PHONE_HOME_WHOLE_NUMBER) { | |
88 // Only full phone numbers should be set directly. The remaining field | |
89 // field types are read-only. | |
90 return; | |
91 } | |
92 | |
93 number_ = value; | |
94 | |
95 // Invalidate the cached number. | |
96 cached_parsed_phone_ = autofill_i18n::PhoneObject(); | |
97 } | |
98 | |
99 // Normalize phones if |type| is a whole number: | |
100 // (650)2345678 -> 6502345678 | |
101 // 1-800-FLOWERS -> 18003569377 | |
102 // If the phone cannot be normalized, returns the stored value verbatim. | |
103 string16 PhoneNumber::GetInfo(AutofillFieldType type, | |
104 const std::string& app_locale) const { | |
105 UpdateCacheIfNeeded(app_locale); | |
106 | |
107 // Queries for whole numbers will return the non-normalized number if | |
108 // normalization for the number fails. All other field types require | |
109 // normalization. | |
110 if (type != PHONE_HOME_WHOLE_NUMBER && !cached_parsed_phone_.IsValidNumber()) | |
111 return string16(); | |
112 | |
113 switch (type) { | |
114 case PHONE_HOME_WHOLE_NUMBER: | |
115 return cached_parsed_phone_.GetWholeNumber(); | |
116 | |
117 case PHONE_HOME_NUMBER: | |
118 return cached_parsed_phone_.number(); | |
119 | |
120 case PHONE_HOME_CITY_CODE: | |
121 return cached_parsed_phone_.city_code(); | |
122 | |
123 case PHONE_HOME_COUNTRY_CODE: | |
124 return cached_parsed_phone_.country_code(); | |
125 | |
126 case PHONE_HOME_CITY_AND_NUMBER: | |
127 return | |
128 cached_parsed_phone_.city_code() + cached_parsed_phone_.number(); | |
129 | |
130 default: | |
131 NOTREACHED(); | |
132 return string16(); | |
133 } | |
134 } | |
135 | |
136 bool PhoneNumber::SetInfo(AutofillFieldType type, | |
137 const string16& value, | |
138 const std::string& app_locale) { | |
139 SetRawInfo(type, value); | |
140 | |
141 if (number_.empty()) | |
142 return true; | |
143 | |
144 // Store a formatted (i.e., pretty printed) version of the number. | |
145 UpdateCacheIfNeeded(app_locale); | |
146 number_ = cached_parsed_phone_.GetFormattedNumber(); | |
147 return !number_.empty(); | |
148 } | |
149 | |
150 void PhoneNumber::GetMatchingTypes(const string16& text, | |
151 const std::string& app_locale, | |
152 FieldTypeSet* matching_types) const { | |
153 string16 stripped_text = text; | |
154 StripPunctuation(&stripped_text); | |
155 FormGroup::GetMatchingTypes(stripped_text, app_locale, matching_types); | |
156 | |
157 // For US numbers, also compare to the three-digit prefix and the four-digit | |
158 // suffix, since web sites often split numbers into these two fields. | |
159 string16 number = GetInfo(PHONE_HOME_NUMBER, app_locale); | |
160 if (GetRegion(*profile_, app_locale) == "US" && | |
161 number.size() == (kPrefixLength + kSuffixLength)) { | |
162 string16 prefix = number.substr(kPrefixOffset, kPrefixLength); | |
163 string16 suffix = number.substr(kSuffixOffset, kSuffixLength); | |
164 if (text == prefix || text == suffix) | |
165 matching_types->insert(PHONE_HOME_NUMBER); | |
166 } | |
167 | |
168 string16 whole_number = GetInfo(PHONE_HOME_WHOLE_NUMBER, app_locale); | |
169 if (!whole_number.empty()) { | |
170 string16 normalized_number = | |
171 autofill_i18n::NormalizePhoneNumber(text, | |
172 GetRegion(*profile_, app_locale)); | |
173 if (normalized_number == whole_number) | |
174 matching_types->insert(PHONE_HOME_WHOLE_NUMBER); | |
175 } | |
176 } | |
177 | |
178 void PhoneNumber::UpdateCacheIfNeeded(const std::string& app_locale) const { | |
179 std::string region = GetRegion(*profile_, app_locale); | |
180 if (!number_.empty() && cached_parsed_phone_.region() != region) | |
181 cached_parsed_phone_ = autofill_i18n::PhoneObject(number_, region); | |
182 } | |
183 | |
184 PhoneNumber::PhoneCombineHelper::PhoneCombineHelper() { | |
185 } | |
186 | |
187 PhoneNumber::PhoneCombineHelper::~PhoneCombineHelper() { | |
188 } | |
189 | |
190 bool PhoneNumber::PhoneCombineHelper::SetInfo(AutofillFieldType field_type, | |
191 const string16& value) { | |
192 if (field_type == PHONE_HOME_COUNTRY_CODE) { | |
193 country_ = value; | |
194 return true; | |
195 } | |
196 | |
197 if (field_type == PHONE_HOME_CITY_CODE) { | |
198 city_ = value; | |
199 return true; | |
200 } | |
201 | |
202 if (field_type == PHONE_HOME_CITY_AND_NUMBER) { | |
203 phone_ = value; | |
204 return true; | |
205 } | |
206 | |
207 if (field_type == PHONE_HOME_WHOLE_NUMBER) { | |
208 whole_number_ = value; | |
209 return true; | |
210 } | |
211 | |
212 if (field_type == PHONE_HOME_NUMBER) { | |
213 phone_.append(value); | |
214 return true; | |
215 } | |
216 | |
217 return false; | |
218 } | |
219 | |
220 bool PhoneNumber::PhoneCombineHelper::ParseNumber( | |
221 const AutofillProfile& profile, | |
222 const std::string& app_locale, | |
223 string16* value) { | |
224 if (IsEmpty()) | |
225 return false; | |
226 | |
227 if (!whole_number_.empty()) { | |
228 *value = whole_number_; | |
229 return true; | |
230 } | |
231 | |
232 return autofill_i18n::ConstructPhoneNumber( | |
233 country_, city_, phone_, GetRegion(profile, app_locale), value); | |
234 } | |
235 | |
236 bool PhoneNumber::PhoneCombineHelper::IsEmpty() const { | |
237 return phone_.empty() && whole_number_.empty(); | |
238 } | |
OLD | NEW |