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