autofill_dialog_i18n_input.cc revision 0529e5d033099cbfc42635f6f6183833b09dff6e
1// Copyright 2014 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/ui/autofill/autofill_dialog_i18n_input.h"
6
7#include "base/strings/string_split.h"
8#include "base/strings/utf_string_conversions.h"
9#include "chrome/browser/browser_process.h"
10#include "components/autofill/core/browser/autofill_profile.h"
11#include "components/autofill/core/browser/credit_card.h"
12#include "components/autofill/core/browser/field_types.h"
13#include "grit/component_strings.h"
14#include "third_party/libaddressinput/chromium/cpp/include/libaddressinput/address_data.h"
15#include "third_party/libaddressinput/chromium/cpp/include/libaddressinput/address_field.h"
16#include "third_party/libaddressinput/chromium/cpp/include/libaddressinput/address_ui.h"
17#include "third_party/libaddressinput/chromium/cpp/include/libaddressinput/address_ui_component.h"
18#include "ui/base/l10n/l10n_util.h"
19
20namespace autofill {
21namespace i18ninput {
22
23namespace {
24
25using base::UTF16ToUTF8;
26using ::i18n::addressinput::AddressData;
27using ::i18n::addressinput::AddressField;
28using ::i18n::addressinput::AddressUiComponent;
29
30DetailInput::Length LengthFromHint(AddressUiComponent::LengthHint hint) {
31  if (hint == AddressUiComponent::HINT_SHORT)
32    return DetailInput::SHORT;
33  DCHECK_EQ(hint, AddressUiComponent::HINT_LONG);
34  return DetailInput::LONG;
35}
36
37}  // namespace
38
39void BuildAddressInputs(common::AddressType address_type,
40                        const std::string& country_code,
41                        DetailInputs* inputs,
42                        std::string* language_code) {
43  std::vector<AddressUiComponent> components(
44      ::i18n::addressinput::BuildComponents(
45          country_code, g_browser_process->GetApplicationLocale(),
46          language_code));
47
48  const bool billing = address_type == common::ADDRESS_TYPE_BILLING;
49
50  for (size_t i = 0; i < components.size(); ++i) {
51    const AddressUiComponent& component = components[i];
52    if (component.field == ::i18n::addressinput::ORGANIZATION) {
53      // TODO(dbeam): figure out when we actually need this.
54      continue;
55    }
56
57    ServerFieldType server_type = TypeForField(component.field, address_type);
58    DetailInput::Length length = LengthFromHint(component.length_hint);
59    base::string16 placeholder = l10n_util::GetStringUTF16(component.name_id);
60    DetailInput input = { length, server_type, placeholder };
61    inputs->push_back(input);
62
63#if defined(OS_ANDROID)
64    if (component.field == ::i18n::addressinput::STREET_ADDRESS &&
65        component.length_hint == AddressUiComponent::HINT_LONG) {
66      // TODO(dbeam): support more than 2 address lines. http://crbug.com/324889
67      ServerFieldType server_type =
68          billing ? ADDRESS_BILLING_LINE2 : ADDRESS_HOME_LINE2;
69      base::string16 placeholder = l10n_util::GetStringUTF16(component.name_id);
70      DetailInput input = { length, server_type, placeholder };
71      inputs->push_back(input);
72    }
73#endif
74  }
75
76  ServerFieldType server_type =
77      billing ? ADDRESS_BILLING_COUNTRY : ADDRESS_HOME_COUNTRY;
78  base::string16 placeholder_text =
79      l10n_util::GetStringUTF16(IDS_AUTOFILL_FIELD_LABEL_COUNTRY);
80  DetailInput input = { DetailInput::LONG, server_type, placeholder_text };
81  inputs->push_back(input);
82}
83
84bool CardHasCompleteAndVerifiedData(const CreditCard& card) {
85  if (!card.IsVerified())
86    return false;
87
88  const ServerFieldType required_fields[] = {
89      CREDIT_CARD_NUMBER,
90      CREDIT_CARD_EXP_MONTH,
91      CREDIT_CARD_EXP_4_DIGIT_YEAR,
92  };
93
94  for (size_t i = 0; i < arraysize(required_fields); ++i) {
95    if (card.GetRawInfo(required_fields[i]).empty())
96      return false;
97  }
98
99  return true;
100}
101
102bool AddressHasCompleteAndVerifiedData(const AutofillProfile& profile) {
103  if (!profile.IsVerified())
104    return false;
105
106  base::string16 country_code = profile.GetRawInfo(ADDRESS_HOME_COUNTRY);
107  if (country_code.empty())
108    return false;
109
110  std::vector<AddressField> required_fields =
111      ::i18n::addressinput::GetRequiredFields(base::UTF16ToUTF8(country_code));
112
113  for (size_t i = 0; i < required_fields.size(); ++i) {
114    ServerFieldType type =
115        TypeForField(required_fields[i], common::ADDRESS_TYPE_SHIPPING);
116    if (profile.GetRawInfo(type).empty())
117      return false;
118  }
119
120  const ServerFieldType more_required_fields[] = {
121      NAME_FULL,
122      PHONE_HOME_WHOLE_NUMBER
123  };
124
125  for (size_t i = 0; i < arraysize(more_required_fields); ++i) {
126    if (profile.GetRawInfo(more_required_fields[i]).empty())
127      return false;
128  }
129
130  return true;
131}
132
133ServerFieldType TypeForField(AddressField address_field,
134                             common::AddressType address_type) {
135  bool billing = address_type == common::ADDRESS_TYPE_BILLING;
136  switch (address_field) {
137    case ::i18n::addressinput::COUNTRY:
138      return billing ? ADDRESS_BILLING_COUNTRY : ADDRESS_HOME_COUNTRY;
139    case ::i18n::addressinput::ADMIN_AREA:
140      return billing ? ADDRESS_BILLING_STATE : ADDRESS_HOME_STATE;
141    case ::i18n::addressinput::LOCALITY:
142      return billing ? ADDRESS_BILLING_CITY : ADDRESS_HOME_CITY;
143    case ::i18n::addressinput::DEPENDENT_LOCALITY:
144      return billing ? ADDRESS_BILLING_DEPENDENT_LOCALITY :
145                       ADDRESS_HOME_DEPENDENT_LOCALITY;
146    case ::i18n::addressinput::POSTAL_CODE:
147      return billing ? ADDRESS_BILLING_ZIP : ADDRESS_HOME_ZIP;
148    case ::i18n::addressinput::SORTING_CODE:
149      return billing ? ADDRESS_BILLING_SORTING_CODE : ADDRESS_HOME_SORTING_CODE;
150#if defined(OS_ANDROID)
151    case ::i18n::addressinput::STREET_ADDRESS:
152      return billing ? ADDRESS_BILLING_LINE1 : ADDRESS_HOME_LINE1;
153#else
154    case ::i18n::addressinput::STREET_ADDRESS:
155      return billing ? ADDRESS_BILLING_STREET_ADDRESS :
156                       ADDRESS_HOME_STREET_ADDRESS;
157#endif
158    case ::i18n::addressinput::RECIPIENT:
159      return billing ? NAME_BILLING_FULL : NAME_FULL;
160    case ::i18n::addressinput::ORGANIZATION:
161      return COMPANY_NAME;
162  }
163  NOTREACHED();
164  return UNKNOWN_TYPE;
165}
166
167bool FieldForType(ServerFieldType server_type,
168                  ::i18n::addressinput::AddressField* field) {
169  switch (server_type) {
170    case ADDRESS_BILLING_COUNTRY:
171    case ADDRESS_HOME_COUNTRY:
172      if (field)
173        *field = ::i18n::addressinput::COUNTRY;
174      return true;
175    case ADDRESS_BILLING_STATE:
176    case ADDRESS_HOME_STATE:
177      if (field)
178        *field = ::i18n::addressinput::ADMIN_AREA;
179      return true;
180    case ADDRESS_BILLING_CITY:
181    case ADDRESS_HOME_CITY:
182      if (field)
183        *field = ::i18n::addressinput::LOCALITY;
184      return true;
185    case ADDRESS_BILLING_DEPENDENT_LOCALITY:
186    case ADDRESS_HOME_DEPENDENT_LOCALITY:
187      if (field)
188        *field = ::i18n::addressinput::DEPENDENT_LOCALITY;
189      return true;
190    case ADDRESS_BILLING_SORTING_CODE:
191    case ADDRESS_HOME_SORTING_CODE:
192      if (field)
193        *field = ::i18n::addressinput::SORTING_CODE;
194      return true;
195    case ADDRESS_BILLING_ZIP:
196    case ADDRESS_HOME_ZIP:
197      if (field)
198        *field = ::i18n::addressinput::POSTAL_CODE;
199      return true;
200    case ADDRESS_BILLING_STREET_ADDRESS:
201    case ADDRESS_BILLING_LINE1:
202    case ADDRESS_BILLING_LINE2:
203    case ADDRESS_HOME_STREET_ADDRESS:
204    case ADDRESS_HOME_LINE1:
205    case ADDRESS_HOME_LINE2:
206      if (field)
207        *field = ::i18n::addressinput::STREET_ADDRESS;
208      return true;
209    case COMPANY_NAME:
210      if (field)
211        *field = ::i18n::addressinput::ORGANIZATION;
212      return true;
213    case NAME_BILLING_FULL:
214    case NAME_FULL:
215      if (field)
216        *field = ::i18n::addressinput::RECIPIENT;
217      return true;
218    default:
219      return false;
220  }
221}
222
223void CreateAddressData(
224    const base::Callback<base::string16(const AutofillType&)>& get_info,
225    AddressData* address_data) {
226  address_data->recipient = UTF16ToUTF8(get_info.Run(AutofillType(NAME_FULL)));
227  address_data->country_code = UTF16ToUTF8(
228      get_info.Run(AutofillType(HTML_TYPE_COUNTRY_CODE, HTML_MODE_SHIPPING)));
229  DCHECK_EQ(2U, address_data->country_code.size());
230  address_data->administrative_area = UTF16ToUTF8(
231      get_info.Run(AutofillType(ADDRESS_HOME_STATE)));
232  address_data->locality = UTF16ToUTF8(
233      get_info.Run(AutofillType(ADDRESS_HOME_CITY)));
234  address_data->dependent_locality = UTF16ToUTF8(
235      get_info.Run(AutofillType(ADDRESS_HOME_DEPENDENT_LOCALITY)));
236  address_data->sorting_code = UTF16ToUTF8(
237      get_info.Run(AutofillType(ADDRESS_HOME_SORTING_CODE)));
238  address_data->postal_code = UTF16ToUTF8(
239      get_info.Run(AutofillType(ADDRESS_HOME_ZIP)));
240  base::SplitString(
241      UTF16ToUTF8(get_info.Run(AutofillType(ADDRESS_HOME_STREET_ADDRESS))),
242      '\n',
243      &address_data->address_lines);
244}
245
246bool CountryIsFullySupported(const std::string& country_code) {
247  DCHECK_EQ(2U, country_code.size());
248  std::vector< ::i18n::addressinput::AddressUiComponent> components =
249      ::i18n::addressinput::BuildComponents(
250          country_code, g_browser_process->GetApplicationLocale(), NULL);
251  for (size_t i = 0; i < components.size(); ++i) {
252    if (components[i].field == ::i18n::addressinput::DEPENDENT_LOCALITY)
253      return false;
254  }
255  return true;
256}
257
258}  // namespace i18ninput
259}  // namespace autofill
260