| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 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 "chrome/browser/autofill/autocheckout_manager.h" | |
| 6 | |
| 7 #include "base/basictypes.h" | |
| 8 #include "base/bind.h" | |
| 9 #include "base/utf_string_conversions.h" | |
| 10 #include "chrome/browser/autofill/autofill_country.h" | |
| 11 #include "chrome/browser/autofill/autofill_field.h" | |
| 12 #include "chrome/browser/autofill/autofill_manager.h" | |
| 13 #include "chrome/browser/autofill/autofill_profile.h" | |
| 14 #include "chrome/browser/autofill/credit_card.h" | |
| 15 #include "chrome/browser/autofill/field_types.h" | |
| 16 #include "chrome/browser/autofill/form_structure.h" | |
| 17 #include "components/autofill/common/autocheckout_status.h" | |
| 18 #include "components/autofill/common/autofill_messages.h" | |
| 19 #include "components/autofill/common/form_data.h" | |
| 20 #include "components/autofill/common/form_field_data.h" | |
| 21 #include "components/autofill/common/web_element_descriptor.h" | |
| 22 #include "content/public/browser/render_view_host.h" | |
| 23 #include "content/public/browser/web_contents.h" | |
| 24 #include "content/public/common/ssl_status.h" | |
| 25 #include "googleurl/src/gurl.h" | |
| 26 #include "ui/gfx/rect.h" | |
| 27 | |
| 28 using content::RenderViewHost; | |
| 29 using content::SSLStatus; | |
| 30 using content::WebContents; | |
| 31 | |
| 32 namespace { | |
| 33 | |
| 34 // Build FormFieldData based on the supplied |autocomplete_attribute|. Will | |
| 35 // fill rest of properties with default values. | |
| 36 FormFieldData BuildField(const std::string& autocomplete_attribute) { | |
| 37 FormFieldData field; | |
| 38 field.name = string16(); | |
| 39 field.value = string16(); | |
| 40 field.autocomplete_attribute = autocomplete_attribute; | |
| 41 field.form_control_type = "text"; | |
| 42 return field; | |
| 43 } | |
| 44 | |
| 45 // Build Autocheckout specific form data to be consumed by | |
| 46 // AutofillDialogController to show the Autocheckout specific UI. | |
| 47 FormData BuildAutocheckoutFormData() { | |
| 48 FormData formdata; | |
| 49 formdata.fields.push_back(BuildField("name")); | |
| 50 formdata.fields.push_back(BuildField("tel")); | |
| 51 formdata.fields.push_back(BuildField("email")); | |
| 52 formdata.fields.push_back(BuildField("cc-name")); | |
| 53 formdata.fields.push_back(BuildField("cc-number")); | |
| 54 formdata.fields.push_back(BuildField("cc-exp-month")); | |
| 55 formdata.fields.push_back(BuildField("cc-exp-year")); | |
| 56 formdata.fields.push_back(BuildField("cc-csc")); | |
| 57 formdata.fields.push_back(BuildField("billing street-address")); | |
| 58 formdata.fields.push_back(BuildField("billing locality")); | |
| 59 formdata.fields.push_back(BuildField("billing region")); | |
| 60 formdata.fields.push_back(BuildField("billing country")); | |
| 61 formdata.fields.push_back(BuildField("billing postal-code")); | |
| 62 formdata.fields.push_back(BuildField("shipping street-address")); | |
| 63 formdata.fields.push_back(BuildField("shipping locality")); | |
| 64 formdata.fields.push_back(BuildField("shipping region")); | |
| 65 formdata.fields.push_back(BuildField("shipping country")); | |
| 66 formdata.fields.push_back(BuildField("shipping postal-code")); | |
| 67 return formdata; | |
| 68 } | |
| 69 | |
| 70 } // namespace | |
| 71 | |
| 72 namespace autofill { | |
| 73 | |
| 74 AutocheckoutManager::AutocheckoutManager(AutofillManager* autofill_manager) | |
| 75 : autofill_manager_(autofill_manager), | |
| 76 autocheckout_bubble_shown_(false), | |
| 77 in_autocheckout_flow_(false), | |
| 78 ALLOW_THIS_IN_INITIALIZER_LIST(weak_ptr_factory_(this)) { | |
| 79 } | |
| 80 | |
| 81 AutocheckoutManager::~AutocheckoutManager() { | |
| 82 } | |
| 83 | |
| 84 void AutocheckoutManager::FillForms() { | |
| 85 // |page_meta_data_| should have been set by OnLoadedPageMetaData. | |
| 86 DCHECK(page_meta_data_); | |
| 87 | |
| 88 // Fill the forms on the page with data given by user. | |
| 89 std::vector<FormData> filled_forms; | |
| 90 const std::vector<FormStructure*>& form_structures = | |
| 91 autofill_manager_->GetFormStructures(); | |
| 92 for (std::vector<FormStructure*>::const_iterator iter = | |
| 93 form_structures.begin(); iter != form_structures.end(); ++iter) { | |
| 94 const FormStructure& form_structure = **iter; | |
| 95 FormData form = form_structure.ToFormData(); | |
| 96 DCHECK_EQ(form_structure.field_count(), form.fields.size()); | |
| 97 | |
| 98 for (size_t i = 0; i < form_structure.field_count(); ++i) { | |
| 99 const AutofillField* field = form_structure.field(i); | |
| 100 SetValue(*field, &form.fields[i]); | |
| 101 } | |
| 102 | |
| 103 filled_forms.push_back(form); | |
| 104 } | |
| 105 | |
| 106 // Send filled forms along with proceed descriptor to renderer. | |
| 107 RenderViewHost* host = | |
| 108 autofill_manager_->GetWebContents()->GetRenderViewHost(); | |
| 109 if (!host) | |
| 110 return; | |
| 111 | |
| 112 host->Send(new AutofillMsg_FillFormsAndClick( | |
| 113 host->GetRoutingID(), | |
| 114 filled_forms, | |
| 115 page_meta_data_->IsEndOfAutofillableFlow() ? | |
| 116 WebElementDescriptor() : | |
| 117 *page_meta_data_->proceed_element_descriptor)); | |
| 118 } | |
| 119 | |
| 120 void AutocheckoutManager::OnLoadedPageMetaData( | |
| 121 scoped_ptr<AutocheckoutPageMetaData> page_meta_data) { | |
| 122 scoped_ptr<AutocheckoutPageMetaData> old_meta_data = | |
| 123 page_meta_data_.Pass(); | |
| 124 page_meta_data_ = page_meta_data.Pass(); | |
| 125 | |
| 126 // On the first page of an Autocheckout flow, when this function is called the | |
| 127 // user won't have opted into the flow yet. | |
| 128 if (!in_autocheckout_flow_) | |
| 129 return; | |
| 130 | |
| 131 // Missing Autofill server results. | |
| 132 if (!page_meta_data_) { | |
| 133 in_autocheckout_flow_ = false; | |
| 134 } else if (page_meta_data_->IsStartOfAutofillableFlow()) { | |
| 135 // Not possible unless Autocheckout failed to proceed. | |
| 136 in_autocheckout_flow_ = false; | |
| 137 } else if (!page_meta_data_->IsInAutofillableFlow()) { | |
| 138 // Missing Autocheckout meta data in the Autofill server results. | |
| 139 in_autocheckout_flow_ = false; | |
| 140 } else if (!page_meta_data_->proceed_element_descriptor && | |
| 141 !page_meta_data_->IsEndOfAutofillableFlow()) { | |
| 142 // Missing Autocheckout proceed data in meta data in the Autofill server | |
| 143 // results. | |
| 144 in_autocheckout_flow_ = false; | |
| 145 } else if (page_meta_data_->current_page_number <= | |
| 146 old_meta_data->current_page_number) { | |
| 147 // Not possible unless Autocheckout failed to proceed. | |
| 148 in_autocheckout_flow_ = false; | |
| 149 } | |
| 150 | |
| 151 // Encountered an error during the Autocheckout flow. | |
| 152 if (!in_autocheckout_flow_) { | |
| 153 // TODO(ahutter): SendAutocheckoutStatus of the error. | |
| 154 autofill_manager_->delegate()->OnAutocheckoutError(); | |
| 155 return; | |
| 156 } | |
| 157 | |
| 158 // Add 1.0 since page numbers are 0-indexed. | |
| 159 autofill_manager_->delegate()->UpdateProgressBar( | |
| 160 (1.0 + page_meta_data_->current_page_number) / | |
| 161 page_meta_data_->total_pages); | |
| 162 FillForms(); | |
| 163 // If the current page is the last page in the flow, close the dialog. | |
| 164 if (page_meta_data_->IsEndOfAutofillableFlow()) { | |
| 165 // TODO(ahutter): SendAutocheckoutStatus of SUCCESS. | |
| 166 autofill_manager_->delegate()->HideRequestAutocompleteDialog(); | |
| 167 in_autocheckout_flow_ = false; | |
| 168 } | |
| 169 } | |
| 170 | |
| 171 void AutocheckoutManager::OnFormsSeen() { | |
| 172 autocheckout_bubble_shown_ = false; | |
| 173 } | |
| 174 | |
| 175 bool AutocheckoutManager::MaybeShowAutocheckoutBubble( | |
| 176 const GURL& frame_url, | |
| 177 const content::SSLStatus& ssl_status, | |
| 178 const gfx::NativeView& native_view, | |
| 179 const gfx::RectF& bounding_box) { | |
| 180 if (autocheckout_bubble_shown_) | |
| 181 return false; | |
| 182 | |
| 183 base::Closure callback = base::Bind( | |
| 184 &AutocheckoutManager::ShowAutocheckoutDialog, | |
| 185 weak_ptr_factory_.GetWeakPtr(), | |
| 186 frame_url, | |
| 187 ssl_status); | |
| 188 autofill_manager_->delegate()->ShowAutocheckoutBubble( | |
| 189 bounding_box, | |
| 190 native_view, | |
| 191 callback); | |
| 192 autocheckout_bubble_shown_ = true; | |
| 193 return true; | |
| 194 } | |
| 195 | |
| 196 void AutocheckoutManager::ShowAutocheckoutDialog( | |
| 197 const GURL& frame_url, | |
| 198 const SSLStatus& ssl_status) { | |
| 199 base::Callback<void(const FormStructure*)> callback = | |
| 200 base::Bind(&AutocheckoutManager::ReturnAutocheckoutData, | |
| 201 weak_ptr_factory_.GetWeakPtr()); | |
| 202 autofill_manager_->ShowRequestAutocompleteDialog( | |
| 203 BuildAutocheckoutFormData(), frame_url, ssl_status, | |
| 204 DIALOG_TYPE_AUTOCHECKOUT, callback); | |
| 205 } | |
| 206 | |
| 207 bool AutocheckoutManager::IsStartOfAutofillableFlow() const { | |
| 208 return page_meta_data_ && page_meta_data_->IsStartOfAutofillableFlow(); | |
| 209 } | |
| 210 | |
| 211 bool AutocheckoutManager::IsInAutofillableFlow() const { | |
| 212 return page_meta_data_ && page_meta_data_->IsInAutofillableFlow(); | |
| 213 } | |
| 214 | |
| 215 void AutocheckoutManager::ReturnAutocheckoutData(const FormStructure* result) { | |
| 216 if (!result) | |
| 217 return; | |
| 218 | |
| 219 in_autocheckout_flow_ = true; | |
| 220 | |
| 221 profile_.reset(new AutofillProfile()); | |
| 222 credit_card_.reset(new CreditCard()); | |
| 223 | |
| 224 for (size_t i = 0; i < result->field_count(); ++i) { | |
| 225 AutofillFieldType type = result->field(i)->type(); | |
| 226 if (type == CREDIT_CARD_VERIFICATION_CODE) { | |
| 227 // TODO(ramankk): CVV is not handled by CreditCard, not sure how to | |
| 228 // handle it yet. | |
| 229 cvv_ = result->field(i)->value; | |
| 230 continue; | |
| 231 } | |
| 232 if (AutofillType(type).group() == AutofillType::CREDIT_CARD) { | |
| 233 credit_card_->SetRawInfo(result->field(i)->type(), | |
| 234 result->field(i)->value); | |
| 235 } else { | |
| 236 profile_->SetRawInfo(result->field(i)->type(), result->field(i)->value); | |
| 237 } | |
| 238 } | |
| 239 | |
| 240 // Add 1.0 since page numbers are 0-indexed. | |
| 241 autofill_manager_->delegate()->UpdateProgressBar( | |
| 242 (1.0 + page_meta_data_->current_page_number) / | |
| 243 page_meta_data_->total_pages); | |
| 244 FillForms(); | |
| 245 } | |
| 246 | |
| 247 void AutocheckoutManager::SetValue(const AutofillField& field, | |
| 248 FormFieldData* field_to_fill) { | |
| 249 AutofillFieldType type = field.type(); | |
| 250 | |
| 251 if (type == FIELD_WITH_DEFAULT_VALUE) { | |
| 252 DCHECK(field.is_checkable); | |
| 253 // For a form with radio buttons, like: | |
| 254 // <form> | |
| 255 // <input type="radio" name="sex" value="male">Male<br> | |
| 256 // <input type="radio" name="sex" value="female">Female | |
| 257 // </form> | |
| 258 // If the default value specified at the server is "female", then | |
| 259 // Autofill server responds back with following field mappings | |
| 260 // (fieldtype: FIELD_WITH_DEFAULT_VALUE, value: "female") | |
| 261 // (fieldtype: FIELD_WITH_DEFAULT_VALUE, value: "female") | |
| 262 // Note that, the field mapping is repeated twice to respond to both the | |
| 263 // input elements with the same name/signature in the form. | |
| 264 string16 default_value = UTF8ToUTF16(field.default_value()); | |
| 265 // Mark the field checked if server says the default value of the field | |
| 266 // to be this field's value. | |
| 267 field_to_fill->is_checked = (field.value == default_value); | |
| 268 return; | |
| 269 } | |
| 270 | |
| 271 // Handle verification code directly. | |
| 272 if (type == CREDIT_CARD_VERIFICATION_CODE) { | |
| 273 field_to_fill->value = cvv_; | |
| 274 return; | |
| 275 } | |
| 276 | |
| 277 // TODO(ramankk): Handle variants in a better fashion, need to distinguish | |
| 278 // between shipping and billing address. | |
| 279 if (AutofillType(type).group() == AutofillType::CREDIT_CARD) | |
| 280 credit_card_->FillFormField(field, 0, field_to_fill); | |
| 281 else | |
| 282 profile_->FillFormField(field, 0, field_to_fill); | |
| 283 } | |
| 284 | |
| 285 } // namespace autofill | |
| OLD | NEW |