blob: cc9c24e1ee4592a5d3c4deb5a9c7483c930dccfa [file] [log] [blame]
mathpf709499d2017-01-09 20:48:361// Copyright 2016 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
rouslan908248c2017-02-27 21:30:245#include "components/payments/content/payment_request.h"
6
Rouslan Solomakhin9c83b8a2019-06-24 20:50:037#include <algorithm>
anthonyvdd23ed702017-04-05 15:29:008#include <string>
rouslan908248c2017-02-27 21:30:249#include <utility>
mathpf709499d2017-01-09 20:48:3610
Sebastien Marchand53801a32019-01-25 16:26:1111#include "base/bind.h"
Rouslan Solomakhin1804ee42017-10-03 14:27:4312#include "base/feature_list.h"
Mathieu Perreault627b97c2017-08-12 00:44:2213#include "base/stl_util.h"
Rouslan Solomakhin9c83b8a2019-06-24 20:50:0314#include "base/strings/string_util.h"
rouslan690997682017-05-09 18:07:3915#include "components/payments/content/can_make_payment_query_factory.h"
Rouslan Solomakhin4eea9bc22017-10-10 15:18:5116#include "components/payments/content/content_payment_request_delegate.h"
Rouslan Solomakhincf9093f2019-05-20 15:32:1717#include "components/payments/content/payment_details_converter.h"
Mohamad Ahmadif5544bb2017-09-01 21:48:2218#include "components/payments/content/payment_request_converter.h"
rouslan908248c2017-02-27 21:30:2419#include "components/payments/content/payment_request_web_contents_manager.h"
rouslan690997682017-05-09 18:07:3920#include "components/payments/core/can_make_payment_query.h"
Rouslan Solomakhina480efa2019-05-06 15:37:2221#include "components/payments/core/error_strings.h"
Anthony Vallee-Dubois968ae4d2018-03-15 16:56:3622#include "components/payments/core/features.h"
Rouslan Solomakhin85b10da2019-11-05 20:03:1723#include "components/payments/core/method_strings.h"
Rouslan Solomakhineb06b272019-07-10 16:23:3224#include "components/payments/core/native_error_strings.h"
Rouslan Solomakhin5d15cb1f2019-11-11 18:11:3925#include "components/payments/core/payment_app.h"
Mohamad Ahmadif5544bb2017-09-01 21:48:2226#include "components/payments/core/payment_details.h"
27#include "components/payments/core/payment_details_validation.h"
anthonyvd6a43b932017-05-11 18:39:2728#include "components/payments/core/payment_prefs.h"
Danyao Wang50ccb9f2019-05-09 23:28:0329#include "components/payments/core/payments_experimental_features.h"
Jinho Bangbe463a22018-08-02 10:26:5030#include "components/payments/core/payments_validators.h"
Rouslan Solomakhin77a7e1a2019-05-23 17:37:5831#include "components/payments/core/url_util.h"
anthonyvd6a43b932017-05-11 18:39:2732#include "components/prefs/pref_service.h"
Steven Holte2083e8bc2018-07-16 23:50:3633#include "components/ukm/content/source_url_recorder.h"
Rouslan Solomakhin6e979ab2017-08-30 17:30:3934#include "components/url_formatter/elide_url.h"
mathpf709499d2017-01-09 20:48:3635#include "content/public/browser/browser_thread.h"
rouslan690997682017-05-09 18:07:3936#include "content/public/browser/render_frame_host.h"
mathpf709499d2017-01-09 20:48:3637#include "content/public/browser/web_contents.h"
Rouslan Solomakhin1804ee42017-10-03 14:27:4338#include "content/public/common/content_features.h"
Rouslan Solomakhin77a7e1a2019-05-23 17:37:5839#include "content/public/common/origin_util.h"
mathpf709499d2017-01-09 20:48:3640
Rouslan Solomakhina480efa2019-05-06 15:37:2241namespace payments {
Danyao Wangce175bf2018-12-21 22:35:5842namespace {
43
Danyao Wang57aa0442019-01-31 04:06:4144using ::payments::mojom::CanMakePaymentQueryResult;
Danyao Wangce175bf2018-12-21 22:35:5845using ::payments::mojom::HasEnrolledInstrumentQueryResult;
46
Rouslan Solomakhin5d15cb1f2019-11-11 18:11:3947bool IsGooglePaymentMethod(const std::string& method_name) {
Rouslan Solomakhin85b10da2019-11-05 20:03:1748 return method_name == methods::kGooglePay ||
49 method_name == methods::kAndroidPay;
Sahel Sharify26884382019-05-07 16:23:5150}
51
Rouslan Solomakhin9c83b8a2019-06-24 20:50:0352std::string GetNotSupportedErrorMessage(PaymentRequestSpec* spec) {
53 if (!spec || spec->payment_method_identifiers_set().empty())
54 return errors::kGenericPaymentMethodNotSupportedMessage;
55
56 std::vector<std::string> method_names(
57 spec->payment_method_identifiers_set().size());
58 std::transform(
59 spec->payment_method_identifiers_set().begin(),
60 spec->payment_method_identifiers_set().end(), method_names.begin(),
61 [](const std::string& method_name) { return "\"" + method_name + "\""; });
62
63 std::string output;
64 bool replaced = base::ReplaceChars(
65 method_names.size() == 1
66 ? errors::kSinglePaymentMethodNotSupportedFormat
67 : errors::kMultiplePaymentMethodsNotSupportedFormat,
68 "$", base::JoinString(method_names, ", "), &output);
69 DCHECK(replaced);
70 return output;
71}
72
Sahel Sharify9d98a502019-09-30 19:58:3973// Redact shipping address before exposing it in ShippingAddressChangeEvent.
74// https://w3c.github.io/payment-request/#shipping-address-changed-algorithm
75mojom::PaymentAddressPtr RedactShippingAddress(
76 mojom::PaymentAddressPtr address) {
77 DCHECK(address);
78 if (!PaymentsExperimentalFeatures::IsEnabled(
79 features::kWebPaymentsRedactShippingAddress)) {
80 return address;
81 }
82 address->organization.clear();
83 address->phone.clear();
84 address->recipient.clear();
85 address->address_line.clear();
86 return address;
87}
88
Rouslan Solomakhina480efa2019-05-06 15:37:2289} // namespace
mathpf709499d2017-01-09 20:48:3690
91PaymentRequest::PaymentRequest(
rouslan690997682017-05-09 18:07:3992 content::RenderFrameHost* render_frame_host,
mathpf709499d2017-01-09 20:48:3693 content::WebContents* web_contents,
Rouslan Solomakhin4eea9bc22017-10-10 15:18:5194 std::unique_ptr<ContentPaymentRequestDelegate> delegate,
mathpf709499d2017-01-09 20:48:3695 PaymentRequestWebContentsManager* manager,
Anthony Vallee-Duboisc7ae7332017-12-19 20:44:0796 PaymentRequestDisplayManager* display_manager,
Gyuyoung Kim9cfbda32019-08-27 02:15:1897 mojo::PendingReceiver<mojom::PaymentRequest> receiver,
mathp300fa542017-03-27 19:29:3798 ObserverForTest* observer_for_testing)
mathpf709499d2017-01-09 20:48:3699 : web_contents_(web_contents),
Danyao Wang4f2ba632020-03-11 13:56:54100 initiator_render_frame_host_(render_frame_host),
Rouslan Solomakhin27064702018-12-14 21:15:33101 log_(web_contents_),
mathpf709499d2017-01-09 20:48:36102 delegate_(std::move(delegate)),
103 manager_(manager),
Anthony Vallee-Duboisc7ae7332017-12-19 20:44:07104 display_manager_(display_manager),
105 display_handle_(nullptr),
Rouslan Solomakhin1f95f092019-08-09 12:28:51106 payment_handler_host_(web_contents_, this),
Rouslan Solomakhin6e979ab2017-08-30 17:30:39107 top_level_origin_(url_formatter::FormatUrlForSecurityDisplay(
108 web_contents_->GetLastCommittedURL())),
109 frame_origin_(url_formatter::FormatUrlForSecurityDisplay(
110 render_frame_host->GetLastCommittedURL())),
Rouslan Solomakhinc71cca622020-01-31 22:15:35111 frame_security_origin_(render_frame_host->GetLastCommittedOrigin()),
sebsg20b49d7b2017-05-04 20:23:17112 observer_for_testing_(observer_for_testing),
113 journey_logger_(delegate_->IsIncognito(),
Jeremy Roman5c341f6d2019-07-15 15:56:10114 ukm::GetSourceIdForWebContentsDocument(web_contents)) {
Gyuyoung Kim9cfbda32019-08-27 02:15:18115 receiver_.Bind(std::move(receiver));
mathpf4bc50e2017-01-24 05:17:50116 // OnConnectionTerminated will be called when the Mojo pipe is closed. This
117 // will happen as a result of many renderer-side events (both successful and
118 // erroneous in nature).
119 // TODO(crbug.com/683636): Investigate using
120 // set_connection_error_with_reason_handler with Binding::CloseWithReason.
Gyuyoung Kim9cfbda32019-08-27 02:15:18121 receiver_.set_disconnect_handler(base::BindOnce(
Anthony Vallee-Duboisdc1dbf1a2017-07-17 15:01:13122 &PaymentRequest::OnConnectionTerminated, weak_ptr_factory_.GetWeakPtr()));
mathpf709499d2017-01-09 20:48:36123}
124
125PaymentRequest::~PaymentRequest() {}
126
Gyuyoung Kim9cfbda32019-08-27 02:15:18127void PaymentRequest::Init(
128 mojo::PendingRemote<mojom::PaymentRequestClient> client,
129 std::vector<mojom::PaymentMethodDataPtr> method_data,
130 mojom::PaymentDetailsPtr details,
131 mojom::PaymentOptionsPtr options) {
mathpf709499d2017-01-09 20:48:36132 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
Rouslan Solomakhin27064702018-12-14 21:15:33133
134 if (is_initialized_) {
Rouslan Solomakhina480efa2019-05-06 15:37:22135 log_.Error(errors::kAttemptedInitializationTwice);
Rouslan Solomakhin27064702018-12-14 21:15:33136 OnConnectionTerminated();
137 return;
138 }
139
140 is_initialized_ = true;
Gyuyoung Kim9cfbda32019-08-27 02:15:18141 client_.Bind(std::move(client));
rouslan6e3cf7c62017-04-17 21:23:28142
rouslanb28f4532017-05-08 15:41:47143 const GURL last_committed_url = delegate_->GetLastCommittedURL();
Rouslan Solomakhin77a7e1a2019-05-23 17:37:58144 if (!content::IsOriginSecure(last_committed_url)) {
Rouslan Solomakhina480efa2019-05-06 15:37:22145 log_.Error(errors::kNotInASecureOrigin);
rouslan6e3cf7c62017-04-17 21:23:28146 OnConnectionTerminated();
147 return;
148 }
149
Rouslan Solomakhin55db8272019-06-25 18:16:28150 // TODO(crbug.com/978471): Improve architecture for handling prohibited
151 // origins and invalid SSL certificates.
rouslanb28f4532017-05-08 15:41:47152 bool allowed_origin =
Rouslan Solomakhin77a7e1a2019-05-23 17:37:58153 UrlUtil::IsOriginAllowedToUseWebPaymentApis(last_committed_url);
rouslanb28f4532017-05-08 15:41:47154 if (!allowed_origin) {
Rouslan Solomakhin68429b72019-06-27 15:12:39155 reject_show_error_message_ = errors::kProhibitedOrigin;
rouslanb28f4532017-05-08 15:41:47156 }
157
Rouslan Solomakhin55db8272019-06-25 18:16:28158 bool invalid_ssl = false;
159 if (last_committed_url.SchemeIsCryptographic()) {
Rouslan Solomakhin68429b72019-06-27 15:12:39160 DCHECK(reject_show_error_message_.empty());
161 reject_show_error_message_ =
Rouslan Solomakhin55db8272019-06-25 18:16:28162 delegate_->GetInvalidSslCertificateErrorMessage();
Rouslan Solomakhin68429b72019-06-27 15:12:39163 invalid_ssl = !reject_show_error_message_.empty();
Rouslan Solomakhin27064702018-12-14 21:15:33164 }
rouslanb28f4532017-05-08 15:41:47165
166 if (!allowed_origin || invalid_ssl) {
Rouslan Solomakhin27064702018-12-14 21:15:33167 // Intentionally don't set |spec_| and |state_|, so the UI is never shown.
Rouslan Solomakhin68429b72019-06-27 15:12:39168 log_.Error(reject_show_error_message_);
Rouslan Solomakhina480efa2019-05-06 15:37:22169 log_.Error(errors::kProhibitedOriginOrInvalidSslExplanation);
rouslan6e3cf7c62017-04-17 21:23:28170 return;
171 }
172
mathpf709499d2017-01-09 20:48:36173 std::string error;
Mohamad Ahmadif5544bb2017-09-01 21:48:22174 if (!ValidatePaymentDetails(ConvertPaymentDetails(details), &error)) {
Rouslan Solomakhin27064702018-12-14 21:15:33175 log_.Error(error);
mathpf4bc50e2017-01-24 05:17:50176 OnConnectionTerminated();
mathpf709499d2017-01-09 20:48:36177 return;
178 }
rouslan6e3cf7c62017-04-17 21:23:28179
jinho.bangfcb5ec92017-03-29 08:08:02180 if (!details->total) {
Rouslan Solomakhina480efa2019-05-06 15:37:22181 log_.Error(errors::kTotalRequired);
jinho.bangfcb5ec92017-03-29 08:08:02182 OnConnectionTerminated();
183 return;
184 }
rouslan6e3cf7c62017-04-17 21:23:28185
sebsga70a6da2017-12-21 22:27:02186 spec_ = std::make_unique<PaymentRequestSpec>(
Rouslan Solomakhin1f95f092019-08-09 12:28:51187 std::move(options), std::move(details), std::move(method_data),
188 /*observer=*/this, delegate_->GetApplicationLocale());
sebsga70a6da2017-12-21 22:27:02189 state_ = std::make_unique<PaymentRequestState>(
Danyao Wang4f2ba632020-03-11 13:56:54190 web_contents_, initiator_render_frame_host_, top_level_origin_,
191 frame_origin_, frame_security_origin_, spec_.get(),
Rouslan Solomakhin1f95f092019-08-09 12:28:51192 /*delegate=*/this, delegate_->GetApplicationLocale(),
193 delegate_->GetPersonalDataManager(), delegate_.get(),
Rouslan Solomakhin6d4c1c272019-11-22 17:09:27194 base::BindRepeating(&PaymentRequest::SetInvokedServiceWorkerIdentity,
195 weak_ptr_factory_.GetWeakPtr()),
Rouslan Solomakhin65552292019-08-29 17:28:21196 &journey_logger_);
Mathieu Perreault627b97c2017-08-12 00:44:22197
198 journey_logger_.SetRequestedInformation(
199 spec_->request_shipping(), spec_->request_payer_email(),
200 spec_->request_payer_phone(), spec_->request_payer_name());
201
202 // Log metrics around which payment methods are requested by the merchant.
Rouslan Solomakhin85b10da2019-11-05 20:03:17203 GURL google_pay_url(methods::kGooglePay);
204 GURL android_pay_url(methods::kAndroidPay);
Mathieu Perreault627b97c2017-08-12 00:44:22205 // Looking for payment methods that are NOT google-related payment methods.
206 auto non_google_it =
207 std::find_if(spec_->url_payment_method_identifiers().begin(),
208 spec_->url_payment_method_identifiers().end(),
209 [google_pay_url, android_pay_url](const GURL& url) {
210 return url != google_pay_url && url != android_pay_url;
211 });
212 journey_logger_.SetRequestedPaymentMethodTypes(
213 /*requested_basic_card=*/!spec_->supported_card_networks().empty(),
214 /*requested_method_google=*/
Jan Wilken Dörrie45d34f42019-06-08 09:40:54215 base::Contains(spec_->url_payment_method_identifiers(), google_pay_url) ||
216 base::Contains(spec_->url_payment_method_identifiers(),
217 android_pay_url),
Mathieu Perreault627b97c2017-08-12 00:44:22218 /*requested_method_other=*/non_google_it !=
219 spec_->url_payment_method_identifiers().end());
Rouslan Solomakhin1f95f092019-08-09 12:28:51220
221 payment_handler_host_.set_payment_request_id_for_logs(*spec_->details().id);
mathpf709499d2017-01-09 20:48:36222}
223
Rouslan Solomakhin9788d4b2019-04-09 13:10:23224void PaymentRequest::Show(bool is_user_gesture, bool wait_for_updated_details) {
Rouslan Solomakhin27064702018-12-14 21:15:33225 if (!IsInitialized()) {
Rouslan Solomakhina480efa2019-05-06 15:37:22226 log_.Error(errors::kCannotShowWithoutInit);
mathpf4bc50e2017-01-24 05:17:50227 OnConnectionTerminated();
tmartino8ce922852017-01-09 22:23:10228 return;
229 }
rouslan6e3cf7c62017-04-17 21:23:28230
Rouslan Solomakhin27064702018-12-14 21:15:33231 if (is_show_called_) {
Rouslan Solomakhina480efa2019-05-06 15:37:22232 log_.Error(errors::kCannotShowTwice);
Rouslan Solomakhin27064702018-12-14 21:15:33233 OnConnectionTerminated();
234 return;
235 }
236
237 is_show_called_ = true;
Sahel Sharify0fadf4da2019-08-09 14:55:58238 journey_logger_.SetTriggerTime();
Rouslan Solomakhin27064702018-12-14 21:15:33239
rouslan7d433cc22017-05-08 15:18:07240 // A tab can display only one PaymentRequest UI at a time.
Anthony Vallee-Dubois8f5e7e12018-01-12 16:14:06241 display_handle_ = display_manager_->TryShow(delegate_.get());
Anthony Vallee-Duboisc7ae7332017-12-19 20:44:07242 if (!display_handle_) {
Rouslan Solomakhina480efa2019-05-06 15:37:22243 log_.Error(errors::kAnotherUiShowing);
Sahel Sharifya50fc4c2019-05-28 14:53:22244 DCHECK(!has_recorded_completion_);
245 has_recorded_completion_ = true;
sebsg828269bc2017-06-09 19:11:12246 journey_logger_.SetNotShown(
247 JourneyLogger::NOT_SHOWN_REASON_CONCURRENT_REQUESTS);
Rouslan Solomakhin9c83b8a2019-06-24 20:50:03248 client_->OnError(mojom::PaymentErrorReason::ALREADY_SHOWING,
249 errors::kAnotherUiShowing);
rouslan7d433cc22017-05-08 15:18:07250 OnConnectionTerminated();
251 return;
252 }
253
Rouslan Solomakhin5b510432017-09-26 16:59:32254 if (!delegate_->IsBrowserWindowActive()) {
Rouslan Solomakhina480efa2019-05-06 15:37:22255 log_.Error(errors::kCannotShowInBackgroundTab);
Sahel Sharifya50fc4c2019-05-28 14:53:22256 DCHECK(!has_recorded_completion_);
257 has_recorded_completion_ = true;
Rouslan Solomakhin5b510432017-09-26 16:59:32258 journey_logger_.SetNotShown(JourneyLogger::NOT_SHOWN_REASON_OTHER);
Rouslan Solomakhin9c83b8a2019-06-24 20:50:03259 client_->OnError(mojom::PaymentErrorReason::USER_CANCEL,
260 errors::kCannotShowInBackgroundTab);
Rouslan Solomakhin5b510432017-09-26 16:59:32261 OnConnectionTerminated();
262 return;
263 }
264
Rouslan Solomakhind2cae95a2018-08-09 00:16:10265 if (!state_) {
Rouslan Solomakhin27064702018-12-14 21:15:33266 // SSL is not valid. Reject show with NotSupportedError, disconnect the
267 // mojo pipe, and destroy this object.
Rouslan Solomakhind5dcc322019-07-11 21:47:20268 AreRequestedMethodsSupportedCallback(false, reject_show_error_message_);
Rouslan Solomakhind2cae95a2018-08-09 00:16:10269 return;
270 }
271
Rouslan Solomakhin833f8512018-04-03 23:19:25272 is_show_user_gesture_ = is_user_gesture;
273
Rouslan Solomakhin9788d4b2019-04-09 13:10:23274 if (wait_for_updated_details) {
275 // Put |spec_| into uninitialized state, so the UI knows to show a spinner.
276 // This method does not block.
277 spec_->StartWaitingForUpdateWith(
278 PaymentRequestSpec::UpdateReason::INITIAL_PAYMENT_DETAILS);
Sahel Sharify98a2c2a2019-07-12 18:57:40279 } else {
280 DCHECK(spec_->details().total);
281 journey_logger_.RecordTransactionAmount(
282 spec_->details().total->amount->currency,
283 spec_->details().total->amount->value, false /*completed*/);
Rouslan Solomakhin9788d4b2019-04-09 13:10:23284 }
Takashi Sakamoto48a29702019-04-08 05:06:32285
Rouslan Solomakhin9788d4b2019-04-09 13:10:23286 display_handle_->Show(this);
Rouslan Solomakhin1dca2a922019-09-06 22:25:07287
288 state_->set_is_show_user_gesture(is_show_user_gesture_);
gogerald0a7ee6c2017-11-13 18:23:19289 state_->AreRequestedMethodsSupported(
290 base::BindOnce(&PaymentRequest::AreRequestedMethodsSupportedCallback,
291 weak_ptr_factory_.GetWeakPtr()));
292}
293
Jinho Bangbe463a22018-08-02 10:26:50294void PaymentRequest::Retry(mojom::PaymentValidationErrorsPtr errors) {
Rouslan Solomakhin27064702018-12-14 21:15:33295 if (!IsInitialized()) {
Rouslan Solomakhina480efa2019-05-06 15:37:22296 log_.Error(errors::kCannotRetryWithoutInit);
Jinho Bangcac8d9a02018-08-23 19:47:22297 OnConnectionTerminated();
298 return;
299 }
300
Rouslan Solomakhin27064702018-12-14 21:15:33301 if (!IsThisPaymentRequestShowing()) {
Rouslan Solomakhina480efa2019-05-06 15:37:22302 log_.Error(errors::kCannotRetryWithoutShow);
Jinho Bangcac8d9a02018-08-23 19:47:22303 OnConnectionTerminated();
304 return;
305 }
306
Jinho Bangbe463a22018-08-02 10:26:50307 std::string error;
308 if (!PaymentsValidators::IsValidPaymentValidationErrorsFormat(errors,
309 &error)) {
Rouslan Solomakhin27064702018-12-14 21:15:33310 log_.Error(error);
Rouslan Solomakhin9c83b8a2019-06-24 20:50:03311 client_->OnError(mojom::PaymentErrorReason::USER_CANCEL, error);
Jinho Bangbe463a22018-08-02 10:26:50312 OnConnectionTerminated();
313 return;
314 }
315
Sahel Sharifycf4e2132020-01-24 23:59:08316 state()->SetAvailablePaymentAppForRetry();
Jinho Bang092e7162018-09-06 23:41:19317 spec()->Retry(std::move(errors));
Jinho Bangcac8d9a02018-08-23 19:47:22318 display_handle_->Retry();
Jinho Bangbe463a22018-08-02 10:26:50319}
320
mathp151bd312017-04-03 21:07:24321void PaymentRequest::UpdateWith(mojom::PaymentDetailsPtr details) {
Rouslan Solomakhin27064702018-12-14 21:15:33322 if (!IsInitialized()) {
Rouslan Solomakhina480efa2019-05-06 15:37:22323 log_.Error(errors::kCannotUpdateWithoutInit);
Rouslan Solomakhin27064702018-12-14 21:15:33324 OnConnectionTerminated();
325 return;
326 }
327
328 if (!IsThisPaymentRequestShowing()) {
Rouslan Solomakhina480efa2019-05-06 15:37:22329 log_.Error(errors::kCannotUpdateWithoutShow);
Rouslan Solomakhin27064702018-12-14 21:15:33330 OnConnectionTerminated();
331 return;
332 }
333
mathp151bd312017-04-03 21:07:24334 std::string error;
Mohamad Ahmadif5544bb2017-09-01 21:48:22335 if (!ValidatePaymentDetails(ConvertPaymentDetails(details), &error)) {
Rouslan Solomakhin27064702018-12-14 21:15:33336 log_.Error(error);
mathp151bd312017-04-03 21:07:24337 OnConnectionTerminated();
338 return;
339 }
Rouslan Solomakhin4cbda822017-08-23 18:50:39340
Jinho Bang092e7162018-09-06 23:41:19341 if (details->shipping_address_errors &&
342 !PaymentsValidators::IsValidAddressErrorsFormat(
343 details->shipping_address_errors, &error)) {
Rouslan Solomakhin27064702018-12-14 21:15:33344 log_.Error(error);
Jinho Bang092e7162018-09-06 23:41:19345 OnConnectionTerminated();
346 return;
347 }
348
Rouslan Solomakhin5d15cb1f2019-11-11 18:11:39349 if (state()->selected_app() && state()->IsPaymentAppInvoked() &&
Sahel Sharifye2f889542019-12-02 22:17:48350 payment_handler_host_.is_waiting_for_payment_details_update()) {
Rouslan Solomakhin8e9f149b22019-05-10 17:43:02351 payment_handler_host_.UpdateWith(
Sahel Sharify47582212019-10-25 21:26:53352 PaymentDetailsConverter::ConvertToPaymentRequestDetailsUpdate(
Rouslan Solomakhin5d15cb1f2019-11-11 18:11:39353 details, state()->selected_app()->HandlesShippingAddress(),
354 base::BindRepeating(&PaymentApp::IsValidForPaymentMethodIdentifier,
355 state()->selected_app()->AsWeakPtr())));
Rouslan Solomakhina480efa2019-05-06 15:37:22356 }
357
Rouslan Solomakhin6ba46fd2019-04-11 23:44:01358 bool is_resolving_promise_passed_into_show_method = !spec_->IsInitialized();
359
mathp151bd312017-04-03 21:07:24360 spec_->UpdateWith(std::move(details));
Rouslan Solomakhin9788d4b2019-04-09 13:10:23361
362 if (is_resolving_promise_passed_into_show_method) {
Sahel Sharify98a2c2a2019-07-12 18:57:40363 DCHECK(spec_->details().total);
364 journey_logger_.RecordTransactionAmount(
365 spec_->details().total->amount->currency,
366 spec_->details().total->amount->value, false /*completed*/);
Rouslan Solomakhin9788d4b2019-04-09 13:10:23367 if (SatisfiesSkipUIConstraints()) {
Rouslan Solomakhin9788d4b2019-04-09 13:10:23368 Pay();
369 } else if (spec_->request_shipping()) {
370 state_->SelectDefaultShippingAddressAndNotifyObservers();
371 }
372 }
mathp151bd312017-04-03 21:07:24373}
374
Sahel Sharifye2f889542019-12-02 22:17:48375void PaymentRequest::OnPaymentDetailsNotUpdated() {
Rouslan Solomakhin27064702018-12-14 21:15:33376 // This Mojo call is triggered by the user of the API doing nothing in
377 // response to a shipping address update event, so the error messages cannot
378 // be more verbose.
379 if (!IsInitialized()) {
Rouslan Solomakhina480efa2019-05-06 15:37:22380 log_.Error(errors::kNotInitialized);
Rouslan Solomakhin27064702018-12-14 21:15:33381 OnConnectionTerminated();
382 return;
383 }
384
385 if (!IsThisPaymentRequestShowing()) {
Rouslan Solomakhina480efa2019-05-06 15:37:22386 log_.Error(errors::kNotShown);
Rouslan Solomakhin27064702018-12-14 21:15:33387 OnConnectionTerminated();
388 return;
389 }
390
Rouslan Solomakhina9ff9282017-10-31 21:58:05391 spec_->RecomputeSpecForDetails();
Rouslan Solomakhina480efa2019-05-06 15:37:22392
Sahel Sharifye2f889542019-12-02 22:17:48393 if (state()->IsPaymentAppInvoked() &&
394 payment_handler_host_.is_waiting_for_payment_details_update()) {
395 payment_handler_host_.OnPaymentDetailsNotUpdated();
Rouslan Solomakhincf9093f2019-05-20 15:32:17396 }
Rouslan Solomakhina9ff9282017-10-31 21:58:05397}
398
mathpf4bc50e2017-01-24 05:17:50399void PaymentRequest::Abort() {
Rouslan Solomakhin27064702018-12-14 21:15:33400 if (!IsInitialized()) {
Rouslan Solomakhina480efa2019-05-06 15:37:22401 log_.Error(errors::kCannotAbortWithoutInit);
Rouslan Solomakhin27064702018-12-14 21:15:33402 OnConnectionTerminated();
403 return;
404 }
405
406 if (!IsThisPaymentRequestShowing()) {
Rouslan Solomakhina480efa2019-05-06 15:37:22407 log_.Error(errors::kCannotAbortWithoutShow);
Rouslan Solomakhin27064702018-12-14 21:15:33408 OnConnectionTerminated();
409 return;
410 }
411
Anthony Vallee-Dubois6813c1442017-05-17 19:32:56412 // The API user has decided to abort. If a successful abort message is
413 // returned to the renderer, the Mojo message pipe is closed, which triggers
mathpf4bc50e2017-01-24 05:17:50414 // PaymentRequest::OnConnectionTerminated, which destroys this object.
Anthony Vallee-Dubois6813c1442017-05-17 19:32:56415 // Otherwise, the abort promise is rejected and the pipe is not closed.
416 // The abort is only successful if the payment app wasn't yet invoked.
417 // TODO(crbug.com/716546): Add a merchant abort metric
418
419 bool accepting_abort = !state_->IsPaymentAppInvoked();
sebsgfcdd13c2017-06-08 15:49:33420 if (accepting_abort)
421 RecordFirstAbortReason(JourneyLogger::ABORT_REASON_ABORTED_BY_MERCHANT);
Anthony Vallee-Dubois6813c1442017-05-17 19:32:56422
mathpf4bc50e2017-01-24 05:17:50423 if (client_.is_bound())
Anthony Vallee-Dubois6813c1442017-05-17 19:32:56424 client_->OnAbort(accepting_abort);
425
426 if (observer_for_testing_)
427 observer_for_testing_->OnAbortCalled();
Sahel Sharifyd3418222020-02-19 21:50:02428
429 if (accepting_abort)
430 state_->OnAbort();
mathpf4bc50e2017-01-24 05:17:50431}
432
mathp218795892017-03-29 15:15:34433void PaymentRequest::Complete(mojom::PaymentComplete result) {
Rouslan Solomakhin27064702018-12-14 21:15:33434 if (!IsInitialized()) {
Rouslan Solomakhina480efa2019-05-06 15:37:22435 log_.Error(errors::kCannotCompleteWithoutInit);
Rouslan Solomakhin27064702018-12-14 21:15:33436 OnConnectionTerminated();
mathp4b85b582017-03-08 21:07:16437 return;
Rouslan Solomakhin27064702018-12-14 21:15:33438 }
439
440 if (!IsThisPaymentRequestShowing()) {
Rouslan Solomakhina480efa2019-05-06 15:37:22441 log_.Error(errors::kCannotAbortWithoutShow);
Rouslan Solomakhin27064702018-12-14 21:15:33442 OnConnectionTerminated();
443 return;
444 }
mathp4b85b582017-03-08 21:07:16445
Sahel Sharify2a56b5f2019-11-28 19:27:19446 if (observer_for_testing_) {
447 observer_for_testing_->OnCompleteCalled();
448 }
449
Rouslan Solomakhine3473192017-06-16 14:54:57450 // Failed transactions show an error. Successful and unknown-state
451 // transactions don't show an error.
452 if (result == mojom::PaymentComplete::FAIL) {
mathp218795892017-03-29 15:15:34453 delegate_->ShowErrorMessage();
454 } else {
sebsgfcdd13c2017-06-08 15:49:33455 DCHECK(!has_recorded_completion_);
sebsgf8272a22017-05-26 14:32:58456 journey_logger_.SetCompleted();
sebsgfcdd13c2017-06-08 15:49:33457 has_recorded_completion_ = true;
Sahel Sharify98a2c2a2019-07-12 18:57:40458 DCHECK(spec_->details().total);
459 journey_logger_.RecordTransactionAmount(
460 spec_->details().total->amount->currency,
461 spec_->details().total->amount->value, true /*completed*/);
sebsgfcdd13c2017-06-08 15:49:33462
anthonyvd6a43b932017-05-11 18:39:27463 delegate_->GetPrefService()->SetBoolean(kPaymentsFirstTransactionCompleted,
464 true);
mathp218795892017-03-29 15:15:34465 // When the renderer closes the connection,
466 // PaymentRequest::OnConnectionTerminated will be called.
467 client_->OnComplete();
sebsg8a93b272017-05-11 19:30:22468 state_->RecordUseStats();
mathp218795892017-03-29 15:15:34469 }
mathp4b85b582017-03-08 21:07:16470}
471
Danyao Wang03a4cbd2019-08-15 23:47:11472void PaymentRequest::CanMakePayment() {
Rouslan Solomakhin27064702018-12-14 21:15:33473 if (!IsInitialized()) {
Rouslan Solomakhina480efa2019-05-06 15:37:22474 log_.Error(errors::kCannotCallCanMakePaymentWithoutInit);
Rouslan Solomakhin27064702018-12-14 21:15:33475 OnConnectionTerminated();
476 return;
477 }
478
479 // It's valid to call canMakePayment() without calling show() first.
480
gogerald8189d522017-09-15 17:52:18481 if (observer_for_testing_)
482 observer_for_testing_->OnCanMakePaymentCalled();
Mathieu Perreaultcacb85e2018-06-06 20:40:13483
Rouslan Solomakhind2cae95a2018-08-09 00:16:10484 if (!delegate_->GetPrefService()->GetBoolean(kCanMakePaymentEnabled) ||
485 !state_) {
Danyao Wang03a4cbd2019-08-15 23:47:11486 CanMakePaymentCallback(/*can_make_payment=*/false);
Mathieu Perreaultcacb85e2018-06-06 20:40:13487 } else {
Rouslan Solomakhind2cae95a2018-08-09 00:16:10488 state_->CanMakePayment(
Mathieu Perreaultcacb85e2018-06-06 20:40:13489 base::BindOnce(&PaymentRequest::CanMakePaymentCallback,
Danyao Wang03a4cbd2019-08-15 23:47:11490 weak_ptr_factory_.GetWeakPtr()));
Mathieu Perreaultcacb85e2018-06-06 20:40:13491 }
gogerald8189d522017-09-15 17:52:18492}
493
Rouslan Solomakhin5683eb282019-01-29 18:06:03494void PaymentRequest::HasEnrolledInstrument(bool per_method_quota) {
Danyao Wangce175bf2018-12-21 22:35:58495 if (!IsInitialized()) {
Rouslan Solomakhina480efa2019-05-06 15:37:22496 log_.Error(errors::kCannotCallHasEnrolledInstrumentWithoutInit);
Danyao Wangce175bf2018-12-21 22:35:58497 OnConnectionTerminated();
498 return;
499 }
500
501 // It's valid to call hasEnrolledInstrument() without calling show() first.
502
503 if (observer_for_testing_)
504 observer_for_testing_->OnHasEnrolledInstrumentCalled();
505
506 if (!delegate_->GetPrefService()->GetBoolean(kCanMakePaymentEnabled) ||
507 !state_) {
Rouslan Solomakhin5683eb282019-01-29 18:06:03508 HasEnrolledInstrumentCallback(per_method_quota,
509 /*has_enrolled_instrument=*/false);
Danyao Wangce175bf2018-12-21 22:35:58510 } else {
511 state_->HasEnrolledInstrument(
512 base::BindOnce(&PaymentRequest::HasEnrolledInstrumentCallback,
Rouslan Solomakhin5683eb282019-01-29 18:06:03513 weak_ptr_factory_.GetWeakPtr(), per_method_quota));
Danyao Wangce175bf2018-12-21 22:35:58514 }
515}
516
Rouslan Solomakhin8e9f149b22019-05-10 17:43:02517bool PaymentRequest::ChangePaymentMethod(const std::string& method_name,
518 const std::string& stringified_data) {
Rouslan Solomakhina480efa2019-05-06 15:37:22519 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
Rouslan Solomakhin8e9f149b22019-05-10 17:43:02520 DCHECK(!method_name.empty());
Rouslan Solomakhina480efa2019-05-06 15:37:22521
Rouslan Solomakhin8e9f149b22019-05-10 17:43:02522 if (!state_ || !state_->IsPaymentAppInvoked() || !client_)
523 return false;
Rouslan Solomakhina480efa2019-05-06 15:37:22524
Rouslan Solomakhin8e9f149b22019-05-10 17:43:02525 client_->OnPaymentMethodChange(method_name, stringified_data);
526 return true;
Rouslan Solomakhina480efa2019-05-06 15:37:22527}
528
Sahel Sharify9d98a502019-09-30 19:58:39529bool PaymentRequest::ChangeShippingOption(
530 const std::string& shipping_option_id) {
531 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
532 DCHECK(!shipping_option_id.empty());
533
534 bool is_valid_id = false;
535 if (spec_->details().shipping_options) {
536 for (const auto& option : spec_->GetShippingOptions()) {
537 if (option->id == shipping_option_id) {
538 is_valid_id = true;
539 break;
540 }
541 }
542 }
543
544 if (!state_ || !state_->IsPaymentAppInvoked() || !client_ || !spec_ ||
545 !spec_->request_shipping() || !is_valid_id) {
546 return false;
547 }
548
549 client_->OnShippingOptionChange(shipping_option_id);
550 return true;
551}
552
553bool PaymentRequest::ChangeShippingAddress(
554 mojom::PaymentAddressPtr shipping_address) {
555 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
556 DCHECK(shipping_address);
557
558 if (!state_ || !state_->IsPaymentAppInvoked() || !client_ || !spec_ ||
559 !spec_->request_shipping()) {
560 return false;
561 }
562
563 client_->OnShippingAddressChange(
564 RedactShippingAddress(std::move(shipping_address)));
565 return true;
566}
567
Rouslan Solomakhin27064702018-12-14 21:15:33568void PaymentRequest::AreRequestedMethodsSupportedCallback(
Rouslan Solomakhind5dcc322019-07-11 21:47:20569 bool methods_supported,
570 const std::string& error_message) {
Danyao Wang25f72dc2019-10-18 05:11:32571 if (is_show_called_ && observer_for_testing_)
Rouslan Solomakhin5d15cb1f2019-11-11 18:11:39572 observer_for_testing_->OnShowAppsReady();
Danyao Wang25f72dc2019-10-18 05:11:32573
Rouslan Solomakhin27064702018-12-14 21:15:33574 if (methods_supported) {
Sahel Sharifyd3f1bc82019-05-21 18:48:46575 if (SatisfiesSkipUIConstraints())
Rouslan Solomakhin27064702018-12-14 21:15:33576 Pay();
Rouslan Solomakhin27064702018-12-14 21:15:33577 } else {
Sahel Sharifya50fc4c2019-05-28 14:53:22578 DCHECK(!has_recorded_completion_);
579 has_recorded_completion_ = true;
Rouslan Solomakhin27064702018-12-14 21:15:33580 journey_logger_.SetNotShown(
581 JourneyLogger::NOT_SHOWN_REASON_NO_SUPPORTED_PAYMENT_METHOD);
Rouslan Solomakhin9c83b8a2019-06-24 20:50:03582 client_->OnError(mojom::PaymentErrorReason::NOT_SUPPORTED,
Rouslan Solomakhind5dcc322019-07-11 21:47:20583 GetNotSupportedErrorMessage(spec_.get()) +
584 (error_message.empty() ? "" : " " + error_message));
Rouslan Solomakhin27064702018-12-14 21:15:33585 if (observer_for_testing_)
586 observer_for_testing_->OnNotSupportedError();
587 OnConnectionTerminated();
588 }
589}
590
591bool PaymentRequest::IsInitialized() const {
592 return is_initialized_ && client_ && client_.is_bound() &&
Gyuyoung Kim9cfbda32019-08-27 02:15:18593 receiver_.is_bound();
Rouslan Solomakhin27064702018-12-14 21:15:33594}
595
596bool PaymentRequest::IsThisPaymentRequestShowing() const {
597 return is_show_called_ && display_handle_ && spec_ && state_;
598}
599
Sahel Sharify9120fd32019-12-05 17:16:11600bool PaymentRequest::OnlySingleAppCanProvideAllRequiredInformation() const {
601 DCHECK(state()->IsInitialized());
602 DCHECK(spec()->IsInitialized());
603
604 if (!spec()->request_shipping() && !spec()->request_payer_name() &&
605 !spec()->request_payer_phone() && !spec()->request_payer_email()) {
606 return state()->available_apps().size() == 1 &&
607 state()->available_apps().at(0)->type() !=
608 PaymentApp::Type::AUTOFILL;
609 }
610
611 bool an_app_can_provide_all_info = false;
612 for (const auto& app : state()->available_apps()) {
613 if ((!spec()->request_shipping() || app->HandlesShippingAddress()) &&
614 (!spec()->request_payer_name() || app->HandlesPayerName()) &&
615 (!spec()->request_payer_phone() || app->HandlesPayerPhone()) &&
616 (!spec()->request_payer_email() || app->HandlesPayerEmail())) {
617 // There is another available app that can provide all merchant requested
618 // information information.
619 if (an_app_can_provide_all_info)
620 return false;
621
622 an_app_can_provide_all_info = true;
623 }
624 }
625 return an_app_can_provide_all_info;
626}
627
Sahel Sharifyd3f1bc82019-05-21 18:48:46628bool PaymentRequest::SatisfiesSkipUIConstraints() {
Rouslan Solomakhin9788d4b2019-04-09 13:10:23629 // Only allowing URL base payment apps to skip the payment sheet.
Sahel Sharifyd3f1bc82019-05-21 18:48:46630 skipped_payment_request_ui_ =
Sahel Sharify9120fd32019-12-05 17:16:11631 (spec()->url_payment_method_identifiers().size() > 0 ||
danakjdca06902019-06-27 21:41:41632 delegate_->SkipUiForBasicCard()) &&
Sahel Sharifyd3f1bc82019-05-21 18:48:46633 base::FeatureList::IsEnabled(features::kWebPaymentsSingleAppUiSkip) &&
634 base::FeatureList::IsEnabled(::features::kServiceWorkerPaymentApps) &&
635 is_show_user_gesture_ && state()->IsInitialized() &&
Sahel Sharify9120fd32019-12-05 17:16:11636 spec()->IsInitialized() &&
637 OnlySingleAppCanProvideAllRequiredInformation() &&
Sahel Sharify90307872019-12-02 17:28:14638 // The available app should be preselectable.
Sahel Sharify9120fd32019-12-05 17:16:11639 state()->selected_app() != nullptr;
Sahel Sharifyd3f1bc82019-05-21 18:48:46640 if (skipped_payment_request_ui_) {
641 DCHECK(state()->IsInitialized() && spec()->IsInitialized());
642 journey_logger_.SetEventOccurred(JourneyLogger::EVENT_SKIPPED_SHOW);
643 } else if (state()->IsInitialized() && spec()->IsInitialized()) {
644 // Set EVENT_SHOWN only after state() and spec() initialization.
645 journey_logger_.SetEventOccurred(JourneyLogger::EVENT_SHOWN);
646 }
647 return skipped_payment_request_ui_;
Rouslan Solomakhin27064702018-12-14 21:15:33648}
649
mathpf1a7a3752017-03-15 11:23:37650void PaymentRequest::OnPaymentResponseAvailable(
651 mojom::PaymentResponsePtr response) {
Rouslan Solomakhin68429b72019-06-27 15:12:39652 DCHECK(!response->method_name.empty());
653 DCHECK(!response->stringified_details.empty());
654
mathp57c8c862017-06-16 20:15:45655 journey_logger_.SetEventOccurred(
656 JourneyLogger::EVENT_RECEIVED_INSTRUMENT_DETAILS);
gogerald7a2b761e2017-11-09 18:30:19657
Sahel Sharify26884382019-05-07 16:23:51658 // Log the correct "selected instrument" metric according to its type and
659 // the method name in response.
Rouslan Solomakhin5d15cb1f2019-11-11 18:11:39660 DCHECK(state_->selected_app());
Sahel Sharify26884382019-05-07 16:23:51661 JourneyLogger::Event selected_event =
662 JourneyLogger::Event::EVENT_SELECTED_OTHER;
Rouslan Solomakhin5d15cb1f2019-11-11 18:11:39663 switch (state_->selected_app()->type()) {
664 case PaymentApp::Type::AUTOFILL:
Sahel Sharify26884382019-05-07 16:23:51665 selected_event = JourneyLogger::Event::EVENT_SELECTED_CREDIT_CARD;
666 break;
Rouslan Solomakhin5d15cb1f2019-11-11 18:11:39667 case PaymentApp::Type::SERVICE_WORKER_APP: {
668 selected_event = IsGooglePaymentMethod(response->method_name)
669 ? JourneyLogger::Event::EVENT_SELECTED_GOOGLE
670 : JourneyLogger::Event::EVENT_SELECTED_OTHER;
Sahel Sharify26884382019-05-07 16:23:51671 break;
672 }
Rouslan Solomakhin5d15cb1f2019-11-11 18:11:39673 case PaymentApp::Type::NATIVE_MOBILE_APP:
Sahel Sharify26884382019-05-07 16:23:51674 NOTREACHED();
675 break;
676 }
677 journey_logger_.SetEventOccurred(selected_event);
678
Rouslan Solomakhin02d086ec2019-01-31 23:10:39679 // If currently interactive, show the processing spinner. Autofill payment
Rouslan Solomakhin5d15cb1f2019-11-11 18:11:39680 // apps request a CVC, so they are always interactive at this point. A payment
681 // handler may elect to be non-interactive by not showing a confirmation page
682 // to the user.
Rouslan Solomakhin02d086ec2019-01-31 23:10:39683 if (delegate_->IsInteractive())
684 delegate_->ShowProcessingSpinner();
685
mathpf1a7a3752017-03-15 11:23:37686 client_->OnPaymentResponse(std::move(response));
mathp4b85b582017-03-08 21:07:16687}
688
Rouslan Solomakhin68429b72019-06-27 15:12:39689void PaymentRequest::OnPaymentResponseError(const std::string& error_message) {
690 journey_logger_.SetEventOccurred(
691 JourneyLogger::EVENT_RECEIVED_INSTRUMENT_DETAILS);
692 RecordFirstAbortReason(JourneyLogger::ABORT_REASON_INSTRUMENT_DETAILS_ERROR);
693
694 reject_show_error_message_ = error_message;
695 delegate_->ShowErrorMessage();
696 // When the user dismisses the error message, UserCancelled() will reject
697 // PaymentRequest.show() with |reject_show_error_message_|.
698}
699
mathp151bd312017-04-03 21:07:24700void PaymentRequest::OnShippingOptionIdSelected(
701 std::string shipping_option_id) {
702 client_->OnShippingOptionChange(shipping_option_id);
703}
704
705void PaymentRequest::OnShippingAddressSelected(
706 mojom::PaymentAddressPtr address) {
Sahel Sharify9d98a502019-09-30 19:58:39707 client_->OnShippingAddressChange(RedactShippingAddress(std::move(address)));
mathp151bd312017-04-03 21:07:24708}
709
Jinho Bangbb178152018-09-13 09:44:43710void PaymentRequest::OnPayerInfoSelected(mojom::PayerDetailPtr payer_info) {
711 client_->OnPayerDetailChange(std::move(payer_info));
712}
713
Rouslan Solomakhin1f95f092019-08-09 12:28:51714void PaymentRequest::SetInvokedServiceWorkerIdentity(const url::Origin& origin,
715 int64_t registration_id) {
716 payment_handler_host_.set_sw_origin_for_logs(origin);
717 payment_handler_host_.set_registration_id_for_logs(registration_id);
718}
719
mathpf4bc50e2017-01-24 05:17:50720void PaymentRequest::UserCancelled() {
721 // If |client_| is not bound, then the object is already being destroyed as
722 // a result of a renderer event.
723 if (!client_.is_bound())
724 return;
725
sebsgfcdd13c2017-06-08 15:49:33726 RecordFirstAbortReason(JourneyLogger::ABORT_REASON_ABORTED_BY_USER);
sebsg20b49d7b2017-05-04 20:23:17727
mathpf4bc50e2017-01-24 05:17:50728 // This sends an error to the renderer, which informs the API user.
Rouslan Solomakhin9c83b8a2019-06-24 20:50:03729 client_->OnError(mojom::PaymentErrorReason::USER_CANCEL,
Rouslan Solomakhin68429b72019-06-27 15:12:39730 !reject_show_error_message_.empty()
731 ? reject_show_error_message_
732 : errors::kUserCancelled);
mathpf4bc50e2017-01-24 05:17:50733
734 // We close all bindings and ask to be destroyed.
735 client_.reset();
Gyuyoung Kim9cfbda32019-08-27 02:15:18736 receiver_.reset();
Rouslan Solomakhin8e9f149b22019-05-10 17:43:02737 payment_handler_host_.Disconnect();
rouslanb28f4532017-05-08 15:41:47738 if (observer_for_testing_)
739 observer_for_testing_->OnConnectionTerminated();
mathpf4bc50e2017-01-24 05:17:50740 manager_->DestroyRequest(this);
mathpf709499d2017-01-09 20:48:36741}
742
sebsgd56b3e422017-10-20 18:08:08743void PaymentRequest::DidStartMainFrameNavigationToDifferentDocument(
744 bool is_user_initiated) {
sebsgfcdd13c2017-06-08 15:49:33745 RecordFirstAbortReason(is_user_initiated
746 ? JourneyLogger::ABORT_REASON_USER_NAVIGATION
747 : JourneyLogger::ABORT_REASON_MERCHANT_NAVIGATION);
sebsg2c8558a2017-05-17 18:54:10748}
749
mathpf4bc50e2017-01-24 05:17:50750void PaymentRequest::OnConnectionTerminated() {
751 // We are here because of a browser-side error, or likely as a result of the
Gyuyoung Kim9cfbda32019-08-27 02:15:18752 // disconnect_handler on |receiver_|, which can mean that the renderer
mathpf4bc50e2017-01-24 05:17:50753 // has decided to close the pipe for various reasons (see all uses of
754 // PaymentRequest::clearResolversAndCloseMojoConnection() in Blink). We close
755 // the binding and the dialog, and ask to be deleted.
756 client_.reset();
Gyuyoung Kim9cfbda32019-08-27 02:15:18757 receiver_.reset();
Rouslan Solomakhin8e9f149b22019-05-10 17:43:02758 payment_handler_host_.Disconnect();
mathpf4bc50e2017-01-24 05:17:50759 delegate_->CloseDialog();
rouslanb28f4532017-05-08 15:41:47760 if (observer_for_testing_)
761 observer_for_testing_->OnConnectionTerminated();
sebsgfcdd13c2017-06-08 15:49:33762
763 RecordFirstAbortReason(JourneyLogger::ABORT_REASON_MOJO_CONNECTION_ERROR);
mathpf709499d2017-01-09 20:48:36764 manager_->DestroyRequest(this);
765}
766
mathpd4be8de82017-03-01 00:51:48767void PaymentRequest::Pay() {
mathp57c8c862017-06-16 20:15:45768 journey_logger_.SetEventOccurred(JourneyLogger::EVENT_PAY_CLICKED);
Rouslan Solomakhin5d15cb1f2019-11-11 18:11:39769 DCHECK(state_->selected_app());
770 if (state_->selected_app()->type() == PaymentApp::Type::SERVICE_WORKER_APP) {
771 static_cast<ServiceWorkerPaymentApp*>(state_->selected_app())
Rouslan Solomakhin8e9f149b22019-05-10 17:43:02772 ->set_payment_handler_host(payment_handler_host_.Bind());
Mathieu Perreault23d25bfb82018-05-11 14:45:37773 }
mathpf1a7a3752017-03-15 11:23:37774 state_->GeneratePaymentResponse();
mathpd4be8de82017-03-01 00:51:48775}
776
Anthony Vallee-Duboisc7ae7332017-12-19 20:44:07777void PaymentRequest::HideIfNecessary() {
778 display_handle_.reset();
779}
780
Anthony Vallee-Dubois10d131a2018-02-22 15:41:04781bool PaymentRequest::IsIncognito() const {
782 return delegate_->IsIncognito();
783}
784
sebsgfcdd13c2017-06-08 15:49:33785void PaymentRequest::RecordFirstAbortReason(
786 JourneyLogger::AbortReason abort_reason) {
787 if (!has_recorded_completion_) {
788 has_recorded_completion_ = true;
789 journey_logger_.SetAborted(abort_reason);
sebsg2c8558a2017-05-17 18:54:10790 }
791}
792
Danyao Wang03a4cbd2019-08-15 23:47:11793void PaymentRequest::CanMakePaymentCallback(bool can_make_payment) {
794 client_->OnCanMakePayment(
795 can_make_payment ? mojom::CanMakePaymentQueryResult::CAN_MAKE_PAYMENT
796 : mojom::CanMakePaymentQueryResult::CANNOT_MAKE_PAYMENT);
Danyao Wang4bc0606a2018-12-27 16:54:53797
Danyao Wang57aa0442019-01-31 04:06:41798 journey_logger_.SetCanMakePaymentValue(can_make_payment);
Rouslan Solomakhin1804ee42017-10-03 14:27:43799
800 if (observer_for_testing_)
801 observer_for_testing_->OnCanMakePaymentReturned();
802}
803
Danyao Wangce175bf2018-12-21 22:35:58804void PaymentRequest::HasEnrolledInstrumentCallback(
Rouslan Solomakhin5683eb282019-01-29 18:06:03805 bool per_method_quota,
Danyao Wangce175bf2018-12-21 22:35:58806 bool has_enrolled_instrument) {
Rouslan Solomakhinb26faa072019-08-19 14:42:28807 if (!spec_ || CanMakePaymentQueryFactory::GetInstance()
808 ->GetForContext(web_contents_->GetBrowserContext())
809 ->CanQuery(top_level_origin_, frame_origin_,
810 spec_->query_for_quota(), per_method_quota)) {
Danyao Wangce175bf2018-12-21 22:35:58811 RespondToHasEnrolledInstrumentQuery(has_enrolled_instrument,
Rouslan Solomakhin77a7e1a2019-05-23 17:37:58812 /*warn_local_development=*/false);
813 } else if (UrlUtil::IsLocalDevelopmentUrl(frame_origin_)) {
Danyao Wangce175bf2018-12-21 22:35:58814 RespondToHasEnrolledInstrumentQuery(has_enrolled_instrument,
Rouslan Solomakhin77a7e1a2019-05-23 17:37:58815 /*warn_local_development=*/true);
Danyao Wangce175bf2018-12-21 22:35:58816 } else {
817 client_->OnHasEnrolledInstrument(
818 HasEnrolledInstrumentQueryResult::QUERY_QUOTA_EXCEEDED);
819 }
820
821 if (observer_for_testing_)
822 observer_for_testing_->OnHasEnrolledInstrumentReturned();
823}
824
Danyao Wangce175bf2018-12-21 22:35:58825void PaymentRequest::RespondToHasEnrolledInstrumentQuery(
826 bool has_enrolled_instrument,
Rouslan Solomakhin77a7e1a2019-05-23 17:37:58827 bool warn_local_development) {
Danyao Wangce175bf2018-12-21 22:35:58828 HasEnrolledInstrumentQueryResult positive =
Rouslan Solomakhin77a7e1a2019-05-23 17:37:58829 warn_local_development
Danyao Wangce175bf2018-12-21 22:35:58830 ? HasEnrolledInstrumentQueryResult::WARNING_HAS_ENROLLED_INSTRUMENT
831 : HasEnrolledInstrumentQueryResult::HAS_ENROLLED_INSTRUMENT;
832 HasEnrolledInstrumentQueryResult negative =
Rouslan Solomakhin77a7e1a2019-05-23 17:37:58833 warn_local_development
Danyao Wangce175bf2018-12-21 22:35:58834 ? HasEnrolledInstrumentQueryResult::WARNING_HAS_NO_ENROLLED_INSTRUMENT
835 : HasEnrolledInstrumentQueryResult::HAS_NO_ENROLLED_INSTRUMENT;
836
837 client_->OnHasEnrolledInstrument(has_enrolled_instrument ? positive
838 : negative);
Danyao Wang57aa0442019-01-31 04:06:41839 journey_logger_.SetHasEnrolledInstrumentValue(has_enrolled_instrument);
Danyao Wangce175bf2018-12-21 22:35:58840}
841
mathpf709499d2017-01-09 20:48:36842} // namespace payments