blob: 2ee67f98b72e732957b41dab4ff7110ca0f5d850 [file] [log] [blame]
Ben Murdocheb525c52013-07-10 11:40:50 +01001// Copyright 2013 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 "components/autofill/core/browser/phone_number.h"
6
7#include "base/basictypes.h"
8#include "base/strings/string_number_conversions.h"
9#include "base/strings/string_util.h"
10#include "base/strings/utf_string_conversions.h"
11#include "components/autofill/core/browser/autofill_country.h"
12#include "components/autofill/core/browser/autofill_profile.h"
13#include "components/autofill/core/browser/autofill_type.h"
14#include "components/autofill/core/browser/field_types.h"
15#include "components/autofill/core/browser/phone_number_i18n.h"
16
17namespace autofill {
18namespace {
19
20const char16 kPhoneNumberSeparators[] = { ' ', '.', '(', ')', '-', 0 };
21
22// The number of digits in a phone number.
23const size_t kPhoneNumberLength = 7;
24
25// The number of digits in an area code.
26const size_t kPhoneCityCodeLength = 3;
27
28void StripPunctuation(base::string16* number) {
29 RemoveChars(*number, kPhoneNumberSeparators, number);
30}
31
32// Returns the region code for this phone number, which is an ISO 3166 2-letter
33// country code. The returned value is based on the |profile|; if the |profile|
34// does not have a country code associated with it, falls back to the country
35// code corresponding to the |app_locale|.
36std::string GetRegion(const AutofillProfile& profile,
37 const std::string& app_locale) {
38 base::string16 country_code = profile.GetRawInfo(ADDRESS_HOME_COUNTRY);
39 if (!country_code.empty())
40 return UTF16ToASCII(country_code);
41
42 return AutofillCountry::CountryCodeForLocale(app_locale);
43}
44
45} // namespace
46
47PhoneNumber::PhoneNumber(AutofillProfile* profile)
48 : profile_(profile) {
49}
50
51PhoneNumber::PhoneNumber(const PhoneNumber& number)
52 : profile_(NULL) {
53 *this = number;
54}
55
56PhoneNumber::~PhoneNumber() {}
57
58PhoneNumber& PhoneNumber::operator=(const PhoneNumber& number) {
59 if (this == &number)
60 return *this;
61
62 number_ = number.number_;
63 profile_ = number.profile_;
64 cached_parsed_phone_ = number.cached_parsed_phone_;
65 return *this;
66}
67
Ben Murdoch32409262013-08-07 11:04:47 +010068void PhoneNumber::GetSupportedTypes(ServerFieldTypeSet* supported_types) const {
Ben Murdocheb525c52013-07-10 11:40:50 +010069 supported_types->insert(PHONE_HOME_WHOLE_NUMBER);
70 supported_types->insert(PHONE_HOME_NUMBER);
71 supported_types->insert(PHONE_HOME_CITY_CODE);
72 supported_types->insert(PHONE_HOME_CITY_AND_NUMBER);
73 supported_types->insert(PHONE_HOME_COUNTRY_CODE);
74}
75
Ben Murdoch32409262013-08-07 11:04:47 +010076base::string16 PhoneNumber::GetRawInfo(ServerFieldType type) const {
Ben Murdochbb1529c2013-08-08 10:24:53 +010077 // TODO(isherman): Is GetStorableType even necessary?
78 if (AutofillType(type).GetStorableType() == PHONE_HOME_WHOLE_NUMBER)
Ben Murdocheb525c52013-07-10 11:40:50 +010079 return number_;
80
81 // Only the whole number is available as raw data. All of the other types are
82 // parsed from this raw info, and parsing requires knowledge of the phone
83 // number's region, which is only available via GetInfo().
84 return base::string16();
85}
86
Ben Murdoch32409262013-08-07 11:04:47 +010087void PhoneNumber::SetRawInfo(ServerFieldType type,
Ben Murdocheb525c52013-07-10 11:40:50 +010088 const base::string16& value) {
Ben Murdochbb1529c2013-08-08 10:24:53 +010089 // TODO(isherman): Is GetStorableType even necessary?
90 type = AutofillType(type).GetStorableType();
91 if (type != PHONE_HOME_CITY_AND_NUMBER && type != PHONE_HOME_WHOLE_NUMBER) {
Ben Murdocheb525c52013-07-10 11:40:50 +010092 // Only full phone numbers should be set directly. The remaining field
93 // field types are read-only.
94 return;
95 }
96
97 number_ = value;
98
99 // Invalidate the cached number.
100 cached_parsed_phone_ = i18n::PhoneObject();
101}
102
103// Normalize phones if |type| is a whole number:
104// (650)2345678 -> 6502345678
105// 1-800-FLOWERS -> 18003569377
106// If the phone cannot be normalized, returns the stored value verbatim.
Ben Murdoch32409262013-08-07 11:04:47 +0100107base::string16 PhoneNumber::GetInfo(const AutofillType& type,
Ben Murdocheb525c52013-07-10 11:40:50 +0100108 const std::string& app_locale) const {
Ben Murdochbb1529c2013-08-08 10:24:53 +0100109 ServerFieldType storable_type = type.GetStorableType();
Ben Murdocheb525c52013-07-10 11:40:50 +0100110 UpdateCacheIfNeeded(app_locale);
111
112 // Queries for whole numbers will return the non-normalized number if
113 // normalization for the number fails. All other field types require
114 // normalization.
Ben Murdochbb1529c2013-08-08 10:24:53 +0100115 if (storable_type != PHONE_HOME_WHOLE_NUMBER &&
Ben Murdoch32409262013-08-07 11:04:47 +0100116 !cached_parsed_phone_.IsValidNumber())
Ben Murdocheb525c52013-07-10 11:40:50 +0100117 return base::string16();
118
Ben Murdochbb1529c2013-08-08 10:24:53 +0100119 switch (storable_type) {
Ben Murdocheb525c52013-07-10 11:40:50 +0100120 case PHONE_HOME_WHOLE_NUMBER:
121 return cached_parsed_phone_.GetWholeNumber();
122
123 case PHONE_HOME_NUMBER:
124 return cached_parsed_phone_.number();
125
126 case PHONE_HOME_CITY_CODE:
127 return cached_parsed_phone_.city_code();
128
129 case PHONE_HOME_COUNTRY_CODE:
130 return cached_parsed_phone_.country_code();
131
132 case PHONE_HOME_CITY_AND_NUMBER:
133 return
134 cached_parsed_phone_.city_code() + cached_parsed_phone_.number();
135
136 default:
137 NOTREACHED();
138 return base::string16();
139 }
140}
141
Ben Murdoch32409262013-08-07 11:04:47 +0100142bool PhoneNumber::SetInfo(const AutofillType& type,
Ben Murdocheb525c52013-07-10 11:40:50 +0100143 const base::string16& value,
144 const std::string& app_locale) {
Ben Murdochbb1529c2013-08-08 10:24:53 +0100145 SetRawInfo(type.GetStorableType(), value);
Ben Murdocheb525c52013-07-10 11:40:50 +0100146
147 if (number_.empty())
148 return true;
149
150 // Store a formatted (i.e., pretty printed) version of the number.
151 UpdateCacheIfNeeded(app_locale);
152 number_ = cached_parsed_phone_.GetFormattedNumber();
153 return !number_.empty();
154}
155
156void PhoneNumber::GetMatchingTypes(const base::string16& text,
157 const std::string& app_locale,
Ben Murdoch32409262013-08-07 11:04:47 +0100158 ServerFieldTypeSet* matching_types) const {
Ben Murdocheb525c52013-07-10 11:40:50 +0100159 base::string16 stripped_text = text;
160 StripPunctuation(&stripped_text);
161 FormGroup::GetMatchingTypes(stripped_text, app_locale, matching_types);
162
163 // For US numbers, also compare to the three-digit prefix and the four-digit
164 // suffix, since web sites often split numbers into these two fields.
Ben Murdoch32409262013-08-07 11:04:47 +0100165 base::string16 number = GetInfo(AutofillType(PHONE_HOME_NUMBER), app_locale);
Ben Murdocheb525c52013-07-10 11:40:50 +0100166 if (GetRegion(*profile_, app_locale) == "US" &&
167 number.size() == (kPrefixLength + kSuffixLength)) {
168 base::string16 prefix = number.substr(kPrefixOffset, kPrefixLength);
169 base::string16 suffix = number.substr(kSuffixOffset, kSuffixLength);
170 if (text == prefix || text == suffix)
171 matching_types->insert(PHONE_HOME_NUMBER);
172 }
173
Ben Murdoch32409262013-08-07 11:04:47 +0100174 base::string16 whole_number =
175 GetInfo(AutofillType(PHONE_HOME_WHOLE_NUMBER), app_locale);
Ben Murdocheb525c52013-07-10 11:40:50 +0100176 if (!whole_number.empty()) {
177 base::string16 normalized_number =
178 i18n::NormalizePhoneNumber(text, GetRegion(*profile_, app_locale));
179 if (normalized_number == whole_number)
180 matching_types->insert(PHONE_HOME_WHOLE_NUMBER);
181 }
182}
183
184void PhoneNumber::UpdateCacheIfNeeded(const std::string& app_locale) const {
185 std::string region = GetRegion(*profile_, app_locale);
186 if (!number_.empty() && cached_parsed_phone_.region() != region)
187 cached_parsed_phone_ = i18n::PhoneObject(number_, region);
188}
189
190PhoneNumber::PhoneCombineHelper::PhoneCombineHelper() {
191}
192
193PhoneNumber::PhoneCombineHelper::~PhoneCombineHelper() {
194}
195
Ben Murdochbb1529c2013-08-08 10:24:53 +0100196bool PhoneNumber::PhoneCombineHelper::SetInfo(const AutofillType& type,
Ben Murdocheb525c52013-07-10 11:40:50 +0100197 const base::string16& value) {
Ben Murdochbb1529c2013-08-08 10:24:53 +0100198 ServerFieldType storable_type = type.GetStorableType();
199 if (storable_type == PHONE_HOME_COUNTRY_CODE) {
Ben Murdocheb525c52013-07-10 11:40:50 +0100200 country_ = value;
201 return true;
202 }
203
Ben Murdochbb1529c2013-08-08 10:24:53 +0100204 if (storable_type == PHONE_HOME_CITY_CODE) {
Ben Murdocheb525c52013-07-10 11:40:50 +0100205 city_ = value;
206 return true;
207 }
208
Ben Murdochbb1529c2013-08-08 10:24:53 +0100209 if (storable_type == PHONE_HOME_CITY_AND_NUMBER) {
Ben Murdocheb525c52013-07-10 11:40:50 +0100210 phone_ = value;
211 return true;
212 }
213
Ben Murdochbb1529c2013-08-08 10:24:53 +0100214 if (storable_type == PHONE_HOME_WHOLE_NUMBER) {
Ben Murdocheb525c52013-07-10 11:40:50 +0100215 whole_number_ = value;
216 return true;
217 }
218
Ben Murdochbb1529c2013-08-08 10:24:53 +0100219 if (storable_type == PHONE_HOME_NUMBER) {
Ben Murdocheb525c52013-07-10 11:40:50 +0100220 phone_.append(value);
221 return true;
222 }
223
224 return false;
225}
226
227bool PhoneNumber::PhoneCombineHelper::ParseNumber(
228 const AutofillProfile& profile,
229 const std::string& app_locale,
230 base::string16* value) {
231 if (IsEmpty())
232 return false;
233
234 if (!whole_number_.empty()) {
235 *value = whole_number_;
236 return true;
237 }
238
239 return i18n::ConstructPhoneNumber(
240 country_, city_, phone_, GetRegion(profile, app_locale), value);
241}
242
243bool PhoneNumber::PhoneCombineHelper::IsEmpty() const {
244 return phone_.empty() && whole_number_.empty();
245}
246
247} // namespace autofill