blob: 18ca4f9cbe085b09b992d345306746b58fca5823 [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"
Rouslan Solomakhina480efa2019-05-06 15:37:2220#include "components/payments/content/service_worker_payment_instrument.h"
rouslan690997682017-05-09 18:07:3921#include "components/payments/core/can_make_payment_query.h"
Rouslan Solomakhina480efa2019-05-06 15:37:2222#include "components/payments/core/error_strings.h"
Anthony Vallee-Dubois968ae4d2018-03-15 16:56:3623#include "components/payments/core/features.h"
Rouslan Solomakhin85b10da2019-11-05 20:03:1724#include "components/payments/core/method_strings.h"
Rouslan Solomakhineb06b272019-07-10 16:23:3225#include "components/payments/core/native_error_strings.h"
Mohamad Ahmadif5544bb2017-09-01 21:48:2226#include "components/payments/core/payment_details.h"
27#include "components/payments/core/payment_details_validation.h"
Mathieu Perreault23d25bfb82018-05-11 14:45:3728#include "components/payments/core/payment_instrument.h"
anthonyvd6a43b932017-05-11 18:39:2729#include "components/payments/core/payment_prefs.h"
Danyao Wang50ccb9f2019-05-09 23:28:0330#include "components/payments/core/payments_experimental_features.h"
Jinho Bangbe463a22018-08-02 10:26:5031#include "components/payments/core/payments_validators.h"
Rouslan Solomakhin77a7e1a2019-05-23 17:37:5832#include "components/payments/core/url_util.h"
anthonyvd6a43b932017-05-11 18:39:2733#include "components/prefs/pref_service.h"
Steven Holte2083e8bc2018-07-16 23:50:3634#include "components/ukm/content/source_url_recorder.h"
Rouslan Solomakhin6e979ab2017-08-30 17:30:3935#include "components/url_formatter/elide_url.h"
mathpf709499d2017-01-09 20:48:3636#include "content/public/browser/browser_thread.h"
rouslan690997682017-05-09 18:07:3937#include "content/public/browser/render_frame_host.h"
mathpf709499d2017-01-09 20:48:3638#include "content/public/browser/web_contents.h"
Rouslan Solomakhin1804ee42017-10-03 14:27:4339#include "content/public/common/content_features.h"
Rouslan Solomakhin77a7e1a2019-05-23 17:37:5840#include "content/public/common/origin_util.h"
mathpf709499d2017-01-09 20:48:3641
Rouslan Solomakhina480efa2019-05-06 15:37:2242namespace payments {
Danyao Wangce175bf2018-12-21 22:35:5843namespace {
44
Danyao Wang57aa0442019-01-31 04:06:4145using ::payments::mojom::CanMakePaymentQueryResult;
Danyao Wangce175bf2018-12-21 22:35:5846using ::payments::mojom::HasEnrolledInstrumentQueryResult;
47
Sahel Sharify26884382019-05-07 16:23:5148bool IsGooglePaymentMethodInstrumentSelected(const std::string& method_name) {
Rouslan Solomakhin85b10da2019-11-05 20:03:1749 return method_name == methods::kGooglePay ||
50 method_name == methods::kAndroidPay;
Sahel Sharify26884382019-05-07 16:23:5151}
52
Rouslan Solomakhin9c83b8a2019-06-24 20:50:0353std::string GetNotSupportedErrorMessage(PaymentRequestSpec* spec) {
54 if (!spec || spec->payment_method_identifiers_set().empty())
55 return errors::kGenericPaymentMethodNotSupportedMessage;
56
57 std::vector<std::string> method_names(
58 spec->payment_method_identifiers_set().size());
59 std::transform(
60 spec->payment_method_identifiers_set().begin(),
61 spec->payment_method_identifiers_set().end(), method_names.begin(),
62 [](const std::string& method_name) { return "\"" + method_name + "\""; });
63
64 std::string output;
65 bool replaced = base::ReplaceChars(
66 method_names.size() == 1
67 ? errors::kSinglePaymentMethodNotSupportedFormat
68 : errors::kMultiplePaymentMethodsNotSupportedFormat,
69 "$", base::JoinString(method_names, ", "), &output);
70 DCHECK(replaced);
71 return output;
72}
73
Sahel Sharify9d98a502019-09-30 19:58:3974// Redact shipping address before exposing it in ShippingAddressChangeEvent.
75// https://w3c.github.io/payment-request/#shipping-address-changed-algorithm
76mojom::PaymentAddressPtr RedactShippingAddress(
77 mojom::PaymentAddressPtr address) {
78 DCHECK(address);
79 if (!PaymentsExperimentalFeatures::IsEnabled(
80 features::kWebPaymentsRedactShippingAddress)) {
81 return address;
82 }
83 address->organization.clear();
84 address->phone.clear();
85 address->recipient.clear();
86 address->address_line.clear();
87 return address;
88}
89
Rouslan Solomakhina480efa2019-05-06 15:37:2290} // namespace
mathpf709499d2017-01-09 20:48:3691
92PaymentRequest::PaymentRequest(
rouslan690997682017-05-09 18:07:3993 content::RenderFrameHost* render_frame_host,
mathpf709499d2017-01-09 20:48:3694 content::WebContents* web_contents,
Rouslan Solomakhin4eea9bc22017-10-10 15:18:5195 std::unique_ptr<ContentPaymentRequestDelegate> delegate,
mathpf709499d2017-01-09 20:48:3696 PaymentRequestWebContentsManager* manager,
Anthony Vallee-Duboisc7ae7332017-12-19 20:44:0797 PaymentRequestDisplayManager* display_manager,
Gyuyoung Kim9cfbda32019-08-27 02:15:1898 mojo::PendingReceiver<mojom::PaymentRequest> receiver,
mathp300fa542017-03-27 19:29:3799 ObserverForTest* observer_for_testing)
mathpf709499d2017-01-09 20:48:36100 : web_contents_(web_contents),
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())),
sebsg20b49d7b2017-05-04 20:23:17111 observer_for_testing_(observer_for_testing),
112 journey_logger_(delegate_->IsIncognito(),
Jeremy Roman5c341f6d2019-07-15 15:56:10113 ukm::GetSourceIdForWebContentsDocument(web_contents)) {
Gyuyoung Kim9cfbda32019-08-27 02:15:18114 receiver_.Bind(std::move(receiver));
mathpf4bc50e2017-01-24 05:17:50115 // OnConnectionTerminated will be called when the Mojo pipe is closed. This
116 // will happen as a result of many renderer-side events (both successful and
117 // erroneous in nature).
118 // TODO(crbug.com/683636): Investigate using
119 // set_connection_error_with_reason_handler with Binding::CloseWithReason.
Gyuyoung Kim9cfbda32019-08-27 02:15:18120 receiver_.set_disconnect_handler(base::BindOnce(
Anthony Vallee-Duboisdc1dbf1a2017-07-17 15:01:13121 &PaymentRequest::OnConnectionTerminated, weak_ptr_factory_.GetWeakPtr()));
mathpf709499d2017-01-09 20:48:36122}
123
124PaymentRequest::~PaymentRequest() {}
125
Gyuyoung Kim9cfbda32019-08-27 02:15:18126void PaymentRequest::Init(
127 mojo::PendingRemote<mojom::PaymentRequestClient> client,
128 std::vector<mojom::PaymentMethodDataPtr> method_data,
129 mojom::PaymentDetailsPtr details,
130 mojom::PaymentOptionsPtr options) {
mathpf709499d2017-01-09 20:48:36131 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
Rouslan Solomakhin27064702018-12-14 21:15:33132
133 if (is_initialized_) {
Rouslan Solomakhina480efa2019-05-06 15:37:22134 log_.Error(errors::kAttemptedInitializationTwice);
Rouslan Solomakhin27064702018-12-14 21:15:33135 OnConnectionTerminated();
136 return;
137 }
138
139 is_initialized_ = true;
Gyuyoung Kim9cfbda32019-08-27 02:15:18140 client_.Bind(std::move(client));
rouslan6e3cf7c62017-04-17 21:23:28141
rouslanb28f4532017-05-08 15:41:47142 const GURL last_committed_url = delegate_->GetLastCommittedURL();
Rouslan Solomakhin77a7e1a2019-05-23 17:37:58143 if (!content::IsOriginSecure(last_committed_url)) {
Rouslan Solomakhina480efa2019-05-06 15:37:22144 log_.Error(errors::kNotInASecureOrigin);
rouslan6e3cf7c62017-04-17 21:23:28145 OnConnectionTerminated();
146 return;
147 }
148
Rouslan Solomakhin55db8272019-06-25 18:16:28149 // TODO(crbug.com/978471): Improve architecture for handling prohibited
150 // origins and invalid SSL certificates.
rouslanb28f4532017-05-08 15:41:47151 bool allowed_origin =
Rouslan Solomakhin77a7e1a2019-05-23 17:37:58152 UrlUtil::IsOriginAllowedToUseWebPaymentApis(last_committed_url);
rouslanb28f4532017-05-08 15:41:47153 if (!allowed_origin) {
Rouslan Solomakhin68429b72019-06-27 15:12:39154 reject_show_error_message_ = errors::kProhibitedOrigin;
rouslanb28f4532017-05-08 15:41:47155 }
156
Rouslan Solomakhin55db8272019-06-25 18:16:28157 bool invalid_ssl = false;
158 if (last_committed_url.SchemeIsCryptographic()) {
Rouslan Solomakhin68429b72019-06-27 15:12:39159 DCHECK(reject_show_error_message_.empty());
160 reject_show_error_message_ =
Rouslan Solomakhin55db8272019-06-25 18:16:28161 delegate_->GetInvalidSslCertificateErrorMessage();
Rouslan Solomakhin68429b72019-06-27 15:12:39162 invalid_ssl = !reject_show_error_message_.empty();
Rouslan Solomakhin27064702018-12-14 21:15:33163 }
rouslanb28f4532017-05-08 15:41:47164
165 if (!allowed_origin || invalid_ssl) {
Rouslan Solomakhin27064702018-12-14 21:15:33166 // Intentionally don't set |spec_| and |state_|, so the UI is never shown.
Rouslan Solomakhin68429b72019-06-27 15:12:39167 log_.Error(reject_show_error_message_);
Rouslan Solomakhina480efa2019-05-06 15:37:22168 log_.Error(errors::kProhibitedOriginOrInvalidSslExplanation);
rouslan6e3cf7c62017-04-17 21:23:28169 return;
170 }
171
mathpf709499d2017-01-09 20:48:36172 std::string error;
Mohamad Ahmadif5544bb2017-09-01 21:48:22173 if (!ValidatePaymentDetails(ConvertPaymentDetails(details), &error)) {
Rouslan Solomakhin27064702018-12-14 21:15:33174 log_.Error(error);
mathpf4bc50e2017-01-24 05:17:50175 OnConnectionTerminated();
mathpf709499d2017-01-09 20:48:36176 return;
177 }
rouslan6e3cf7c62017-04-17 21:23:28178
jinho.bangfcb5ec92017-03-29 08:08:02179 if (!details->total) {
Rouslan Solomakhina480efa2019-05-06 15:37:22180 log_.Error(errors::kTotalRequired);
jinho.bangfcb5ec92017-03-29 08:08:02181 OnConnectionTerminated();
182 return;
183 }
rouslan6e3cf7c62017-04-17 21:23:28184
sebsga70a6da2017-12-21 22:27:02185 spec_ = std::make_unique<PaymentRequestSpec>(
Rouslan Solomakhin1f95f092019-08-09 12:28:51186 std::move(options), std::move(details), std::move(method_data),
187 /*observer=*/this, delegate_->GetApplicationLocale());
sebsga70a6da2017-12-21 22:27:02188 state_ = std::make_unique<PaymentRequestState>(
Rouslan Solomakhin1f95f092019-08-09 12:28:51189 web_contents_, top_level_origin_, frame_origin_, spec_.get(),
190 /*delegate=*/this, delegate_->GetApplicationLocale(),
191 delegate_->GetPersonalDataManager(), delegate_.get(),
Rouslan Solomakhin65552292019-08-29 17:28:21192 /*sw_identity_observer=*/weak_ptr_factory_.GetWeakPtr(),
193 &journey_logger_);
Mathieu Perreault627b97c2017-08-12 00:44:22194
195 journey_logger_.SetRequestedInformation(
196 spec_->request_shipping(), spec_->request_payer_email(),
197 spec_->request_payer_phone(), spec_->request_payer_name());
198
199 // Log metrics around which payment methods are requested by the merchant.
Rouslan Solomakhin85b10da2019-11-05 20:03:17200 GURL google_pay_url(methods::kGooglePay);
201 GURL android_pay_url(methods::kAndroidPay);
Mathieu Perreault627b97c2017-08-12 00:44:22202 // Looking for payment methods that are NOT google-related payment methods.
203 auto non_google_it =
204 std::find_if(spec_->url_payment_method_identifiers().begin(),
205 spec_->url_payment_method_identifiers().end(),
206 [google_pay_url, android_pay_url](const GURL& url) {
207 return url != google_pay_url && url != android_pay_url;
208 });
209 journey_logger_.SetRequestedPaymentMethodTypes(
210 /*requested_basic_card=*/!spec_->supported_card_networks().empty(),
211 /*requested_method_google=*/
Jan Wilken Dörrie45d34f42019-06-08 09:40:54212 base::Contains(spec_->url_payment_method_identifiers(), google_pay_url) ||
213 base::Contains(spec_->url_payment_method_identifiers(),
214 android_pay_url),
Mathieu Perreault627b97c2017-08-12 00:44:22215 /*requested_method_other=*/non_google_it !=
216 spec_->url_payment_method_identifiers().end());
Rouslan Solomakhin1f95f092019-08-09 12:28:51217
218 payment_handler_host_.set_payment_request_id_for_logs(*spec_->details().id);
mathpf709499d2017-01-09 20:48:36219}
220
Rouslan Solomakhin9788d4b2019-04-09 13:10:23221void PaymentRequest::Show(bool is_user_gesture, bool wait_for_updated_details) {
Rouslan Solomakhin27064702018-12-14 21:15:33222 if (!IsInitialized()) {
Rouslan Solomakhina480efa2019-05-06 15:37:22223 log_.Error(errors::kCannotShowWithoutInit);
mathpf4bc50e2017-01-24 05:17:50224 OnConnectionTerminated();
tmartino8ce922852017-01-09 22:23:10225 return;
226 }
rouslan6e3cf7c62017-04-17 21:23:28227
Rouslan Solomakhin27064702018-12-14 21:15:33228 if (is_show_called_) {
Rouslan Solomakhina480efa2019-05-06 15:37:22229 log_.Error(errors::kCannotShowTwice);
Rouslan Solomakhin27064702018-12-14 21:15:33230 OnConnectionTerminated();
231 return;
232 }
233
234 is_show_called_ = true;
Sahel Sharify0fadf4da2019-08-09 14:55:58235 journey_logger_.SetTriggerTime();
Rouslan Solomakhin27064702018-12-14 21:15:33236
rouslan7d433cc22017-05-08 15:18:07237 // A tab can display only one PaymentRequest UI at a time.
Anthony Vallee-Dubois8f5e7e12018-01-12 16:14:06238 display_handle_ = display_manager_->TryShow(delegate_.get());
Anthony Vallee-Duboisc7ae7332017-12-19 20:44:07239 if (!display_handle_) {
Rouslan Solomakhina480efa2019-05-06 15:37:22240 log_.Error(errors::kAnotherUiShowing);
Sahel Sharifya50fc4c2019-05-28 14:53:22241 DCHECK(!has_recorded_completion_);
242 has_recorded_completion_ = true;
sebsg828269bc2017-06-09 19:11:12243 journey_logger_.SetNotShown(
244 JourneyLogger::NOT_SHOWN_REASON_CONCURRENT_REQUESTS);
Rouslan Solomakhin9c83b8a2019-06-24 20:50:03245 client_->OnError(mojom::PaymentErrorReason::ALREADY_SHOWING,
246 errors::kAnotherUiShowing);
rouslan7d433cc22017-05-08 15:18:07247 OnConnectionTerminated();
248 return;
249 }
250
Rouslan Solomakhin5b510432017-09-26 16:59:32251 if (!delegate_->IsBrowserWindowActive()) {
Rouslan Solomakhina480efa2019-05-06 15:37:22252 log_.Error(errors::kCannotShowInBackgroundTab);
Sahel Sharifya50fc4c2019-05-28 14:53:22253 DCHECK(!has_recorded_completion_);
254 has_recorded_completion_ = true;
Rouslan Solomakhin5b510432017-09-26 16:59:32255 journey_logger_.SetNotShown(JourneyLogger::NOT_SHOWN_REASON_OTHER);
Rouslan Solomakhin9c83b8a2019-06-24 20:50:03256 client_->OnError(mojom::PaymentErrorReason::USER_CANCEL,
257 errors::kCannotShowInBackgroundTab);
Rouslan Solomakhin5b510432017-09-26 16:59:32258 OnConnectionTerminated();
259 return;
260 }
261
Rouslan Solomakhind2cae95a2018-08-09 00:16:10262 if (!state_) {
Rouslan Solomakhin27064702018-12-14 21:15:33263 // SSL is not valid. Reject show with NotSupportedError, disconnect the
264 // mojo pipe, and destroy this object.
Rouslan Solomakhind5dcc322019-07-11 21:47:20265 AreRequestedMethodsSupportedCallback(false, reject_show_error_message_);
Rouslan Solomakhind2cae95a2018-08-09 00:16:10266 return;
267 }
268
Rouslan Solomakhin833f8512018-04-03 23:19:25269 is_show_user_gesture_ = is_user_gesture;
270
Rouslan Solomakhin9788d4b2019-04-09 13:10:23271 if (wait_for_updated_details) {
272 // Put |spec_| into uninitialized state, so the UI knows to show a spinner.
273 // This method does not block.
274 spec_->StartWaitingForUpdateWith(
275 PaymentRequestSpec::UpdateReason::INITIAL_PAYMENT_DETAILS);
Sahel Sharify98a2c2a2019-07-12 18:57:40276 } else {
277 DCHECK(spec_->details().total);
278 journey_logger_.RecordTransactionAmount(
279 spec_->details().total->amount->currency,
280 spec_->details().total->amount->value, false /*completed*/);
Rouslan Solomakhin9788d4b2019-04-09 13:10:23281 }
Takashi Sakamoto48a29702019-04-08 05:06:32282
Rouslan Solomakhin9788d4b2019-04-09 13:10:23283 display_handle_->Show(this);
Rouslan Solomakhin1dca2a922019-09-06 22:25:07284
285 state_->set_is_show_user_gesture(is_show_user_gesture_);
gogerald0a7ee6c2017-11-13 18:23:19286 state_->AreRequestedMethodsSupported(
287 base::BindOnce(&PaymentRequest::AreRequestedMethodsSupportedCallback,
288 weak_ptr_factory_.GetWeakPtr()));
289}
290
Jinho Bangbe463a22018-08-02 10:26:50291void PaymentRequest::Retry(mojom::PaymentValidationErrorsPtr errors) {
Rouslan Solomakhin27064702018-12-14 21:15:33292 if (!IsInitialized()) {
Rouslan Solomakhina480efa2019-05-06 15:37:22293 log_.Error(errors::kCannotRetryWithoutInit);
Jinho Bangcac8d9a02018-08-23 19:47:22294 OnConnectionTerminated();
295 return;
296 }
297
Rouslan Solomakhin27064702018-12-14 21:15:33298 if (!IsThisPaymentRequestShowing()) {
Rouslan Solomakhina480efa2019-05-06 15:37:22299 log_.Error(errors::kCannotRetryWithoutShow);
Jinho Bangcac8d9a02018-08-23 19:47:22300 OnConnectionTerminated();
301 return;
302 }
303
Jinho Bangbe463a22018-08-02 10:26:50304 std::string error;
305 if (!PaymentsValidators::IsValidPaymentValidationErrorsFormat(errors,
306 &error)) {
Rouslan Solomakhin27064702018-12-14 21:15:33307 log_.Error(error);
Rouslan Solomakhin9c83b8a2019-06-24 20:50:03308 client_->OnError(mojom::PaymentErrorReason::USER_CANCEL, error);
Jinho Bangbe463a22018-08-02 10:26:50309 OnConnectionTerminated();
310 return;
311 }
312
Jinho Bang092e7162018-09-06 23:41:19313 spec()->Retry(std::move(errors));
Jinho Bangcac8d9a02018-08-23 19:47:22314 display_handle_->Retry();
Jinho Bangbe463a22018-08-02 10:26:50315}
316
mathp151bd312017-04-03 21:07:24317void PaymentRequest::UpdateWith(mojom::PaymentDetailsPtr details) {
Rouslan Solomakhin27064702018-12-14 21:15:33318 if (!IsInitialized()) {
Rouslan Solomakhina480efa2019-05-06 15:37:22319 log_.Error(errors::kCannotUpdateWithoutInit);
Rouslan Solomakhin27064702018-12-14 21:15:33320 OnConnectionTerminated();
321 return;
322 }
323
324 if (!IsThisPaymentRequestShowing()) {
Rouslan Solomakhina480efa2019-05-06 15:37:22325 log_.Error(errors::kCannotUpdateWithoutShow);
Rouslan Solomakhin27064702018-12-14 21:15:33326 OnConnectionTerminated();
327 return;
328 }
329
mathp151bd312017-04-03 21:07:24330 std::string error;
Mohamad Ahmadif5544bb2017-09-01 21:48:22331 if (!ValidatePaymentDetails(ConvertPaymentDetails(details), &error)) {
Rouslan Solomakhin27064702018-12-14 21:15:33332 log_.Error(error);
mathp151bd312017-04-03 21:07:24333 OnConnectionTerminated();
334 return;
335 }
Rouslan Solomakhin4cbda822017-08-23 18:50:39336
Jinho Bang092e7162018-09-06 23:41:19337 if (details->shipping_address_errors &&
338 !PaymentsValidators::IsValidAddressErrorsFormat(
339 details->shipping_address_errors, &error)) {
Rouslan Solomakhin27064702018-12-14 21:15:33340 log_.Error(error);
Jinho Bang092e7162018-09-06 23:41:19341 OnConnectionTerminated();
342 return;
343 }
344
Rouslan Solomakhincf9093f2019-05-20 15:32:17345 if (state()->selected_instrument() && state()->IsPaymentAppInvoked() &&
Sahel Sharify9d98a502019-09-30 19:58:39346 payment_handler_host_.is_changing()) {
Rouslan Solomakhin8e9f149b22019-05-10 17:43:02347 payment_handler_host_.UpdateWith(
Sahel Sharify47582212019-10-25 21:26:53348 PaymentDetailsConverter::ConvertToPaymentRequestDetailsUpdate(
Sahel Sharify110e14c2019-10-07 20:55:48349 details, state()->selected_instrument()->HandlesShippingAddress(),
350 base::BindRepeating(
351 &PaymentInstrument::IsValidForPaymentMethodIdentifier,
352 state()->selected_instrument()->AsWeakPtr())));
Rouslan Solomakhina480efa2019-05-06 15:37:22353 }
354
Rouslan Solomakhin6ba46fd2019-04-11 23:44:01355 bool is_resolving_promise_passed_into_show_method = !spec_->IsInitialized();
356
mathp151bd312017-04-03 21:07:24357 spec_->UpdateWith(std::move(details));
Rouslan Solomakhin9788d4b2019-04-09 13:10:23358
359 if (is_resolving_promise_passed_into_show_method) {
Sahel Sharify98a2c2a2019-07-12 18:57:40360 DCHECK(spec_->details().total);
361 journey_logger_.RecordTransactionAmount(
362 spec_->details().total->amount->currency,
363 spec_->details().total->amount->value, false /*completed*/);
Rouslan Solomakhin9788d4b2019-04-09 13:10:23364 if (SatisfiesSkipUIConstraints()) {
Rouslan Solomakhin9788d4b2019-04-09 13:10:23365 Pay();
366 } else if (spec_->request_shipping()) {
367 state_->SelectDefaultShippingAddressAndNotifyObservers();
368 }
369 }
mathp151bd312017-04-03 21:07:24370}
371
Rouslan Solomakhina9ff9282017-10-31 21:58:05372void PaymentRequest::NoUpdatedPaymentDetails() {
Rouslan Solomakhin27064702018-12-14 21:15:33373 // This Mojo call is triggered by the user of the API doing nothing in
374 // response to a shipping address update event, so the error messages cannot
375 // be more verbose.
376 if (!IsInitialized()) {
Rouslan Solomakhina480efa2019-05-06 15:37:22377 log_.Error(errors::kNotInitialized);
Rouslan Solomakhin27064702018-12-14 21:15:33378 OnConnectionTerminated();
379 return;
380 }
381
382 if (!IsThisPaymentRequestShowing()) {
Rouslan Solomakhina480efa2019-05-06 15:37:22383 log_.Error(errors::kNotShown);
Rouslan Solomakhin27064702018-12-14 21:15:33384 OnConnectionTerminated();
385 return;
386 }
387
Rouslan Solomakhina9ff9282017-10-31 21:58:05388 spec_->RecomputeSpecForDetails();
Rouslan Solomakhina480efa2019-05-06 15:37:22389
Sahel Sharify9d98a502019-09-30 19:58:39390 if (state()->IsPaymentAppInvoked() && payment_handler_host_.is_changing()) {
Rouslan Solomakhin8e9f149b22019-05-10 17:43:02391 payment_handler_host_.NoUpdatedPaymentDetails();
Rouslan Solomakhincf9093f2019-05-20 15:32:17392 }
Rouslan Solomakhina9ff9282017-10-31 21:58:05393}
394
mathpf4bc50e2017-01-24 05:17:50395void PaymentRequest::Abort() {
Rouslan Solomakhin27064702018-12-14 21:15:33396 if (!IsInitialized()) {
Rouslan Solomakhina480efa2019-05-06 15:37:22397 log_.Error(errors::kCannotAbortWithoutInit);
Rouslan Solomakhin27064702018-12-14 21:15:33398 OnConnectionTerminated();
399 return;
400 }
401
402 if (!IsThisPaymentRequestShowing()) {
Rouslan Solomakhina480efa2019-05-06 15:37:22403 log_.Error(errors::kCannotAbortWithoutShow);
Rouslan Solomakhin27064702018-12-14 21:15:33404 OnConnectionTerminated();
405 return;
406 }
407
Anthony Vallee-Dubois6813c1442017-05-17 19:32:56408 // The API user has decided to abort. If a successful abort message is
409 // returned to the renderer, the Mojo message pipe is closed, which triggers
mathpf4bc50e2017-01-24 05:17:50410 // PaymentRequest::OnConnectionTerminated, which destroys this object.
Anthony Vallee-Dubois6813c1442017-05-17 19:32:56411 // Otherwise, the abort promise is rejected and the pipe is not closed.
412 // The abort is only successful if the payment app wasn't yet invoked.
413 // TODO(crbug.com/716546): Add a merchant abort metric
414
415 bool accepting_abort = !state_->IsPaymentAppInvoked();
sebsgfcdd13c2017-06-08 15:49:33416 if (accepting_abort)
417 RecordFirstAbortReason(JourneyLogger::ABORT_REASON_ABORTED_BY_MERCHANT);
Anthony Vallee-Dubois6813c1442017-05-17 19:32:56418
mathpf4bc50e2017-01-24 05:17:50419 if (client_.is_bound())
Anthony Vallee-Dubois6813c1442017-05-17 19:32:56420 client_->OnAbort(accepting_abort);
421
422 if (observer_for_testing_)
423 observer_for_testing_->OnAbortCalled();
mathpf4bc50e2017-01-24 05:17:50424}
425
mathp218795892017-03-29 15:15:34426void PaymentRequest::Complete(mojom::PaymentComplete result) {
Rouslan Solomakhin27064702018-12-14 21:15:33427 if (!IsInitialized()) {
Rouslan Solomakhina480efa2019-05-06 15:37:22428 log_.Error(errors::kCannotCompleteWithoutInit);
Rouslan Solomakhin27064702018-12-14 21:15:33429 OnConnectionTerminated();
mathp4b85b582017-03-08 21:07:16430 return;
Rouslan Solomakhin27064702018-12-14 21:15:33431 }
432
433 if (!IsThisPaymentRequestShowing()) {
Rouslan Solomakhina480efa2019-05-06 15:37:22434 log_.Error(errors::kCannotAbortWithoutShow);
Rouslan Solomakhin27064702018-12-14 21:15:33435 OnConnectionTerminated();
436 return;
437 }
mathp4b85b582017-03-08 21:07:16438
Rouslan Solomakhine3473192017-06-16 14:54:57439 // Failed transactions show an error. Successful and unknown-state
440 // transactions don't show an error.
441 if (result == mojom::PaymentComplete::FAIL) {
mathp218795892017-03-29 15:15:34442 delegate_->ShowErrorMessage();
443 } else {
sebsgfcdd13c2017-06-08 15:49:33444 DCHECK(!has_recorded_completion_);
sebsgf8272a22017-05-26 14:32:58445 journey_logger_.SetCompleted();
sebsgfcdd13c2017-06-08 15:49:33446 has_recorded_completion_ = true;
Sahel Sharify98a2c2a2019-07-12 18:57:40447 DCHECK(spec_->details().total);
448 journey_logger_.RecordTransactionAmount(
449 spec_->details().total->amount->currency,
450 spec_->details().total->amount->value, true /*completed*/);
sebsgfcdd13c2017-06-08 15:49:33451
anthonyvd6a43b932017-05-11 18:39:27452 delegate_->GetPrefService()->SetBoolean(kPaymentsFirstTransactionCompleted,
453 true);
mathp218795892017-03-29 15:15:34454 // When the renderer closes the connection,
455 // PaymentRequest::OnConnectionTerminated will be called.
456 client_->OnComplete();
sebsg8a93b272017-05-11 19:30:22457 state_->RecordUseStats();
mathp218795892017-03-29 15:15:34458 }
mathp4b85b582017-03-08 21:07:16459}
460
Danyao Wang03a4cbd2019-08-15 23:47:11461void PaymentRequest::CanMakePayment() {
Rouslan Solomakhin27064702018-12-14 21:15:33462 if (!IsInitialized()) {
Rouslan Solomakhina480efa2019-05-06 15:37:22463 log_.Error(errors::kCannotCallCanMakePaymentWithoutInit);
Rouslan Solomakhin27064702018-12-14 21:15:33464 OnConnectionTerminated();
465 return;
466 }
467
468 // It's valid to call canMakePayment() without calling show() first.
469
gogerald8189d522017-09-15 17:52:18470 if (observer_for_testing_)
471 observer_for_testing_->OnCanMakePaymentCalled();
Mathieu Perreaultcacb85e2018-06-06 20:40:13472
Rouslan Solomakhind2cae95a2018-08-09 00:16:10473 if (!delegate_->GetPrefService()->GetBoolean(kCanMakePaymentEnabled) ||
474 !state_) {
Danyao Wang03a4cbd2019-08-15 23:47:11475 CanMakePaymentCallback(/*can_make_payment=*/false);
Mathieu Perreaultcacb85e2018-06-06 20:40:13476 } else {
Rouslan Solomakhind2cae95a2018-08-09 00:16:10477 state_->CanMakePayment(
Mathieu Perreaultcacb85e2018-06-06 20:40:13478 base::BindOnce(&PaymentRequest::CanMakePaymentCallback,
Danyao Wang03a4cbd2019-08-15 23:47:11479 weak_ptr_factory_.GetWeakPtr()));
Mathieu Perreaultcacb85e2018-06-06 20:40:13480 }
gogerald8189d522017-09-15 17:52:18481}
482
Rouslan Solomakhin5683eb282019-01-29 18:06:03483void PaymentRequest::HasEnrolledInstrument(bool per_method_quota) {
Danyao Wangce175bf2018-12-21 22:35:58484 if (!IsInitialized()) {
Rouslan Solomakhina480efa2019-05-06 15:37:22485 log_.Error(errors::kCannotCallHasEnrolledInstrumentWithoutInit);
Danyao Wangce175bf2018-12-21 22:35:58486 OnConnectionTerminated();
487 return;
488 }
489
490 // It's valid to call hasEnrolledInstrument() without calling show() first.
491
492 if (observer_for_testing_)
493 observer_for_testing_->OnHasEnrolledInstrumentCalled();
494
495 if (!delegate_->GetPrefService()->GetBoolean(kCanMakePaymentEnabled) ||
496 !state_) {
Rouslan Solomakhin5683eb282019-01-29 18:06:03497 HasEnrolledInstrumentCallback(per_method_quota,
498 /*has_enrolled_instrument=*/false);
Danyao Wangce175bf2018-12-21 22:35:58499 } else {
500 state_->HasEnrolledInstrument(
501 base::BindOnce(&PaymentRequest::HasEnrolledInstrumentCallback,
Rouslan Solomakhin5683eb282019-01-29 18:06:03502 weak_ptr_factory_.GetWeakPtr(), per_method_quota));
Danyao Wangce175bf2018-12-21 22:35:58503 }
504}
505
Rouslan Solomakhin8e9f149b22019-05-10 17:43:02506bool PaymentRequest::ChangePaymentMethod(const std::string& method_name,
507 const std::string& stringified_data) {
Rouslan Solomakhina480efa2019-05-06 15:37:22508 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
Rouslan Solomakhin8e9f149b22019-05-10 17:43:02509 DCHECK(!method_name.empty());
Rouslan Solomakhina480efa2019-05-06 15:37:22510
Rouslan Solomakhin8e9f149b22019-05-10 17:43:02511 if (!state_ || !state_->IsPaymentAppInvoked() || !client_)
512 return false;
Rouslan Solomakhina480efa2019-05-06 15:37:22513
Rouslan Solomakhin8e9f149b22019-05-10 17:43:02514 client_->OnPaymentMethodChange(method_name, stringified_data);
515 return true;
Rouslan Solomakhina480efa2019-05-06 15:37:22516}
517
Sahel Sharify9d98a502019-09-30 19:58:39518bool PaymentRequest::ChangeShippingOption(
519 const std::string& shipping_option_id) {
520 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
521 DCHECK(!shipping_option_id.empty());
522
523 bool is_valid_id = false;
524 if (spec_->details().shipping_options) {
525 for (const auto& option : spec_->GetShippingOptions()) {
526 if (option->id == shipping_option_id) {
527 is_valid_id = true;
528 break;
529 }
530 }
531 }
532
533 if (!state_ || !state_->IsPaymentAppInvoked() || !client_ || !spec_ ||
534 !spec_->request_shipping() || !is_valid_id) {
535 return false;
536 }
537
538 client_->OnShippingOptionChange(shipping_option_id);
539 return true;
540}
541
542bool PaymentRequest::ChangeShippingAddress(
543 mojom::PaymentAddressPtr shipping_address) {
544 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
545 DCHECK(shipping_address);
546
547 if (!state_ || !state_->IsPaymentAppInvoked() || !client_ || !spec_ ||
548 !spec_->request_shipping()) {
549 return false;
550 }
551
552 client_->OnShippingAddressChange(
553 RedactShippingAddress(std::move(shipping_address)));
554 return true;
555}
556
Rouslan Solomakhin27064702018-12-14 21:15:33557void PaymentRequest::AreRequestedMethodsSupportedCallback(
Rouslan Solomakhind5dcc322019-07-11 21:47:20558 bool methods_supported,
559 const std::string& error_message) {
Danyao Wang25f72dc2019-10-18 05:11:32560 if (is_show_called_ && observer_for_testing_)
561 observer_for_testing_->OnShowInstrumentsReady();
562
Rouslan Solomakhin27064702018-12-14 21:15:33563 if (methods_supported) {
Sahel Sharifyd3f1bc82019-05-21 18:48:46564 if (SatisfiesSkipUIConstraints())
Rouslan Solomakhin27064702018-12-14 21:15:33565 Pay();
Rouslan Solomakhin27064702018-12-14 21:15:33566 } else {
Sahel Sharifya50fc4c2019-05-28 14:53:22567 DCHECK(!has_recorded_completion_);
568 has_recorded_completion_ = true;
Rouslan Solomakhin27064702018-12-14 21:15:33569 journey_logger_.SetNotShown(
570 JourneyLogger::NOT_SHOWN_REASON_NO_SUPPORTED_PAYMENT_METHOD);
Rouslan Solomakhin9c83b8a2019-06-24 20:50:03571 client_->OnError(mojom::PaymentErrorReason::NOT_SUPPORTED,
Rouslan Solomakhind5dcc322019-07-11 21:47:20572 GetNotSupportedErrorMessage(spec_.get()) +
573 (error_message.empty() ? "" : " " + error_message));
Rouslan Solomakhin27064702018-12-14 21:15:33574 if (observer_for_testing_)
575 observer_for_testing_->OnNotSupportedError();
576 OnConnectionTerminated();
577 }
578}
579
580bool PaymentRequest::IsInitialized() const {
581 return is_initialized_ && client_ && client_.is_bound() &&
Gyuyoung Kim9cfbda32019-08-27 02:15:18582 receiver_.is_bound();
Rouslan Solomakhin27064702018-12-14 21:15:33583}
584
585bool PaymentRequest::IsThisPaymentRequestShowing() const {
586 return is_show_called_ && display_handle_ && spec_ && state_;
587}
588
Sahel Sharifyd3f1bc82019-05-21 18:48:46589bool PaymentRequest::SatisfiesSkipUIConstraints() {
Rouslan Solomakhin9788d4b2019-04-09 13:10:23590 // Only allowing URL base payment apps to skip the payment sheet.
Sahel Sharifyd3f1bc82019-05-21 18:48:46591 skipped_payment_request_ui_ =
592 (spec()->url_payment_method_identifiers().size() == 1 ||
danakjdca06902019-06-27 21:41:41593 delegate_->SkipUiForBasicCard()) &&
Sahel Sharifyd3f1bc82019-05-21 18:48:46594 base::FeatureList::IsEnabled(features::kWebPaymentsSingleAppUiSkip) &&
595 base::FeatureList::IsEnabled(::features::kServiceWorkerPaymentApps) &&
596 is_show_user_gesture_ && state()->IsInitialized() &&
597 spec()->IsInitialized() && state()->available_instruments().size() == 1 &&
598 spec()->stringified_method_data().size() == 1 &&
Sahel Sharifyfef3d922019-09-11 01:41:22599 (!spec()->request_shipping() ||
600 state()->available_instruments().front()->HandlesShippingAddress()) &&
601 (!spec()->request_payer_name() ||
602 state()->available_instruments().front()->HandlesPayerName()) &&
603 (!spec()->request_payer_phone() ||
604 state()->available_instruments().front()->HandlesPayerPhone()) &&
605 (!spec()->request_payer_email() ||
606 state()->available_instruments().front()->HandlesPayerEmail());
Sahel Sharifyd3f1bc82019-05-21 18:48:46607 if (skipped_payment_request_ui_) {
608 DCHECK(state()->IsInitialized() && spec()->IsInitialized());
609 journey_logger_.SetEventOccurred(JourneyLogger::EVENT_SKIPPED_SHOW);
610 } else if (state()->IsInitialized() && spec()->IsInitialized()) {
611 // Set EVENT_SHOWN only after state() and spec() initialization.
612 journey_logger_.SetEventOccurred(JourneyLogger::EVENT_SHOWN);
613 }
614 return skipped_payment_request_ui_;
Rouslan Solomakhin27064702018-12-14 21:15:33615}
616
mathpf1a7a3752017-03-15 11:23:37617void PaymentRequest::OnPaymentResponseAvailable(
618 mojom::PaymentResponsePtr response) {
Rouslan Solomakhin68429b72019-06-27 15:12:39619 DCHECK(!response->method_name.empty());
620 DCHECK(!response->stringified_details.empty());
621
mathp57c8c862017-06-16 20:15:45622 journey_logger_.SetEventOccurred(
623 JourneyLogger::EVENT_RECEIVED_INSTRUMENT_DETAILS);
gogerald7a2b761e2017-11-09 18:30:19624
Sahel Sharify26884382019-05-07 16:23:51625 // Log the correct "selected instrument" metric according to its type and
626 // the method name in response.
627 DCHECK(state_->selected_instrument());
628 JourneyLogger::Event selected_event =
629 JourneyLogger::Event::EVENT_SELECTED_OTHER;
630 switch (state_->selected_instrument()->type()) {
631 case PaymentInstrument::Type::AUTOFILL:
632 selected_event = JourneyLogger::Event::EVENT_SELECTED_CREDIT_CARD;
633 break;
634 case PaymentInstrument::Type::SERVICE_WORKER_APP: {
635 selected_event =
636 IsGooglePaymentMethodInstrumentSelected(response->method_name)
637 ? JourneyLogger::Event::EVENT_SELECTED_GOOGLE
638 : JourneyLogger::Event::EVENT_SELECTED_OTHER;
639 break;
640 }
641 case PaymentInstrument::Type::NATIVE_MOBILE_APP:
642 NOTREACHED();
643 break;
644 }
645 journey_logger_.SetEventOccurred(selected_event);
646
Rouslan Solomakhin02d086ec2019-01-31 23:10:39647 // If currently interactive, show the processing spinner. Autofill payment
648 // instruments request a CVC, so they are always interactive at this point. A
649 // payment handler may elect to be non-interactive by not showing a
650 // confirmation page to the user.
651 if (delegate_->IsInteractive())
652 delegate_->ShowProcessingSpinner();
653
mathpf1a7a3752017-03-15 11:23:37654 client_->OnPaymentResponse(std::move(response));
mathp4b85b582017-03-08 21:07:16655}
656
Rouslan Solomakhin68429b72019-06-27 15:12:39657void PaymentRequest::OnPaymentResponseError(const std::string& error_message) {
658 journey_logger_.SetEventOccurred(
659 JourneyLogger::EVENT_RECEIVED_INSTRUMENT_DETAILS);
660 RecordFirstAbortReason(JourneyLogger::ABORT_REASON_INSTRUMENT_DETAILS_ERROR);
661
662 reject_show_error_message_ = error_message;
663 delegate_->ShowErrorMessage();
664 // When the user dismisses the error message, UserCancelled() will reject
665 // PaymentRequest.show() with |reject_show_error_message_|.
666}
667
mathp151bd312017-04-03 21:07:24668void PaymentRequest::OnShippingOptionIdSelected(
669 std::string shipping_option_id) {
670 client_->OnShippingOptionChange(shipping_option_id);
671}
672
673void PaymentRequest::OnShippingAddressSelected(
674 mojom::PaymentAddressPtr address) {
Sahel Sharify9d98a502019-09-30 19:58:39675 client_->OnShippingAddressChange(RedactShippingAddress(std::move(address)));
mathp151bd312017-04-03 21:07:24676}
677
Jinho Bangbb178152018-09-13 09:44:43678void PaymentRequest::OnPayerInfoSelected(mojom::PayerDetailPtr payer_info) {
679 client_->OnPayerDetailChange(std::move(payer_info));
680}
681
Rouslan Solomakhin1f95f092019-08-09 12:28:51682void PaymentRequest::SetInvokedServiceWorkerIdentity(const url::Origin& origin,
683 int64_t registration_id) {
684 payment_handler_host_.set_sw_origin_for_logs(origin);
685 payment_handler_host_.set_registration_id_for_logs(registration_id);
686}
687
mathpf4bc50e2017-01-24 05:17:50688void PaymentRequest::UserCancelled() {
689 // If |client_| is not bound, then the object is already being destroyed as
690 // a result of a renderer event.
691 if (!client_.is_bound())
692 return;
693
sebsgfcdd13c2017-06-08 15:49:33694 RecordFirstAbortReason(JourneyLogger::ABORT_REASON_ABORTED_BY_USER);
sebsg20b49d7b2017-05-04 20:23:17695
mathpf4bc50e2017-01-24 05:17:50696 // This sends an error to the renderer, which informs the API user.
Rouslan Solomakhin9c83b8a2019-06-24 20:50:03697 client_->OnError(mojom::PaymentErrorReason::USER_CANCEL,
Rouslan Solomakhin68429b72019-06-27 15:12:39698 !reject_show_error_message_.empty()
699 ? reject_show_error_message_
700 : errors::kUserCancelled);
mathpf4bc50e2017-01-24 05:17:50701
702 // We close all bindings and ask to be destroyed.
703 client_.reset();
Gyuyoung Kim9cfbda32019-08-27 02:15:18704 receiver_.reset();
Rouslan Solomakhin8e9f149b22019-05-10 17:43:02705 payment_handler_host_.Disconnect();
rouslanb28f4532017-05-08 15:41:47706 if (observer_for_testing_)
707 observer_for_testing_->OnConnectionTerminated();
mathpf4bc50e2017-01-24 05:17:50708 manager_->DestroyRequest(this);
mathpf709499d2017-01-09 20:48:36709}
710
sebsgd56b3e422017-10-20 18:08:08711void PaymentRequest::DidStartMainFrameNavigationToDifferentDocument(
712 bool is_user_initiated) {
sebsgfcdd13c2017-06-08 15:49:33713 RecordFirstAbortReason(is_user_initiated
714 ? JourneyLogger::ABORT_REASON_USER_NAVIGATION
715 : JourneyLogger::ABORT_REASON_MERCHANT_NAVIGATION);
sebsg2c8558a2017-05-17 18:54:10716}
717
mathpf4bc50e2017-01-24 05:17:50718void PaymentRequest::OnConnectionTerminated() {
719 // We are here because of a browser-side error, or likely as a result of the
Gyuyoung Kim9cfbda32019-08-27 02:15:18720 // disconnect_handler on |receiver_|, which can mean that the renderer
mathpf4bc50e2017-01-24 05:17:50721 // has decided to close the pipe for various reasons (see all uses of
722 // PaymentRequest::clearResolversAndCloseMojoConnection() in Blink). We close
723 // the binding and the dialog, and ask to be deleted.
724 client_.reset();
Gyuyoung Kim9cfbda32019-08-27 02:15:18725 receiver_.reset();
Rouslan Solomakhin8e9f149b22019-05-10 17:43:02726 payment_handler_host_.Disconnect();
mathpf4bc50e2017-01-24 05:17:50727 delegate_->CloseDialog();
rouslanb28f4532017-05-08 15:41:47728 if (observer_for_testing_)
729 observer_for_testing_->OnConnectionTerminated();
sebsgfcdd13c2017-06-08 15:49:33730
731 RecordFirstAbortReason(JourneyLogger::ABORT_REASON_MOJO_CONNECTION_ERROR);
mathpf709499d2017-01-09 20:48:36732 manager_->DestroyRequest(this);
733}
734
mathpd4be8de82017-03-01 00:51:48735void PaymentRequest::Pay() {
mathp57c8c862017-06-16 20:15:45736 journey_logger_.SetEventOccurred(JourneyLogger::EVENT_PAY_CLICKED);
Mathieu Perreault23d25bfb82018-05-11 14:45:37737 DCHECK(state_->selected_instrument());
Sahel Sharify26884382019-05-07 16:23:51738 if (state_->selected_instrument()->type() ==
739 PaymentInstrument::Type::SERVICE_WORKER_APP) {
Rouslan Solomakhin8e9f149b22019-05-10 17:43:02740 static_cast<ServiceWorkerPaymentInstrument*>(state_->selected_instrument())
741 ->set_payment_handler_host(payment_handler_host_.Bind());
Mathieu Perreault23d25bfb82018-05-11 14:45:37742 }
mathpf1a7a3752017-03-15 11:23:37743 state_->GeneratePaymentResponse();
mathpd4be8de82017-03-01 00:51:48744}
745
Anthony Vallee-Duboisc7ae7332017-12-19 20:44:07746void PaymentRequest::HideIfNecessary() {
747 display_handle_.reset();
748}
749
Anthony Vallee-Dubois10d131a2018-02-22 15:41:04750bool PaymentRequest::IsIncognito() const {
751 return delegate_->IsIncognito();
752}
753
sebsgfcdd13c2017-06-08 15:49:33754void PaymentRequest::RecordFirstAbortReason(
755 JourneyLogger::AbortReason abort_reason) {
756 if (!has_recorded_completion_) {
757 has_recorded_completion_ = true;
758 journey_logger_.SetAborted(abort_reason);
sebsg2c8558a2017-05-17 18:54:10759 }
760}
761
Danyao Wang03a4cbd2019-08-15 23:47:11762void PaymentRequest::CanMakePaymentCallback(bool can_make_payment) {
763 client_->OnCanMakePayment(
764 can_make_payment ? mojom::CanMakePaymentQueryResult::CAN_MAKE_PAYMENT
765 : mojom::CanMakePaymentQueryResult::CANNOT_MAKE_PAYMENT);
Danyao Wang4bc0606a2018-12-27 16:54:53766
Danyao Wang57aa0442019-01-31 04:06:41767 journey_logger_.SetCanMakePaymentValue(can_make_payment);
Rouslan Solomakhin1804ee42017-10-03 14:27:43768
769 if (observer_for_testing_)
770 observer_for_testing_->OnCanMakePaymentReturned();
771}
772
Danyao Wangce175bf2018-12-21 22:35:58773void PaymentRequest::HasEnrolledInstrumentCallback(
Rouslan Solomakhin5683eb282019-01-29 18:06:03774 bool per_method_quota,
Danyao Wangce175bf2018-12-21 22:35:58775 bool has_enrolled_instrument) {
Rouslan Solomakhinb26faa072019-08-19 14:42:28776 if (!spec_ || CanMakePaymentQueryFactory::GetInstance()
777 ->GetForContext(web_contents_->GetBrowserContext())
778 ->CanQuery(top_level_origin_, frame_origin_,
779 spec_->query_for_quota(), per_method_quota)) {
Danyao Wangce175bf2018-12-21 22:35:58780 RespondToHasEnrolledInstrumentQuery(has_enrolled_instrument,
Rouslan Solomakhin77a7e1a2019-05-23 17:37:58781 /*warn_local_development=*/false);
782 } else if (UrlUtil::IsLocalDevelopmentUrl(frame_origin_)) {
Danyao Wangce175bf2018-12-21 22:35:58783 RespondToHasEnrolledInstrumentQuery(has_enrolled_instrument,
Rouslan Solomakhin77a7e1a2019-05-23 17:37:58784 /*warn_local_development=*/true);
Danyao Wangce175bf2018-12-21 22:35:58785 } else {
786 client_->OnHasEnrolledInstrument(
787 HasEnrolledInstrumentQueryResult::QUERY_QUOTA_EXCEEDED);
788 }
789
790 if (observer_for_testing_)
791 observer_for_testing_->OnHasEnrolledInstrumentReturned();
792}
793
Danyao Wangce175bf2018-12-21 22:35:58794void PaymentRequest::RespondToHasEnrolledInstrumentQuery(
795 bool has_enrolled_instrument,
Rouslan Solomakhin77a7e1a2019-05-23 17:37:58796 bool warn_local_development) {
Danyao Wangce175bf2018-12-21 22:35:58797 HasEnrolledInstrumentQueryResult positive =
Rouslan Solomakhin77a7e1a2019-05-23 17:37:58798 warn_local_development
Danyao Wangce175bf2018-12-21 22:35:58799 ? HasEnrolledInstrumentQueryResult::WARNING_HAS_ENROLLED_INSTRUMENT
800 : HasEnrolledInstrumentQueryResult::HAS_ENROLLED_INSTRUMENT;
801 HasEnrolledInstrumentQueryResult negative =
Rouslan Solomakhin77a7e1a2019-05-23 17:37:58802 warn_local_development
Danyao Wangce175bf2018-12-21 22:35:58803 ? HasEnrolledInstrumentQueryResult::WARNING_HAS_NO_ENROLLED_INSTRUMENT
804 : HasEnrolledInstrumentQueryResult::HAS_NO_ENROLLED_INSTRUMENT;
805
806 client_->OnHasEnrolledInstrument(has_enrolled_instrument ? positive
807 : negative);
Danyao Wang57aa0442019-01-31 04:06:41808 journey_logger_.SetHasEnrolledInstrumentValue(has_enrolled_instrument);
Danyao Wangce175bf2018-12-21 22:35:58809}
810
mathpf709499d2017-01-09 20:48:36811} // namespace payments