blob: be8192362e87396fd69a445b3f75fc5c88b773a9 [file] [log] [blame]
Torne (Richard Coles)7d4cd472013-06-19 11:58:07 +01001// Copyright 2013 The Chromium Authors. All rights reserved.
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +00002// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
Torne (Richard Coles)7d4cd472013-06-19 11:58:07 +01005#include "components/autofill/content/browser/autocheckout_manager.h"
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +00006
7#include "base/basictypes.h"
8#include "base/bind.h"
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +01009#include "base/strings/utf_string_conversions.h"
Torne (Richard Coles)7d4cd472013-06-19 11:58:07 +010010#include "components/autofill/content/browser/autocheckout_request_manager.h"
Ben Murdocheb525c52013-07-10 11:40:50 +010011#include "components/autofill/content/browser/autocheckout_statistic.h"
12#include "components/autofill/content/browser/autocheckout_steps.h"
13#include "components/autofill/core/browser/autofill_country.h"
14#include "components/autofill/core/browser/autofill_field.h"
15#include "components/autofill/core/browser/autofill_manager.h"
16#include "components/autofill/core/browser/autofill_metrics.h"
17#include "components/autofill/core/browser/autofill_profile.h"
Ben Murdoch32409262013-08-07 11:04:47 +010018#include "components/autofill/core/browser/autofill_type.h"
Ben Murdocheb525c52013-07-10 11:40:50 +010019#include "components/autofill/core/browser/credit_card.h"
Ben Murdocheb525c52013-07-10 11:40:50 +010020#include "components/autofill/core/browser/form_structure.h"
Torne (Richard Coles)7d4cd472013-06-19 11:58:07 +010021#include "components/autofill/core/common/autofill_messages.h"
22#include "components/autofill/core/common/form_data.h"
23#include "components/autofill/core/common/form_field_data.h"
24#include "components/autofill/core/common/web_element_descriptor.h"
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +010025#include "content/public/browser/browser_context.h"
26#include "content/public/browser/browser_thread.h"
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000027#include "content/public/browser/render_view_host.h"
28#include "content/public/browser/web_contents.h"
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +010029#include "net/cookies/cookie_options.h"
30#include "net/cookies/cookie_store.h"
31#include "net/url_request/url_request_context.h"
32#include "net/url_request/url_request_context_getter.h"
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000033#include "ui/gfx/rect.h"
Ben Murdoch7dbb3d52013-07-17 14:55:54 +010034#include "url/gurl.h"
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000035
36using content::RenderViewHost;
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000037using content::WebContents;
38
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +010039namespace autofill {
40
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000041namespace {
42
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +010043const char kGoogleAccountsUrl[] = "https://accounts.google.com/";
44
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000045// Build FormFieldData based on the supplied |autocomplete_attribute|. Will
46// fill rest of properties with default values.
47FormFieldData BuildField(const std::string& autocomplete_attribute) {
48 FormFieldData field;
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +010049 field.name = base::string16();
50 field.value = base::string16();
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000051 field.autocomplete_attribute = autocomplete_attribute;
52 field.form_control_type = "text";
53 return field;
54}
55
56// Build Autocheckout specific form data to be consumed by
57// AutofillDialogController to show the Autocheckout specific UI.
58FormData BuildAutocheckoutFormData() {
59 FormData formdata;
60 formdata.fields.push_back(BuildField("email"));
61 formdata.fields.push_back(BuildField("cc-name"));
62 formdata.fields.push_back(BuildField("cc-number"));
63 formdata.fields.push_back(BuildField("cc-exp-month"));
64 formdata.fields.push_back(BuildField("cc-exp-year"));
65 formdata.fields.push_back(BuildField("cc-csc"));
Ben Murdocheb525c52013-07-10 11:40:50 +010066 formdata.fields.push_back(BuildField("billing address-line1"));
67 formdata.fields.push_back(BuildField("billing address-line2"));
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000068 formdata.fields.push_back(BuildField("billing locality"));
69 formdata.fields.push_back(BuildField("billing region"));
70 formdata.fields.push_back(BuildField("billing country"));
71 formdata.fields.push_back(BuildField("billing postal-code"));
72 formdata.fields.push_back(BuildField("billing tel"));
73 formdata.fields.push_back(BuildField("shipping name"));
Ben Murdocheb525c52013-07-10 11:40:50 +010074 formdata.fields.push_back(BuildField("shipping address-line1"));
75 formdata.fields.push_back(BuildField("shipping address-line2"));
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000076 formdata.fields.push_back(BuildField("shipping locality"));
77 formdata.fields.push_back(BuildField("shipping region"));
78 formdata.fields.push_back(BuildField("shipping country"));
79 formdata.fields.push_back(BuildField("shipping postal-code"));
80 formdata.fields.push_back(BuildField("shipping tel"));
81 return formdata;
82}
83
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +010084AutofillMetrics::AutocheckoutBuyFlowMetric AutocheckoutStatusToUmaMetric(
85 AutocheckoutStatus status) {
86 switch (status) {
87 case SUCCESS:
88 return AutofillMetrics::AUTOCHECKOUT_BUY_FLOW_SUCCESS;
89 case MISSING_FIELDMAPPING:
90 return AutofillMetrics::AUTOCHECKOUT_BUY_FLOW_MISSING_FIELDMAPPING;
Torne (Richard Coles)5e3f23d2013-06-11 16:24:11 +010091 case MISSING_CLICK_ELEMENT_BEFORE_FORM_FILLING:
92 return AutofillMetrics::
93 AUTOCHECKOUT_BUY_FLOW_MISSING_CLICK_ELEMENT_BEFORE_FORM_FILLING;
94 case MISSING_CLICK_ELEMENT_AFTER_FORM_FILLING:
95 return AutofillMetrics::
96 AUTOCHECKOUT_BUY_FLOW_MISSING_CLICK_ELEMENT_AFTER_FORM_FILLING;
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +010097 case MISSING_ADVANCE:
98 return AutofillMetrics::AUTOCHECKOUT_BUY_FLOW_MISSING_ADVANCE_ELEMENT;
99 case CANNOT_PROCEED:
100 return AutofillMetrics::AUTOCHECKOUT_BUY_FLOW_CANNOT_PROCEED;
Torne (Richard Coles)7d4cd472013-06-19 11:58:07 +0100101 case AUTOCHECKOUT_STATUS_NUM_STATUS:
102 NOTREACHED();
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100103 }
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000104
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100105 NOTREACHED();
106 return AutofillMetrics::NUM_AUTOCHECKOUT_BUY_FLOW_METRICS;
107}
108
109// Callback for retrieving Google Account cookies. |callback| is passed the
110// retrieved cookies and posted back to the UI thread. |cookies| is any Google
111// Account cookies.
112void GetGoogleCookiesCallback(
113 const base::Callback<void(const std::string&)>& callback,
114 const std::string& cookies) {
115 content::BrowserThread::PostTask(content::BrowserThread::UI,
116 FROM_HERE,
117 base::Bind(callback, cookies));
118}
119
120// Gets Google Account cookies. Must be called on the IO thread.
121// |request_context_getter| is a getter for the current request context.
122// |callback| is called when retrieving cookies is completed.
123void GetGoogleCookies(
124 scoped_refptr<net::URLRequestContextGetter> request_context_getter,
125 const base::Callback<void(const std::string&)>& callback) {
126 net::URLRequestContext* url_request_context =
127 request_context_getter->GetURLRequestContext();
128 if (!url_request_context)
129 return;
130
131 net::CookieStore* cookie_store = url_request_context->cookie_store();
132
133 base::Callback<void(const std::string&)> cookie_callback = base::Bind(
134 &GetGoogleCookiesCallback,
135 callback);
136
137 net::CookieOptions cookie_options;
138 cookie_options.set_include_httponly();
139 cookie_store->GetCookiesWithOptionsAsync(GURL(kGoogleAccountsUrl),
140 cookie_options,
141 cookie_callback);
142}
143
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100144bool IsBillingGroup(FieldTypeGroup group) {
Ben Murdoch2385ea32013-08-06 11:01:04 +0100145 return group == ADDRESS_BILLING ||
146 group == PHONE_BILLING ||
147 group == NAME_BILLING;
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100148}
149
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100150const char kTransactionIdNotSet[] = "transaction id not set";
151
152} // namespace
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000153
154AutocheckoutManager::AutocheckoutManager(AutofillManager* autofill_manager)
155 : autofill_manager_(autofill_manager),
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100156 metric_logger_(new AutofillMetrics),
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100157 should_show_bubble_(true),
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000158 is_autocheckout_bubble_showing_(false),
159 in_autocheckout_flow_(false),
Ben Murdochca12bfa2013-07-23 11:17:05 +0100160 should_preserve_dialog_(false),
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100161 google_transaction_id_(kTransactionIdNotSet),
162 weak_ptr_factory_(this) {}
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000163
164AutocheckoutManager::~AutocheckoutManager() {
165}
166
167void AutocheckoutManager::FillForms() {
168 // |page_meta_data_| should have been set by OnLoadedPageMetaData.
169 DCHECK(page_meta_data_);
170
171 // Fill the forms on the page with data given by user.
172 std::vector<FormData> filled_forms;
173 const std::vector<FormStructure*>& form_structures =
174 autofill_manager_->GetFormStructures();
175 for (std::vector<FormStructure*>::const_iterator iter =
176 form_structures.begin(); iter != form_structures.end(); ++iter) {
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100177 FormStructure* form_structure = *iter;
178 form_structure->set_filled_by_autocheckout(true);
179 FormData form = form_structure->ToFormData();
180 DCHECK_EQ(form_structure->field_count(), form.fields.size());
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000181
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100182 for (size_t i = 0; i < form_structure->field_count(); ++i) {
183 const AutofillField* field = form_structure->field(i);
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000184 SetValue(*field, &form.fields[i]);
185 }
186
187 filled_forms.push_back(form);
188 }
189
190 // Send filled forms along with proceed descriptor to renderer.
191 RenderViewHost* host =
192 autofill_manager_->GetWebContents()->GetRenderViewHost();
193 if (!host)
194 return;
195
196 host->Send(new AutofillMsg_FillFormsAndClick(
197 host->GetRoutingID(),
198 filled_forms,
Torne (Richard Coles)5e3f23d2013-06-11 16:24:11 +0100199 page_meta_data_->click_elements_before_form_fill,
200 page_meta_data_->click_elements_after_form_fill,
Torne (Richard Coles)b2df76e2013-05-13 16:52:09 +0100201 page_meta_data_->proceed_element_descriptor));
Ben Murdocheb525c52013-07-10 11:40:50 +0100202 // Record time taken for navigating current page.
203 RecordTimeTaken(page_meta_data_->current_page_number);
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000204}
205
Ben Murdochca12bfa2013-07-23 11:17:05 +0100206void AutocheckoutManager::OnAutocheckoutPageCompleted(
207 AutocheckoutStatus status) {
208 if (!in_autocheckout_flow_)
209 return;
210
211 DVLOG(2) << "OnAutocheckoutPageCompleted, page_no: "
212 << page_meta_data_->current_page_number
213 << " status: "
214 << status;
215
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100216 DCHECK_NE(MISSING_FIELDMAPPING, status);
217
Ben Murdochca12bfa2013-07-23 11:17:05 +0100218 SetStepProgressForPage(
219 page_meta_data_->current_page_number,
220 (status == SUCCESS) ? AUTOCHECKOUT_STEP_COMPLETED :
221 AUTOCHECKOUT_STEP_FAILED);
Ben Murdocheb525c52013-07-10 11:40:50 +0100222
Ben Murdochca12bfa2013-07-23 11:17:05 +0100223 if (page_meta_data_->IsEndOfAutofillableFlow() || status != SUCCESS)
224 EndAutocheckout(status);
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100225}
226
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000227void AutocheckoutManager::OnLoadedPageMetaData(
228 scoped_ptr<AutocheckoutPageMetaData> page_meta_data) {
Ben Murdochca12bfa2013-07-23 11:17:05 +0100229 scoped_ptr<AutocheckoutPageMetaData> old_meta_data = page_meta_data_.Pass();
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000230 page_meta_data_ = page_meta_data.Pass();
231
Ben Murdochca12bfa2013-07-23 11:17:05 +0100232 // If there is no click element in the last page, then it's the real last page
233 // of the flow, and the dialog will be closed when the page navigates.
234 // Otherwise, the dialog should be preserved for the page loaded by the click
235 // element on the last page of the flow.
236 // Note, |should_preserve_dialog_| has to be computed at this point because
237 // |in_autocheckout_flow_| may change after |OnLoadedPageMetaData| is called.
238 should_preserve_dialog_ = in_autocheckout_flow_ ||
239 (old_meta_data.get() &&
240 old_meta_data->IsEndOfAutofillableFlow() &&
241 old_meta_data->proceed_element_descriptor.retrieval_method !=
242 WebElementDescriptor::NONE);
243
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100244 // Don't log that the bubble could be displayed if the user entered an
245 // Autocheckout flow and sees the first page of the flow again due to an
246 // error.
247 if (IsStartOfAutofillableFlow() && !in_autocheckout_flow_) {
248 metric_logger_->LogAutocheckoutBubbleMetric(
249 AutofillMetrics::BUBBLE_COULD_BE_DISPLAYED);
250 }
251
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000252 // On the first page of an Autocheckout flow, when this function is called the
253 // user won't have opted into the flow yet.
254 if (!in_autocheckout_flow_)
255 return;
256
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100257 AutocheckoutStatus status = SUCCESS;
258
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000259 // Missing Autofill server results.
Ben Murdochca12bfa2013-07-23 11:17:05 +0100260 if (!page_meta_data_.get()) {
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100261 status = MISSING_FIELDMAPPING;
Ben Murdochca12bfa2013-07-23 11:17:05 +0100262 } else if (IsStartOfAutofillableFlow()) {
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000263 // Not possible unless Autocheckout failed to proceed.
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100264 status = CANNOT_PROCEED;
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000265 } else if (!page_meta_data_->IsInAutofillableFlow()) {
266 // Missing Autocheckout meta data in the Autofill server results.
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100267 status = MISSING_FIELDMAPPING;
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000268 } else if (page_meta_data_->current_page_number <=
269 old_meta_data->current_page_number) {
270 // Not possible unless Autocheckout failed to proceed.
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100271 status = CANNOT_PROCEED;
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000272 }
273
Ben Murdocheb525c52013-07-10 11:40:50 +0100274 // Encountered an error during the Autocheckout flow, probably to
275 // do with a problem on the previous page.
Ben Murdochca12bfa2013-07-23 11:17:05 +0100276 if (status != SUCCESS) {
277 SetStepProgressForPage(old_meta_data->current_page_number,
278 AUTOCHECKOUT_STEP_FAILED);
279 EndAutocheckout(status);
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000280 return;
281 }
282
Ben Murdocheb525c52013-07-10 11:40:50 +0100283 SetStepProgressForPage(page_meta_data_->current_page_number,
284 AUTOCHECKOUT_STEP_STARTED);
285
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000286 FillForms();
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000287}
288
289void AutocheckoutManager::OnFormsSeen() {
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100290 should_show_bubble_ = true;
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000291}
292
Ben Murdocheb525c52013-07-10 11:40:50 +0100293bool AutocheckoutManager::ShouldIgnoreAjax() {
294 return in_autocheckout_flow_ && page_meta_data_->ignore_ajax;
295}
296
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000297void AutocheckoutManager::MaybeShowAutocheckoutBubble(
298 const GURL& frame_url,
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000299 const gfx::RectF& bounding_box) {
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100300 if (!should_show_bubble_ ||
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000301 is_autocheckout_bubble_showing_ ||
302 !IsStartOfAutofillableFlow())
303 return;
304
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100305 base::Callback<void(const std::string&)> callback = base::Bind(
306 &AutocheckoutManager::ShowAutocheckoutBubble,
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000307 weak_ptr_factory_.GetWeakPtr(),
308 frame_url,
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100309 bounding_box);
310
311 content::WebContents* web_contents = autofill_manager_->GetWebContents();
312 if (!web_contents)
313 return;
314
315 content::BrowserContext* browser_context = web_contents->GetBrowserContext();
316 if(!browser_context)
317 return;
318
319 scoped_refptr<net::URLRequestContextGetter> request_context =
320 scoped_refptr<net::URLRequestContextGetter>(
321 browser_context->GetRequestContext());
322
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100323 if (!request_context.get())
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100324 return;
325
326 base::Closure task = base::Bind(&GetGoogleCookies, request_context, callback);
327
328 content::BrowserThread::PostTask(content::BrowserThread::IO,
329 FROM_HERE,
330 task);
331}
332
Torne (Richard Coles)7d4cd472013-06-19 11:58:07 +0100333void AutocheckoutManager::ReturnAutocheckoutData(
334 const FormStructure* result,
335 const std::string& google_transaction_id) {
336 if (!result) {
Ben Murdochca12bfa2013-07-23 11:17:05 +0100337 // When user cancels the dialog, |result| is NULL.
338 // TODO(): add AutocheckoutStatus.USER_CANCELLED, and call
339 // EndAutocheckout(USER_CANCELLED) instead.
Torne (Richard Coles)7d4cd472013-06-19 11:58:07 +0100340 in_autocheckout_flow_ = false;
341 return;
342 }
343
Ben Murdocheb525c52013-07-10 11:40:50 +0100344 latency_statistics_.clear();
345 last_step_completion_timestamp_ = base::TimeTicks().Now();
Torne (Richard Coles)7d4cd472013-06-19 11:58:07 +0100346 google_transaction_id_ = google_transaction_id;
347 in_autocheckout_flow_ = true;
Ben Murdochca12bfa2013-07-23 11:17:05 +0100348 should_preserve_dialog_ = true;
Torne (Richard Coles)7d4cd472013-06-19 11:58:07 +0100349 metric_logger_->LogAutocheckoutBuyFlowMetric(
350 AutofillMetrics::AUTOCHECKOUT_BUY_FLOW_STARTED);
351
352 profile_.reset(new AutofillProfile());
353 credit_card_.reset(new CreditCard());
354 billing_address_.reset(new AutofillProfile());
355
356 for (size_t i = 0; i < result->field_count(); ++i) {
Ben Murdoch32409262013-08-07 11:04:47 +0100357 const AutofillType& type = result->field(i)->Type();
Torne (Richard Coles)7d4cd472013-06-19 11:58:07 +0100358 const base::string16& value = result->field(i)->value;
Ben Murdochbb1529c2013-08-08 10:24:53 +0100359 ServerFieldType server_type = type.GetStorableType();
360 if (server_type == CREDIT_CARD_VERIFICATION_CODE) {
Torne (Richard Coles)7d4cd472013-06-19 11:58:07 +0100361 cvv_ = result->field(i)->value;
362 continue;
363 }
Ben Murdoch32409262013-08-07 11:04:47 +0100364 FieldTypeGroup group = type.group();
Ben Murdoch2385ea32013-08-06 11:01:04 +0100365 if (group == CREDIT_CARD) {
Ben Murdochbb1529c2013-08-08 10:24:53 +0100366 credit_card_->SetRawInfo(server_type, value);
Torne (Richard Coles)a36e5922013-08-05 13:57:33 +0100367 // TODO(dgwallinga): Find a way of cleanly deprecating CREDIT_CARD_NAME.
368 // code.google.com/p/chromium/issues/detail?id=263498
Ben Murdochbb1529c2013-08-08 10:24:53 +0100369 if (server_type == CREDIT_CARD_NAME)
Torne (Richard Coles)a36e5922013-08-05 13:57:33 +0100370 billing_address_->SetRawInfo(NAME_BILLING_FULL, value);
Ben Murdochbb1529c2013-08-08 10:24:53 +0100371 } else if (server_type == ADDRESS_HOME_COUNTRY) {
372 if (IsBillingGroup(group))
373 billing_address_->SetInfo(type, value, autofill_manager_->app_locale());
374 else
375 profile_->SetInfo(type, value, autofill_manager_->app_locale());
Torne (Richard Coles)7d4cd472013-06-19 11:58:07 +0100376 } else if (IsBillingGroup(group)) {
Ben Murdochbb1529c2013-08-08 10:24:53 +0100377 billing_address_->SetRawInfo(server_type, value);
Torne (Richard Coles)7d4cd472013-06-19 11:58:07 +0100378 } else {
Ben Murdochbb1529c2013-08-08 10:24:53 +0100379 profile_->SetRawInfo(server_type, value);
Torne (Richard Coles)7d4cd472013-06-19 11:58:07 +0100380 }
381 }
382
Ben Murdocheb525c52013-07-10 11:40:50 +0100383 // Page types only available in first-page meta data, so save
384 // them for use later as we navigate.
385 page_types_ = page_meta_data_->page_types;
386 SetStepProgressForPage(page_meta_data_->current_page_number,
387 AUTOCHECKOUT_STEP_STARTED);
388
Torne (Richard Coles)7d4cd472013-06-19 11:58:07 +0100389 FillForms();
Torne (Richard Coles)7d4cd472013-06-19 11:58:07 +0100390}
391
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100392void AutocheckoutManager::set_metric_logger(
393 scoped_ptr<AutofillMetrics> metric_logger) {
394 metric_logger_ = metric_logger.Pass();
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000395}
396
397void AutocheckoutManager::MaybeShowAutocheckoutDialog(
398 const GURL& frame_url,
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100399 AutocheckoutBubbleState state) {
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000400 is_autocheckout_bubble_showing_ = false;
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000401
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100402 // User has taken action on the bubble, don't offer bubble again.
403 if (state != AUTOCHECKOUT_BUBBLE_IGNORED)
404 should_show_bubble_ = false;
405
406 if (state != AUTOCHECKOUT_BUBBLE_ACCEPTED)
407 return;
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100408
409 base::Callback<void(const FormStructure*, const std::string&)> callback =
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000410 base::Bind(&AutocheckoutManager::ReturnAutocheckoutData,
411 weak_ptr_factory_.GetWeakPtr());
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100412 autofill_manager_->ShowRequestAutocompleteDialog(BuildAutocheckoutFormData(),
413 frame_url,
414 DIALOG_TYPE_AUTOCHECKOUT,
415 callback);
Ben Murdocheb525c52013-07-10 11:40:50 +0100416
417 for (std::map<int, std::vector<AutocheckoutStepType> >::const_iterator
418 it = page_meta_data_->page_types.begin();
419 it != page_meta_data_->page_types.end(); ++it) {
420 for (size_t i = 0; i < it->second.size(); ++i) {
421 autofill_manager_->delegate()->AddAutocheckoutStep(it->second[i]);
422 }
423 }
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000424}
425
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100426void AutocheckoutManager::ShowAutocheckoutBubble(
427 const GURL& frame_url,
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100428 const gfx::RectF& bounding_box,
429 const std::string& cookies) {
430 DCHECK(thread_checker_.CalledOnValidThread());
431
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100432 base::Callback<void(AutocheckoutBubbleState)> callback = base::Bind(
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100433 &AutocheckoutManager::MaybeShowAutocheckoutDialog,
434 weak_ptr_factory_.GetWeakPtr(),
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100435 frame_url);
Ben Murdochbb1529c2013-08-08 10:24:53 +0100436 is_autocheckout_bubble_showing_ =
437 autofill_manager_->delegate()->ShowAutocheckoutBubble(
438 bounding_box,
439 cookies.find("LSID") != std::string::npos,
440 callback);
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100441}
442
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000443bool AutocheckoutManager::IsStartOfAutofillableFlow() const {
444 return page_meta_data_ && page_meta_data_->IsStartOfAutofillableFlow();
445}
446
447bool AutocheckoutManager::IsInAutofillableFlow() const {
448 return page_meta_data_ && page_meta_data_->IsInAutofillableFlow();
449}
450
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000451void AutocheckoutManager::SetValue(const AutofillField& field,
452 FormFieldData* field_to_fill) {
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100453 // No-op if Autofill server doesn't know about the field.
454 if (field.server_type() == NO_SERVER_DATA)
455 return;
456
Ben Murdoch32409262013-08-07 11:04:47 +0100457 const AutofillType& type = field.Type();
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000458
Ben Murdochbb1529c2013-08-08 10:24:53 +0100459 ServerFieldType server_type = type.GetStorableType();
460 if (server_type == FIELD_WITH_DEFAULT_VALUE) {
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000461 // For a form with radio buttons, like:
462 // <form>
463 // <input type="radio" name="sex" value="male">Male<br>
464 // <input type="radio" name="sex" value="female">Female
465 // </form>
466 // If the default value specified at the server is "female", then
467 // Autofill server responds back with following field mappings
468 // (fieldtype: FIELD_WITH_DEFAULT_VALUE, value: "female")
469 // (fieldtype: FIELD_WITH_DEFAULT_VALUE, value: "female")
470 // Note that, the field mapping is repeated twice to respond to both the
471 // input elements with the same name/signature in the form.
Torne (Richard Coles)a36e5922013-08-05 13:57:33 +0100472 //
473 // FIELD_WITH_DEFAULT_VALUE can also be used for selects, the correspondent
474 // example of the radio buttons example above is:
475 // <SELECT name="sex">
476 // <OPTION value="female">Female</OPTION>
477 // <OPTION value="male">Male</OPTION>
478 // </SELECT>
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100479 base::string16 default_value = UTF8ToUTF16(field.default_value());
Torne (Richard Coles)a36e5922013-08-05 13:57:33 +0100480 if (field.is_checkable) {
481 // Mark the field checked if server says the default value of the field
482 // to be this field's value.
483 field_to_fill->is_checked = (field.value == default_value);
484 } else if (field.form_control_type == "select-one") {
485 field_to_fill->value = default_value;
486 } else {
487 // FIELD_WITH_DEFAULT_VALUE should not be used for other type of fields.
488 NOTREACHED();
489 }
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000490 return;
491 }
492
493 // Handle verification code directly.
Ben Murdochbb1529c2013-08-08 10:24:53 +0100494 if (server_type == CREDIT_CARD_VERIFICATION_CODE) {
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000495 field_to_fill->value = cvv_;
496 return;
497 }
498
Ben Murdoch32409262013-08-07 11:04:47 +0100499 if (type.group() == CREDIT_CARD) {
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100500 credit_card_->FillFormField(
501 field, 0, autofill_manager_->app_locale(), field_to_fill);
Ben Murdoch32409262013-08-07 11:04:47 +0100502 } else if (IsBillingGroup(type.group())) {
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100503 billing_address_->FillFormField(
504 field, 0, autofill_manager_->app_locale(), field_to_fill);
505 } else {
506 profile_->FillFormField(
507 field, 0, autofill_manager_->app_locale(), field_to_fill);
508 }
509}
510
511void AutocheckoutManager::SendAutocheckoutStatus(AutocheckoutStatus status) {
512 // To ensure stale data isn't being sent.
513 DCHECK_NE(kTransactionIdNotSet, google_transaction_id_);
514
515 AutocheckoutRequestManager::CreateForBrowserContext(
516 autofill_manager_->GetWebContents()->GetBrowserContext());
517 AutocheckoutRequestManager* autocheckout_request_manager =
518 AutocheckoutRequestManager::FromBrowserContext(
519 autofill_manager_->GetWebContents()->GetBrowserContext());
520 // It is assumed that the domain Autocheckout starts on does not change
521 // during the flow. If this proves to be incorrect, the |source_url| from
522 // AutofillDialogControllerImpl will need to be provided in its callback in
523 // addition to the Google transaction id.
524 autocheckout_request_manager->SendAutocheckoutStatus(
525 status,
526 autofill_manager_->GetWebContents()->GetURL(),
Ben Murdocheb525c52013-07-10 11:40:50 +0100527 latency_statistics_,
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100528 google_transaction_id_);
529
530 // Log the result of this Autocheckout flow to UMA.
531 metric_logger_->LogAutocheckoutBuyFlowMetric(
532 AutocheckoutStatusToUmaMetric(status));
533
534 google_transaction_id_ = kTransactionIdNotSet;
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000535}
536
Ben Murdocheb525c52013-07-10 11:40:50 +0100537void AutocheckoutManager::SetStepProgressForPage(
538 int page_number,
539 AutocheckoutStepStatus status) {
540 if (page_types_.count(page_number) == 1) {
541 for (size_t i = 0; i < page_types_[page_number].size(); ++i) {
542 autofill_manager_->delegate()->UpdateAutocheckoutStep(
543 page_types_[page_number][i], status);
544 }
545 }
546}
547
548void AutocheckoutManager::RecordTimeTaken(int page_number) {
549 AutocheckoutStatistic statistic;
550 statistic.page_number = page_number;
551 if (page_types_.count(page_number) == 1) {
552 for (size_t i = 0; i < page_types_[page_number].size(); ++i) {
553 statistic.steps.push_back(page_types_[page_number][i]);
554 }
555 }
556
557 statistic.time_taken =
558 base::TimeTicks().Now() - last_step_completion_timestamp_;
559 latency_statistics_.push_back(statistic);
560
561 // Reset timestamp.
562 last_step_completion_timestamp_ = base::TimeTicks().Now();
563}
564
Ben Murdochca12bfa2013-07-23 11:17:05 +0100565void AutocheckoutManager::EndAutocheckout(AutocheckoutStatus status) {
566 DCHECK(in_autocheckout_flow_);
567
568 DVLOG(2) << "EndAutocheckout at step: "
569 << page_meta_data_->current_page_number
570 << " with status: "
571 << status;
572
573 SendAutocheckoutStatus(status);
574 if (status == SUCCESS)
575 autofill_manager_->delegate()->OnAutocheckoutSuccess();
576 else
577 autofill_manager_->delegate()->OnAutocheckoutError();
578 in_autocheckout_flow_ = false;
579}
580
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000581} // namespace autofill