phone_number.cc revision 424c4d7b64af9d0d8fd9624f381f469654d5e3d2
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
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
68void PhoneNumber::GetSupportedTypes(ServerFieldTypeSet* supported_types) const {
69  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
76base::string16 PhoneNumber::GetRawInfo(ServerFieldType type) const {
77  DCHECK_EQ(PHONE_HOME, AutofillType(type).group());
78  if (type == PHONE_HOME_WHOLE_NUMBER)
79    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
87void PhoneNumber::SetRawInfo(ServerFieldType type,
88                             const base::string16& value) {
89  DCHECK_EQ(PHONE_HOME, AutofillType(type).group());
90  if (type != PHONE_HOME_CITY_AND_NUMBER && type != PHONE_HOME_WHOLE_NUMBER) {
91    // Only full phone numbers should be set directly.  The remaining field
92    // field types are read-only.
93    return;
94  }
95
96  number_ = value;
97
98  // Invalidate the cached number.
99  cached_parsed_phone_ = i18n::PhoneObject();
100}
101
102// Normalize phones if |type| is a whole number:
103//   (650)2345678 -> 6502345678
104//   1-800-FLOWERS -> 18003569377
105// If the phone cannot be normalized, returns the stored value verbatim.
106base::string16 PhoneNumber::GetInfo(const AutofillType& type,
107                                    const std::string& app_locale) const {
108  ServerFieldType storable_type = type.GetStorableType();
109  UpdateCacheIfNeeded(app_locale);
110
111  // Queries for whole numbers will return the non-normalized number if
112  // normalization for the number fails.  All other field types require
113  // normalization.
114  if (storable_type != PHONE_HOME_WHOLE_NUMBER &&
115      !cached_parsed_phone_.IsValidNumber())
116    return base::string16();
117
118  switch (storable_type) {
119    case PHONE_HOME_WHOLE_NUMBER:
120      return cached_parsed_phone_.GetWholeNumber();
121
122    case PHONE_HOME_NUMBER:
123      return cached_parsed_phone_.number();
124
125    case PHONE_HOME_CITY_CODE:
126      return cached_parsed_phone_.city_code();
127
128    case PHONE_HOME_COUNTRY_CODE:
129      return cached_parsed_phone_.country_code();
130
131    case PHONE_HOME_CITY_AND_NUMBER:
132      return
133          cached_parsed_phone_.city_code() + cached_parsed_phone_.number();
134
135    default:
136      NOTREACHED();
137      return base::string16();
138  }
139}
140
141bool PhoneNumber::SetInfo(const AutofillType& type,
142                          const base::string16& value,
143                          const std::string& app_locale) {
144  SetRawInfo(type.GetStorableType(), value);
145
146  if (number_.empty())
147    return true;
148
149  // Store a formatted (i.e., pretty printed) version of the number.
150  UpdateCacheIfNeeded(app_locale);
151  number_ = cached_parsed_phone_.GetFormattedNumber();
152  return !number_.empty();
153}
154
155void PhoneNumber::GetMatchingTypes(const base::string16& text,
156                                   const std::string& app_locale,
157                                   ServerFieldTypeSet* matching_types) const {
158  base::string16 stripped_text = text;
159  StripPunctuation(&stripped_text);
160  FormGroup::GetMatchingTypes(stripped_text, app_locale, matching_types);
161
162  // For US numbers, also compare to the three-digit prefix and the four-digit
163  // suffix, since web sites often split numbers into these two fields.
164  base::string16 number = GetInfo(AutofillType(PHONE_HOME_NUMBER), app_locale);
165  if (GetRegion(*profile_, app_locale) == "US" &&
166      number.size() == (kPrefixLength + kSuffixLength)) {
167    base::string16 prefix = number.substr(kPrefixOffset, kPrefixLength);
168    base::string16 suffix = number.substr(kSuffixOffset, kSuffixLength);
169    if (text == prefix || text == suffix)
170      matching_types->insert(PHONE_HOME_NUMBER);
171  }
172
173  base::string16 whole_number =
174      GetInfo(AutofillType(PHONE_HOME_WHOLE_NUMBER), app_locale);
175  if (!whole_number.empty()) {
176    base::string16 normalized_number =
177        i18n::NormalizePhoneNumber(text, GetRegion(*profile_, app_locale));
178    if (normalized_number == whole_number)
179      matching_types->insert(PHONE_HOME_WHOLE_NUMBER);
180  }
181}
182
183void PhoneNumber::UpdateCacheIfNeeded(const std::string& app_locale) const {
184  std::string region = GetRegion(*profile_, app_locale);
185  if (!number_.empty() && cached_parsed_phone_.region() != region)
186    cached_parsed_phone_ = i18n::PhoneObject(number_, region);
187}
188
189PhoneNumber::PhoneCombineHelper::PhoneCombineHelper() {
190}
191
192PhoneNumber::PhoneCombineHelper::~PhoneCombineHelper() {
193}
194
195bool PhoneNumber::PhoneCombineHelper::SetInfo(const AutofillType& type,
196                                              const base::string16& value) {
197  ServerFieldType storable_type = type.GetStorableType();
198  if (storable_type == PHONE_HOME_COUNTRY_CODE) {
199    country_ = value;
200    return true;
201  }
202
203  if (storable_type == PHONE_HOME_CITY_CODE) {
204    city_ = value;
205    return true;
206  }
207
208  if (storable_type == PHONE_HOME_CITY_AND_NUMBER) {
209    phone_ = value;
210    return true;
211  }
212
213  if (storable_type == PHONE_HOME_WHOLE_NUMBER) {
214    whole_number_ = value;
215    return true;
216  }
217
218  if (storable_type == PHONE_HOME_NUMBER) {
219    phone_.append(value);
220    return true;
221  }
222
223  return false;
224}
225
226bool PhoneNumber::PhoneCombineHelper::ParseNumber(
227    const AutofillProfile& profile,
228    const std::string& app_locale,
229    base::string16* value) {
230  if (IsEmpty())
231    return false;
232
233  if (!whole_number_.empty()) {
234    *value = whole_number_;
235    return true;
236  }
237
238  return i18n::ConstructPhoneNumber(
239      country_, city_, phone_, GetRegion(profile, app_locale), value);
240}
241
242bool PhoneNumber::PhoneCombineHelper::IsEmpty() const {
243  return phone_.empty() && whole_number_.empty();
244}
245
246}  // namespace autofill
247