From 5b3b71aae6434999ec0c48fc652b019d0733f52c Mon Sep 17 00:00:00 2001 From: Eden Chuang Date: Wed, 14 Jun 2017 15:59:00 +0800 Subject: [PATCH] Bug 1345365 - PaymentRequest API canMakePayment(), abort() and show() implementation. r=baku --HG-- extra : rebase_source : 1471c9b98cd919d411b22426c55bc3159d4d2f00 --- dom/interfaces/payments/moz.build | 2 + .../payments/nsIPaymentActionRequest.idl | 45 +++- .../payments/nsIPaymentActionResponse.idl | 164 +++++++++++++ .../payments/nsIPaymentRequestService.idl | 14 +- .../payments/nsIPaymentUIService.idl | 16 ++ dom/payments/PaymentActionRequest.cpp | 67 +++++- dom/payments/PaymentActionRequest.h | 22 +- dom/payments/PaymentActionResponse.cpp | 220 +++++++++++++++++ dom/payments/PaymentActionResponse.h | 104 ++++++++ dom/payments/PaymentAddress.cpp | 128 ++++++++++ dom/payments/PaymentAddress.h | 88 +++++++ dom/payments/PaymentRequest.cpp | 225 +++++++++++++++++- dom/payments/PaymentRequest.h | 33 ++- dom/payments/PaymentRequestManager.cpp | 187 +++++++++++++-- dom/payments/PaymentRequestManager.h | 17 +- dom/payments/PaymentRequestModule.cpp | 31 +++ dom/payments/PaymentRequestService.cpp | 225 +++++++++++++++++- dom/payments/PaymentRequestService.h | 14 ++ dom/payments/PaymentRequestUtils.cpp | 48 ---- dom/payments/PaymentRequestUtils.h | 7 - dom/payments/PaymentResponse.cpp | 155 ++++++++++++ dom/payments/PaymentResponse.h | 89 +++++++ dom/payments/ipc/PPaymentRequest.ipdl | 65 +++++ dom/payments/ipc/PaymentRequestChild.cpp | 25 +- dom/payments/ipc/PaymentRequestChild.h | 3 + dom/payments/ipc/PaymentRequestParent.cpp | 203 ++++++++++++++-- dom/payments/ipc/PaymentRequestParent.h | 13 +- dom/payments/moz.build | 5 + dom/webidl/PaymentAddress.webidl | 31 +++ dom/webidl/PaymentRequest.webidl | 4 - dom/webidl/PaymentResponse.webidl | 34 +++ dom/webidl/moz.build | 2 + 32 files changed, 2148 insertions(+), 138 deletions(-) create mode 100644 dom/interfaces/payments/nsIPaymentActionResponse.idl create mode 100644 dom/interfaces/payments/nsIPaymentUIService.idl create mode 100644 dom/payments/PaymentActionResponse.cpp create mode 100644 dom/payments/PaymentActionResponse.h create mode 100644 dom/payments/PaymentAddress.cpp create mode 100644 dom/payments/PaymentAddress.h create mode 100644 dom/payments/PaymentResponse.cpp create mode 100644 dom/payments/PaymentResponse.h create mode 100644 dom/webidl/PaymentAddress.webidl create mode 100644 dom/webidl/PaymentResponse.webidl diff --git a/dom/interfaces/payments/moz.build b/dom/interfaces/payments/moz.build index c0ef2471dd15..0b2738eded82 100644 --- a/dom/interfaces/payments/moz.build +++ b/dom/interfaces/payments/moz.build @@ -6,8 +6,10 @@ XPIDL_SOURCES += [ 'nsIPaymentActionRequest.idl', + 'nsIPaymentActionResponse.idl', 'nsIPaymentRequest.idl', 'nsIPaymentRequestService.idl', + 'nsIPaymentUIService.idl', ] XPIDL_MODULE = 'dom_payments' diff --git a/dom/interfaces/payments/nsIPaymentActionRequest.idl b/dom/interfaces/payments/nsIPaymentActionRequest.idl index 42de8a639b66..4c9f2035ac86 100644 --- a/dom/interfaces/payments/nsIPaymentActionRequest.idl +++ b/dom/interfaces/payments/nsIPaymentActionRequest.idl @@ -6,13 +6,26 @@ #include "nsISupports.idl" #include "nsIVariant.idl" #include "nsIPaymentRequest.idl" +#include "nsIPaymentActionResponse.idl" interface nsIArray; +[builtinclass, uuid(3fef5459-b0ea-469b-be9f-b99e8ca75d3d)] +interface nsIPaymentActionCallback : nsISupports +{ + void respondPayment(in nsIPaymentActionResponse aResponse); +}; + [builtinclass, uuid(7ddbe8be-beac-4952-96f6-619981dff7a6)] interface nsIPaymentActionRequest : nsISupports { + const uint32_t UNKNOWN_ACTION = 0; const uint32_t CREATE_ACTION = 1; + const uint32_t CANMAKE_ACTION = 2; + const uint32_t SHOW_ACTION = 3; + const uint32_t ABORT_ACTION = 4; + const uint32_t COMPLETE_ACTION = 5; + /* * The payment request identifier. */ @@ -23,11 +36,17 @@ interface nsIPaymentActionRequest : nsISupports */ readonly attribute uint32_t type; + /* + * The callback for the response from UI module + */ + readonly attribute nsIPaymentActionCallback callback; + /* * Initialize function for this request. */ void init(in AString aRequestId, - in uint32_t aType); + in uint32_t aType, + in nsIPaymentActionCallback aCallback); }; [builtinclass, uuid(1d38dce6-8bcd-441b-aa94-68e300b6e175)] @@ -57,12 +76,30 @@ interface nsIPaymentCreateActionRequest : nsIPaymentActionRequest * Initialize function the this request. */ void initRequest(in AString aRequestId, + in nsIPaymentActionCallback aCallback, in uint64_t aTabId, in nsIArray aMethodData, in nsIPaymentDetails aDetails, in nsIPaymentOptions aOptions); }; +[builtinclass, uuid(4429697d-1135-47de-a46e-5196d399ec55)] +interface nsIPaymentCompleteActionRequest : nsIPaymentActionRequest +{ + /* + * The complete status from merchant side. + */ + readonly attribute AString completeStatus; + + /* + * Initialize function for this request. + */ + void initRequest(in AString aRequestId, + in nsIPaymentActionCallback aCallback, + in AString aCompleteStatus); +}; + + %{C++ #define NS_PAYMENT_ACTION_REQUEST_CID \ { 0x7ddbe8be, 0xbeac, 0x4952, { 0x96, 0xf6, 0x61, 0x99, 0x81, 0xdf, 0xf7, 0xa6 } } @@ -73,4 +110,10 @@ interface nsIPaymentCreateActionRequest : nsIPaymentActionRequest { 0x1d38dce6, 0x8bcd, 0x441b, { 0xaa, 0x94, 0x68, 0xe3, 0x00, 0xb6, 0xe1, 0x75 } } #define NS_PAYMENT_CREATE_ACTION_REQUEST_CONTRACT_ID \ "@mozilla.org/dom/payments/payment-create-action-request;1" + +#define NS_PAYMENT_COMPLETE_ACTION_REQUEST_CID \ + { 0x4429697d, 0x1135, 0x47de, { 0xa4, 0x6e, 0x51, 0x96, 0xd3, 0x99, 0xec, 0x55 } } +#define NS_PAYMENT_COMPLETE_ACTION_REQUEST_CONTRACT_ID \ + "@mozilla.org/dom/payments/payment-complete-action-request;1" + %} diff --git a/dom/interfaces/payments/nsIPaymentActionResponse.idl b/dom/interfaces/payments/nsIPaymentActionResponse.idl new file mode 100644 index 000000000000..13b548dfa1d3 --- /dev/null +++ b/dom/interfaces/payments/nsIPaymentActionResponse.idl @@ -0,0 +1,164 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "nsISupports.idl" +#include "nsIVariant.idl" + +[builtinclass, scriptable, uuid(a607c095-ef60-4a9b-a3d0-0506c60728b3)] +interface nsIPaymentActionResponse : nsISupports +{ + /* + * Align type to nsIPaymentActionRequest types, + * where 1 is for payment request creation. + * the action expects no response from UI module. + */ + const uint32_t NO_TYPE = 0; + // const uint32_t CREATE_ACTION = 1; + const uint32_t CANMAKE_ACTION = 2; + const uint32_t SHOW_ACTION = 3; + const uint32_t ABORT_ACTION = 4; + const uint32_t COMPLETE_ACTION = 5; + + const uint32_t ABORT_SUCCEEDED = 1; + const uint32_t ABORT_FAILED = 0; + + const uint32_t PAYMENT_ACCEPTED = 1; + const uint32_t PAYMENT_REJECTED = 0; + + const uint32_t COMPLETE_SUCCEEDED = 1; + const uint32_t COMPLETE_FAILED = 0; + + /* + * The payment request identity. + */ + readonly attribute AString requestId; + + /* + * The response type. + */ + readonly attribute uint32_t type; +}; + +[builtinclass, scriptable, uuid(52fc3f9f-c0cb-4874-b3d4-ee4b6e9cbe9c)] +interface nsIPaymentCanMakeActionResponse : nsIPaymentActionResponse +{ + /* + * The result of CanMake task. + */ + readonly attribute bool result; + + /* + * Initialize function of this response. + */ + void init(in AString aRequestId, in bool aResult); +}; + +[builtinclass, scriptable, uuid(184385cb-2d35-4b99-a9a3-7c780bf66b9b)] +interface nsIPaymentShowActionResponse : nsIPaymentActionResponse +{ + /* + * Accpet status of the payment. + */ + readonly attribute uint32_t acceptStatus; + + /* + * The decided payment method name. + */ + readonly attribute AString methodName; + + /* + * The data needed by the payment method. (it must be serializable) + */ + readonly attribute AString data; + + /* + * The payer name information. + */ + readonly attribute AString payerName; + + /* + * The payer email information. + */ + readonly attribute AString payerEmail; + + /* + * The payer phone information. + */ + readonly attribute AString payerPhone; + + /* + * Initialize function for this response. + */ + void init(in AString aRequestId, + in uint32_t aAcceptStatus, + in AString aMethodName, + in AString aData, + in AString aPayerName, + in AString aPayerEmail, + in AString aPayerPhone); + + /* + * Check if the payment is accpeted + */ + bool isAccepted(); +}; + +[builtinclass, scriptable, uuid(8c72bcdb-0c37-4786-a9e5-510afa2f8ede)] +interface nsIPaymentAbortActionResponse : nsIPaymentActionResponse +{ + /* + * The abort task status. + */ + readonly attribute uint32_t abortStatus; + + /* + * Initialize function of this response. + */ + void init(in AString aRequestId, in uint32_t aAbortStatus); + + /* + * Check if the abort task is succeeded + */ + bool isSucceeded(); +}; + +[builtinclass, scriptable, uuid(62c01e69-9ca4-4060-99e4-b95f628c8e6d)] +interface nsIPaymentCompleteActionResponse : nsIPaymentActionResponse +{ + /* + * The UI status after calling complete(). + */ + readonly attribute uint32_t completeStatus; + + void init(in AString aRequestId, + in uint32_t aCompleteStatus); + + /* + * Check if the UI is finished. + */ + bool isCompleted(); +}; + +%{C++ +#define NS_PAYMENT_CANMAKE_ACTION_RESPONSE_CID \ + { 0x52fc3f9f, 0xc0cb, 0x4874, { 0xb3, 0xd4, 0xee, 0x4b, 0x6e, 0x9c, 0xbe, 0x9c } } +#define NS_PAYMENT_CANMAKE_ACTION_RESPONSE_CONTRACT_ID \ + "@mozilla.org/dom/payments/payment-canmake-action-response;1" + +#define NS_PAYMENT_SHOW_ACTION_RESPONSE_CID \ + { 0x184385cb, 0x2d35, 0x4b99, { 0xa9, 0xa3, 0x7c, 0x78, 0x0b, 0xf6, 0x6b, 0x9b } } +#define NS_PAYMENT_SHOW_ACTION_RESPONSE_CONTRACT_ID \ + "@mozilla.org/dom/payments/payment-show-action-response;1" + +#define NS_PAYMENT_ABORT_ACTION_RESPONSE_CID \ + { 0x8c72bcdb, 0x0c37, 0x4786, { 0xa9, 0xe5, 0x51, 0x0a, 0xfa, 0x2f, 0x8e, 0xde } } +#define NS_PAYMENT_ABORT_ACTION_RESPONSE_CONTRACT_ID \ + "@mozilla.org/dom/payments/payment-abort-action-response;1" + +#define NS_PAYMENT_COMPLETE_ACTION_RESPONSE_CID \ + { 0x62c01e69, 0x9ca4, 0x4060, { 0x99, 0xe4, 0xb9, 0x5f, 0x62, 0x8c, 0x8e, 0x6d } } +#define NS_PAYMENT_COMPLETE_ACTION_RESPONSE_CONTRACT_ID \ + "@mozilla.org/dom/payments/payment-complete-action-response;1" +%} diff --git a/dom/interfaces/payments/nsIPaymentRequestService.idl b/dom/interfaces/payments/nsIPaymentRequestService.idl index 9000afc8d299..1b8e80193b74 100644 --- a/dom/interfaces/payments/nsIPaymentRequestService.idl +++ b/dom/interfaces/payments/nsIPaymentRequestService.idl @@ -7,7 +7,9 @@ #include "nsIVariant.idl" #include "nsIPaymentRequest.idl" #include "nsIPaymentActionRequest.idl" +#include "nsIPaymentActionResponse.idl" #include "nsISimpleEnumerator.idl" +#include "nsIPaymentUIService.idl" /* * nsPaymentRequestService is used to manage the created PaymentRequest in the @@ -17,19 +19,27 @@ [scriptable, builtinclass, uuid(cccd665f-edf3-41fc-ab9b-fc55b37340aa)] interface nsIPaymentRequestService : nsISupports { - nsIPaymentRequest getPaymentRequestById(in AString requestId); + nsIPaymentRequest getPaymentRequestById(in AString aRequestId); nsISimpleEnumerator enumerate(); /* - * This method is only for testing. + * These methods are only for testing. */ void cleanup(); + void setTestingUIService(in nsIPaymentUIService aUIService); + + void removeActionCallback(in nsIPaymentActionCallback aCallback); /* * requestPayment is used to handle the asked action request of the payment * from content process. */ void requestPayment(in nsIPaymentActionRequest aRequest); + + /* + * respondPayment is used for payment UI to respond the asked action result. + */ + void respondPayment(in nsIPaymentActionResponse aResponse); }; %{C++ diff --git a/dom/interfaces/payments/nsIPaymentUIService.idl b/dom/interfaces/payments/nsIPaymentUIService.idl new file mode 100644 index 000000000000..57e70313ec36 --- /dev/null +++ b/dom/interfaces/payments/nsIPaymentUIService.idl @@ -0,0 +1,16 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "nsISupports.idl" +#include "nsIPaymentActionResponse.idl" + +[scriptable, uuid(ea008d0c-9e9f-411f-a6c5-a62106ba7ab9)] +interface nsIPaymentUIService : nsISupports +{ + nsIPaymentActionResponse canMakePayment(in AString requestId); + nsIPaymentActionResponse showPayment(in AString requestId); + nsIPaymentActionResponse abortPayment(in AString requestId); + nsIPaymentActionResponse completePayment(in AString requestId); +}; diff --git a/dom/payments/PaymentActionRequest.cpp b/dom/payments/PaymentActionRequest.cpp index d2803e5b8979..e6def5dd4336 100644 --- a/dom/payments/PaymentActionRequest.cpp +++ b/dom/payments/PaymentActionRequest.cpp @@ -18,12 +18,21 @@ namespace dom { NS_IMPL_ISUPPORTS(PaymentActionRequest, nsIPaymentActionRequest) +PaymentActionRequest::PaymentActionRequest() + : mRequestId(EmptyString()) + , mType(nsIPaymentActionRequest::UNKNOWN_ACTION) + , mCallback(nullptr) +{ +} + NS_IMETHODIMP PaymentActionRequest::Init(const nsAString& aRequestId, - const uint32_t aType) + const uint32_t aType, + nsIPaymentActionCallback* aCallback) { mRequestId = aRequestId; mType = aType; + mCallback = aCallback; return NS_OK; } @@ -41,23 +50,42 @@ PaymentActionRequest::GetType(uint32_t* aType) return NS_OK; } +NS_IMETHODIMP +PaymentActionRequest::GetCallback(nsIPaymentActionCallback** aCallback) +{ + NS_ENSURE_ARG_POINTER(aCallback); + nsCOMPtr callback = mCallback; + callback.forget(aCallback); + return NS_OK; +} + /* PaymentCreateActionRequest */ NS_IMPL_ISUPPORTS_INHERITED(PaymentCreateActionRequest, PaymentActionRequest, nsIPaymentCreateActionRequest) +PaymentCreateActionRequest::PaymentCreateActionRequest() + : mTabId(0) +{ +} + NS_IMETHODIMP PaymentCreateActionRequest::InitRequest(const nsAString& aRequestId, + nsIPaymentActionCallback* aCallback, const uint64_t aTabId, nsIArray* aMethodData, nsIPaymentDetails* aDetails, nsIPaymentOptions* aOptions) { + NS_ENSURE_ARG_POINTER(aCallback); NS_ENSURE_ARG_POINTER(aMethodData); NS_ENSURE_ARG_POINTER(aDetails); NS_ENSURE_ARG_POINTER(aOptions); - Init(aRequestId, nsIPaymentActionRequest::CREATE_ACTION); + nsresult rv = Init(aRequestId, nsIPaymentActionRequest::CREATE_ACTION, aCallback); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } mTabId = aTabId; mMethodData = aMethodData; mDetails = aDetails; @@ -77,7 +105,6 @@ NS_IMETHODIMP PaymentCreateActionRequest::GetMethodData(nsIArray** aMethodData) { NS_ENSURE_ARG_POINTER(aMethodData); - *aMethodData = nullptr; MOZ_ASSERT(mMethodData); nsCOMPtr methodData = mMethodData; methodData.forget(aMethodData); @@ -88,7 +115,6 @@ NS_IMETHODIMP PaymentCreateActionRequest::GetDetails(nsIPaymentDetails** aDetails) { NS_ENSURE_ARG_POINTER(aDetails); - *aDetails = nullptr; MOZ_ASSERT(mDetails); nsCOMPtr details = mDetails; details.forget(aDetails); @@ -99,12 +125,43 @@ NS_IMETHODIMP PaymentCreateActionRequest::GetOptions(nsIPaymentOptions** aOptions) { NS_ENSURE_ARG_POINTER(aOptions); - *aOptions = nullptr; MOZ_ASSERT(mOptions); nsCOMPtr options = mOptions; options.forget(aOptions); return NS_OK; } +/* PaymentCompleteActionRequest */ + +NS_IMPL_ISUPPORTS_INHERITED(PaymentCompleteActionRequest, + PaymentActionRequest, + nsIPaymentCompleteActionRequest) + +PaymentCompleteActionRequest::PaymentCompleteActionRequest() + : mCompleteStatus(EmptyString()) +{ +} + +NS_IMETHODIMP +PaymentCompleteActionRequest::GetCompleteStatus(nsAString& aCompleteStatus) +{ + aCompleteStatus = mCompleteStatus; + return NS_OK; +} + +NS_IMETHODIMP +PaymentCompleteActionRequest::InitRequest(const nsAString& aRequestId, + nsIPaymentActionCallback* aCallback, + const nsAString& aCompleteStatus) +{ + NS_ENSURE_ARG_POINTER(aCallback); + nsresult rv = Init(aRequestId, nsIPaymentActionRequest::COMPLETE_ACTION, aCallback); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + mCompleteStatus = aCompleteStatus; + return NS_OK; +} + } // end of namespace dom } // end of namespace mozilla diff --git a/dom/payments/PaymentActionRequest.h b/dom/payments/PaymentActionRequest.h index 7efb348a575a..155770b52587 100644 --- a/dom/payments/PaymentActionRequest.h +++ b/dom/payments/PaymentActionRequest.h @@ -9,7 +9,6 @@ #include "nsIPaymentActionRequest.h" #include "nsCOMPtr.h" -#include "nsCOMArray.h" #include "nsIArray.h" #include "nsString.h" @@ -22,13 +21,14 @@ public: NS_DECL_ISUPPORTS NS_DECL_NSIPAYMENTACTIONREQUEST - PaymentActionRequest() = default; + PaymentActionRequest(); protected: virtual ~PaymentActionRequest() = default; nsString mRequestId; uint32_t mType; + nsCOMPtr mCallback; }; class PaymentCreateActionRequest final : public nsIPaymentCreateActionRequest @@ -39,7 +39,7 @@ public: NS_FORWARD_NSIPAYMENTACTIONREQUEST(PaymentActionRequest::) NS_DECL_NSIPAYMENTCREATEACTIONREQUEST - PaymentCreateActionRequest() = default; + PaymentCreateActionRequest(); private: ~PaymentCreateActionRequest() = default; @@ -50,6 +50,22 @@ private: nsCOMPtr mOptions; }; +class PaymentCompleteActionRequest final : public nsIPaymentCompleteActionRequest + , public PaymentActionRequest +{ +public: + NS_DECL_ISUPPORTS_INHERITED + NS_FORWARD_NSIPAYMENTACTIONREQUEST(PaymentActionRequest::) + NS_DECL_NSIPAYMENTCOMPLETEACTIONREQUEST + + PaymentCompleteActionRequest(); + +private: + ~PaymentCompleteActionRequest() = default; + + nsString mCompleteStatus; +}; + } // end of namespace dom } // end of namespace mozilla diff --git a/dom/payments/PaymentActionResponse.cpp b/dom/payments/PaymentActionResponse.cpp new file mode 100644 index 000000000000..456aaf43bba0 --- /dev/null +++ b/dom/payments/PaymentActionResponse.cpp @@ -0,0 +1,220 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "PaymentActionResponse.h" +#include "nsIRunnable.h" + +namespace mozilla { +namespace dom { + +/* PaymentActionResponse */ + +NS_IMPL_ISUPPORTS(PaymentActionResponse, + nsIPaymentActionResponse) + +PaymentActionResponse::PaymentActionResponse() + : mRequestId(EmptyString()) + , mType(nsIPaymentActionResponse::NO_TYPE) +{ +} + +NS_IMETHODIMP +PaymentActionResponse::GetRequestId(nsAString& aRequestId) +{ + aRequestId = mRequestId; + return NS_OK; +} + +NS_IMETHODIMP +PaymentActionResponse::GetType(uint32_t* aType) +{ + NS_ENSURE_ARG_POINTER(aType); + *aType = mType; + return NS_OK; +} + +/* PaymentCanMakeActionResponse */ + +NS_IMPL_ISUPPORTS_INHERITED(PaymentCanMakeActionResponse, + PaymentActionResponse, + nsIPaymentCanMakeActionResponse) + +PaymentCanMakeActionResponse::PaymentCanMakeActionResponse() +{ + mType = nsIPaymentActionResponse::CANMAKE_ACTION; +} + +NS_IMETHODIMP +PaymentCanMakeActionResponse::GetResult(bool* aResult) +{ + NS_ENSURE_ARG_POINTER(aResult); + *aResult = mResult; + return NS_OK; +} + +NS_IMETHODIMP +PaymentCanMakeActionResponse::Init(const nsAString& aRequestId, const bool aResult) +{ + mRequestId = aRequestId; + mResult = aResult; + return NS_OK; +} + +/* PaymentShowActionResponse */ + +NS_IMPL_ISUPPORTS_INHERITED(PaymentShowActionResponse, + PaymentActionResponse, + nsIPaymentShowActionResponse) + +PaymentShowActionResponse::PaymentShowActionResponse() +{ + mType = nsIPaymentActionResponse::SHOW_ACTION; +} + +NS_IMETHODIMP +PaymentShowActionResponse::GetAcceptStatus(uint32_t* aAcceptStatus) +{ + NS_ENSURE_ARG_POINTER(aAcceptStatus); + *aAcceptStatus = mAcceptStatus; + return NS_OK; +} + +NS_IMETHODIMP +PaymentShowActionResponse::GetMethodName(nsAString& aMethodName) +{ + aMethodName = mMethodName; + return NS_OK; +} + +NS_IMETHODIMP +PaymentShowActionResponse::GetData(nsAString& aData) +{ + aData = mData; + return NS_OK; +} + +NS_IMETHODIMP +PaymentShowActionResponse::GetPayerName(nsAString& aPayerName) +{ + aPayerName = mPayerName; + return NS_OK; +} + +NS_IMETHODIMP +PaymentShowActionResponse::GetPayerEmail(nsAString& aPayerEmail) +{ + aPayerEmail = mPayerEmail; + return NS_OK; +} + +NS_IMETHODIMP +PaymentShowActionResponse::GetPayerPhone(nsAString& aPayerPhone) +{ + aPayerPhone = mPayerPhone; + return NS_OK; +} + +NS_IMETHODIMP +PaymentShowActionResponse::Init(const nsAString& aRequestId, + const uint32_t aAcceptStatus, + const nsAString& aMethodName, + const nsAString& aData, + const nsAString& aPayerName, + const nsAString& aPayerEmail, + const nsAString& aPayerPhone) +{ + mRequestId = aRequestId; + mAcceptStatus = aAcceptStatus; + mMethodName = aMethodName; + mData = aData; + mPayerName = aPayerName; + mPayerEmail = aPayerEmail; + mPayerPhone = aPayerPhone; + return NS_OK; +} + +NS_IMETHODIMP +PaymentShowActionResponse::IsAccepted(bool* aIsAccepted) +{ + NS_ENSURE_ARG_POINTER(aIsAccepted); + *aIsAccepted = (mAcceptStatus == nsIPaymentActionResponse::PAYMENT_ACCEPTED); + return NS_OK; +} + +/* PaymentAbortActionResponse */ + +NS_IMPL_ISUPPORTS_INHERITED(PaymentAbortActionResponse, + PaymentActionResponse, + nsIPaymentAbortActionResponse) + +PaymentAbortActionResponse::PaymentAbortActionResponse() +{ + mType = nsIPaymentActionResponse::ABORT_ACTION; +} + +NS_IMETHODIMP +PaymentAbortActionResponse::GetAbortStatus(uint32_t* aAbortStatus) +{ + NS_ENSURE_ARG_POINTER(aAbortStatus); + *aAbortStatus = mAbortStatus; + return NS_OK; +} + +NS_IMETHODIMP +PaymentAbortActionResponse::Init(const nsAString& aRequestId, + const uint32_t aAbortStatus) +{ + mRequestId = aRequestId; + mAbortStatus = aAbortStatus; + return NS_OK; +} + +NS_IMETHODIMP +PaymentAbortActionResponse::IsSucceeded(bool* aIsSucceeded) +{ + NS_ENSURE_ARG_POINTER(aIsSucceeded); + *aIsSucceeded = (mAbortStatus == nsIPaymentActionResponse::ABORT_SUCCEEDED); + return NS_OK; +} + +/* PaymentCompleteActionResponse */ + +NS_IMPL_ISUPPORTS_INHERITED(PaymentCompleteActionResponse, + PaymentActionResponse, + nsIPaymentCompleteActionResponse) + +PaymentCompleteActionResponse::PaymentCompleteActionResponse() +{ + mType = nsIPaymentActionResponse::COMPLETE_ACTION; +} + +nsresult +PaymentCompleteActionResponse::Init(const nsAString& aRequestId, + const uint32_t aCompleteStatus) +{ + mRequestId = aRequestId; + mCompleteStatus = aCompleteStatus; + return NS_OK; +} + +nsresult +PaymentCompleteActionResponse::GetCompleteStatus(uint32_t* aCompleteStatus) +{ + NS_ENSURE_ARG_POINTER(aCompleteStatus); + *aCompleteStatus = mCompleteStatus; + return NS_OK; +} + +nsresult +PaymentCompleteActionResponse::IsCompleted(bool* aIsCompleted) +{ + NS_ENSURE_ARG_POINTER(aIsCompleted); + *aIsCompleted = (mCompleteStatus == nsIPaymentActionResponse::COMPLETE_SUCCEEDED); + return NS_OK; +} + +} // end of namespace dom +} // end of namespace mozilla diff --git a/dom/payments/PaymentActionResponse.h b/dom/payments/PaymentActionResponse.h new file mode 100644 index 000000000000..1eae27104113 --- /dev/null +++ b/dom/payments/PaymentActionResponse.h @@ -0,0 +1,104 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_dom_PaymentActionResponse_h +#define mozilla_dom_PaymentActionResponse_h + +#include "nsIPaymentActionResponse.h" + +namespace mozilla { +namespace dom { + +class PaymentRequestParent; + +class PaymentActionResponse : public nsIPaymentActionResponse +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSIPAYMENTACTIONRESPONSE + + PaymentActionResponse(); + +protected: + virtual ~PaymentActionResponse() = default; + + nsString mRequestId; + uint32_t mType; +}; + +class PaymentCanMakeActionResponse final : public nsIPaymentCanMakeActionResponse + , public PaymentActionResponse +{ +public: + NS_DECL_ISUPPORTS_INHERITED + NS_FORWARD_NSIPAYMENTACTIONRESPONSE(PaymentActionResponse::) + NS_DECL_NSIPAYMENTCANMAKEACTIONRESPONSE + + PaymentCanMakeActionResponse(); + +private: + ~PaymentCanMakeActionResponse() = default; + + bool mResult; +}; + +class PaymentShowActionResponse final : public nsIPaymentShowActionResponse + , public PaymentActionResponse +{ +public: + NS_DECL_ISUPPORTS_INHERITED + NS_FORWARD_NSIPAYMENTACTIONRESPONSE(PaymentActionResponse::) + NS_DECL_NSIPAYMENTSHOWACTIONRESPONSE + + PaymentShowActionResponse(); + +private: + ~PaymentShowActionResponse() = default; + + uint32_t mAcceptStatus; + nsString mMethodName; + nsString mData; + nsString mPayerName; + nsString mPayerEmail; + nsString mPayerPhone; +}; + +class PaymentAbortActionResponse final : public nsIPaymentAbortActionResponse + , public PaymentActionResponse +{ +public: + NS_DECL_ISUPPORTS_INHERITED + NS_FORWARD_NSIPAYMENTACTIONRESPONSE(PaymentActionResponse::) + NS_DECL_NSIPAYMENTABORTACTIONRESPONSE + + PaymentAbortActionResponse(); + +private: + ~PaymentAbortActionResponse() = default; + + uint32_t mAbortStatus; +}; + +class PaymentCompleteActionResponse final : public nsIPaymentCompleteActionResponse + , public PaymentActionResponse +{ +public: + NS_DECL_ISUPPORTS_INHERITED + NS_FORWARD_NSIPAYMENTACTIONRESPONSE(PaymentActionResponse::) + NS_DECL_NSIPAYMENTCOMPLETEACTIONRESPONSE + + PaymentCompleteActionResponse(); + +private: + ~PaymentCompleteActionResponse() = default; + + uint32_t mCompleteStatus; +}; + +} // end of dom +} // end of namespace mozilla + +#endif diff --git a/dom/payments/PaymentAddress.cpp b/dom/payments/PaymentAddress.cpp new file mode 100644 index 000000000000..a311f76658a6 --- /dev/null +++ b/dom/payments/PaymentAddress.cpp @@ -0,0 +1,128 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "mozilla/dom/PaymentAddress.h" +#include "mozilla/dom/PaymentAddressBinding.h" + +namespace mozilla { +namespace dom { + +NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(PaymentAddress, mOwner) + +NS_IMPL_CYCLE_COLLECTING_ADDREF(PaymentAddress) +NS_IMPL_CYCLE_COLLECTING_RELEASE(PaymentAddress) + +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(PaymentAddress) + NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY + NS_INTERFACE_MAP_ENTRY(nsISupports) +NS_INTERFACE_MAP_END + +PaymentAddress::PaymentAddress(nsPIDOMWindowInner* aWindow, + const nsAString& aCountry, + const nsTArray& aAddressLine, + const nsAString& aRegion, + const nsAString& aCity, + const nsAString& aDependentLocality, + const nsAString& aPostalCode, + const nsAString& aSortingCode, + const nsAString& aLanguageCode, + const nsAString& aOrganization, + const nsAString& aRecipient, + const nsAString& aPhone) + : mCountry(aCountry) + , mAddressLine(aAddressLine) + , mRegion(aRegion) + , mCity(aCity) + , mDependentLocality(aDependentLocality) + , mPostalCode(aPostalCode) + , mSortingCode(aSortingCode) + , mLanguageCode(aLanguageCode) + , mOrganization(aOrganization) + , mRecipient(aRecipient) + , mPhone(aPhone) + , mOwner(aWindow) +{ +} + +void +PaymentAddress::GetCountry(nsAString& aRetVal) const +{ + aRetVal = mCountry; +} + +void +PaymentAddress::GetAddressLine(nsTArray& aRetVal) const +{ + aRetVal = mAddressLine; +} + +void +PaymentAddress::GetRegion(nsAString& aRetVal) const +{ + aRetVal = mRegion; +} + +void +PaymentAddress::GetCity(nsAString& aRetVal) const +{ + aRetVal = mCity; +} + +void +PaymentAddress::GetDependentLocality(nsAString& aRetVal) const +{ + aRetVal = mDependentLocality; +} + +void +PaymentAddress::GetPostalCode(nsAString& aRetVal) const +{ + aRetVal = mPostalCode; +} + +void +PaymentAddress::GetSortingCode(nsAString& aRetVal) const +{ + aRetVal = mSortingCode; +} + +void +PaymentAddress::GetLanguageCode(nsAString& aRetVal) const +{ + aRetVal = mLanguageCode; +} + +void +PaymentAddress::GetOrganization(nsAString& aRetVal) const +{ + aRetVal = mOrganization; +} + +void +PaymentAddress::GetRecipient(nsAString& aRetVal) const +{ + aRetVal = mRecipient; +} + +void +PaymentAddress::GetPhone(nsAString& aRetVal) const +{ + aRetVal = mPhone; +} + +PaymentAddress::~PaymentAddress() +{ +} + +JSObject* +PaymentAddress::WrapObject(JSContext* aCx, JS::Handle aGivenProto) +{ + return PaymentAddressBinding::Wrap(aCx, this, aGivenProto); +} + + +} // namespace dom +} // namespace mozilla diff --git a/dom/payments/PaymentAddress.h b/dom/payments/PaymentAddress.h new file mode 100644 index 000000000000..b293ded6e05c --- /dev/null +++ b/dom/payments/PaymentAddress.h @@ -0,0 +1,88 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_dom_PaymentAddress_h +#define mozilla_dom_PaymentAddress_h + +#include "nsPIDOMWindow.h" +#include "nsWrapperCache.h" + +namespace mozilla { +namespace dom { + +class PaymentAddress final : public nsISupports, + public nsWrapperCache +{ +public: + NS_DECL_CYCLE_COLLECTING_ISUPPORTS + NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(PaymentAddress) + + PaymentAddress(nsPIDOMWindowInner* aWindow, + const nsAString& aCountry, + const nsTArray& aAddressLine, + const nsAString& aRegion, + const nsAString& aCity, + const nsAString& aDependentLocality, + const nsAString& aPostalCode, + const nsAString& aSortingCode, + const nsAString& aLanguageCode, + const nsAString& aOrganization, + const nsAString& aRecipient, + const nsAString& aPhone); + + nsPIDOMWindowInner* GetParentObject() const + { + return mOwner; + } + + virtual JSObject* WrapObject(JSContext* aCx, + JS::Handle aGivenProto) override; + + // Getter functions + void GetCountry(nsAString& aRetVal) const; + + void GetAddressLine(nsTArray& aRetVal) const; + + void GetRegion(nsAString& aRetVal) const; + + void GetCity(nsAString& aRetVal) const; + + void GetDependentLocality(nsAString& aRetVal) const; + + void GetPostalCode(nsAString& aRetVal) const; + + void GetSortingCode(nsAString& aRetVal) const; + + void GetLanguageCode(nsAString& aRetVal) const; + + void GetOrganization(nsAString& aRetVal) const; + + void GetRecipient(nsAString& aRetVal) const; + + void GetPhone(nsAString& aRetVal) const; + +private: + ~PaymentAddress(); + + nsString mCountry; + nsTArray mAddressLine; + nsString mRegion; + nsString mCity; + nsString mDependentLocality; + nsString mPostalCode; + nsString mSortingCode; + nsString mLanguageCode; + nsString mOrganization; + nsString mRecipient; + nsString mPhone; + + nsCOMPtr mOwner; +}; + +} // namespace dom +} // namespace mozilla + +#endif // mozilla_dom_PaymentAddress_h diff --git a/dom/payments/PaymentRequest.cpp b/dom/payments/PaymentRequest.cpp index 36ad9b255192..3d18fb906e2a 100644 --- a/dom/payments/PaymentRequest.cpp +++ b/dom/payments/PaymentRequest.cpp @@ -5,6 +5,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "mozilla/dom/PaymentRequest.h" +#include "mozilla/dom/PaymentResponse.h" #include "nsContentUtils.h" #include "PaymentRequestManager.h" @@ -21,10 +22,20 @@ NS_IMPL_CYCLE_COLLECTION_TRACE_END NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(PaymentRequest, DOMEventTargetHelper) + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mResultPromise) + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mAcceptPromise) + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mAbortPromise) + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mResponse) + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mShippingAddress) NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(PaymentRequest, DOMEventTargetHelper) + NS_IMPL_CYCLE_COLLECTION_UNLINK(mResultPromise) + NS_IMPL_CYCLE_COLLECTION_UNLINK(mAcceptPromise) + NS_IMPL_CYCLE_COLLECTION_UNLINK(mAbortPromise) + NS_IMPL_CYCLE_COLLECTION_UNLINK(mResponse) + NS_IMPL_CYCLE_COLLECTION_UNLINK(mShippingAddress) NS_IMPL_CYCLE_COLLECTION_UNLINK_END NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(PaymentRequest) @@ -39,6 +50,26 @@ PaymentRequest::PrefEnabled(JSContext* aCx, JSObject* aObj) return Preferences::GetBool("dom.payments.request.enabled"); } +bool +PaymentRequest::IsValidMethodData(const Sequence& aMethodData, + nsAString& aErrorMsg) +{ + if (!aMethodData.Length()) { + aErrorMsg.AssignLiteral("At least one payment method is required."); + return false; + } + + for (const PaymentMethodData& methodData : aMethodData) { + if (!methodData.mSupportedMethods.Length()) { + aErrorMsg.AssignLiteral( + "At least one payment method identifier is required."); + return false; + } + } + + return true; +} + bool PaymentRequest::IsValidNumber(const nsAString& aItem, const nsAString& aStr, @@ -152,11 +183,10 @@ PaymentRequest::Constructor(const GlobalObject& aGlobal, // [TODO] Bug 1318988 - Implement `allowPaymentRequest` on iframe - // Check payment methods is done by webidl - - // Check payment details + // Check payment methods and details nsAutoString message; - if (!IsValidDetailsInit(aDetails, message)) { + if (!IsValidMethodData(aMethodData, message) || + !IsValidDetailsInit(aDetails, message)) { aRv.ThrowTypeError(message); return nullptr; } @@ -171,6 +201,7 @@ PaymentRequest::Constructor(const GlobalObject& aGlobal, nsresult rv = manager->CreatePayment(window, aMethodData, aDetails, aOptions, getter_AddRefs(request)); if (NS_WARN_IF(NS_FAILED(rv))) { + aRv.Throw(NS_ERROR_DOM_TYPE_ERR); return nullptr; } @@ -198,6 +229,7 @@ PaymentRequest::CreatePaymentRequest(nsPIDOMWindowInner* aWindow, nsresult& aRv) PaymentRequest::PaymentRequest(nsPIDOMWindowInner* aWindow, const nsAString& aInternalId) : DOMEventTargetHelper(aWindow) , mInternalId(aInternalId) + , mShippingAddress(nullptr) , mUpdating(false) , mState(eCreated) { @@ -205,24 +237,180 @@ PaymentRequest::PaymentRequest(nsPIDOMWindowInner* aWindow, const nsAString& aIn } already_AddRefed -PaymentRequest::Show(ErrorResult& aRv) +PaymentRequest::CanMakePayment(ErrorResult& aRv) { - aRv.Throw(NS_ERROR_FAILURE); - return nullptr; + if (mState != eCreated) { + aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR); + return nullptr; + } + + if (mResultPromise) { + aRv.Throw(NS_ERROR_DOM_NOT_ALLOWED_ERR); + return nullptr; + } + + nsCOMPtr global = do_QueryInterface(GetOwner()); + ErrorResult result; + RefPtr promise = Promise::Create(global, result); + if (result.Failed()) { + aRv.Throw(NS_ERROR_FAILURE); + return nullptr; + } + + RefPtr manager = PaymentRequestManager::GetSingleton(); + if (NS_WARN_IF(!manager)) { + aRv.Throw(NS_ERROR_FAILURE); + return nullptr; + } + nsresult rv = manager->CanMakePayment(mInternalId); + if (NS_WARN_IF(NS_FAILED(rv))) { + promise->MaybeReject(NS_ERROR_FAILURE); + return promise.forget(); + } + mResultPromise = promise; + return promise.forget(); +} + +void +PaymentRequest::RespondCanMakePayment(bool aResult) +{ + MOZ_ASSERT(mResultPromise); + mResultPromise->MaybeResolve(aResult); + mResultPromise = nullptr; } already_AddRefed -PaymentRequest::CanMakePayment(ErrorResult& aRv) +PaymentRequest::Show(ErrorResult& aRv) { - aRv.Throw(NS_ERROR_FAILURE); - return nullptr; + if (mState != eCreated) { + aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR); + return nullptr; + } + + nsCOMPtr global = do_QueryInterface(GetOwner()); + ErrorResult result; + RefPtr promise = Promise::Create(global, result); + if (result.Failed()) { + mState = eClosed; + aRv.Throw(NS_ERROR_FAILURE); + return nullptr; + } + + RefPtr manager = PaymentRequestManager::GetSingleton(); + if (NS_WARN_IF(!manager)) { + mState = eClosed; + aRv.Throw(NS_ERROR_FAILURE); + return nullptr; + } + nsresult rv = manager->ShowPayment(mInternalId); + if (NS_WARN_IF(NS_FAILED(rv))) { + promise->MaybeReject(NS_ERROR_FAILURE); + mState = eClosed; + return promise.forget(); + } + + mAcceptPromise = promise; + mState = eInteractive; + return promise.forget(); +} + +void +PaymentRequest::RejectShowPayment(nsresult aRejectReason) +{ + MOZ_ASSERT(mAcceptPromise); + MOZ_ASSERT(ReadyForUpdate()); + + mAcceptPromise->MaybeReject(aRejectReason); + mState = eClosed; + mAcceptPromise = nullptr; +} + +void +PaymentRequest::RespondShowPayment(bool aAccept, + const nsAString& aMethodName, + const nsAString& aDetails, + const nsAString& aPayerName, + const nsAString& aPayerEmail, + const nsAString& aPayerPhone, + nsresult aRv) +{ + MOZ_ASSERT(mAcceptPromise); + MOZ_ASSERT(ReadyForUpdate()); + MOZ_ASSERT(mState == eInteractive); + + if (!aAccept) { + RejectShowPayment(aRv); + return; + } + + RefPtr paymentResponse = + new PaymentResponse(GetOwner(), mInternalId, mId, aMethodName, + mShippingOption, mShippingAddress, aDetails, + aPayerName, aPayerEmail, aPayerPhone); + mResponse = paymentResponse; + mAcceptPromise->MaybeResolve(paymentResponse); + + mState = eClosed; + mAcceptPromise = nullptr; +} + +void +PaymentRequest::RespondComplete() +{ + MOZ_ASSERT(mResponse); + mResponse->RespondComplete(); } already_AddRefed PaymentRequest::Abort(ErrorResult& aRv) { - aRv.Throw(NS_ERROR_FAILURE); - return nullptr; + if (mState != eInteractive) { + aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR); + return nullptr; + } + + if (mAbortPromise) { + aRv.Throw(NS_ERROR_DOM_NOT_ALLOWED_ERR); + return nullptr; + } + + nsCOMPtr global = do_QueryInterface(GetOwner()); + ErrorResult result; + RefPtr promise = Promise::Create(global, result); + if (result.Failed()) { + aRv.Throw(NS_ERROR_FAILURE); + return nullptr; + } + + RefPtr manager = PaymentRequestManager::GetSingleton(); + if (NS_WARN_IF(!manager)) { + aRv.Throw(NS_ERROR_FAILURE); + return nullptr; + } + nsresult rv = manager->AbortPayment(mInternalId); + if (NS_WARN_IF(NS_FAILED(rv))) { + aRv.Throw(NS_ERROR_FAILURE); + return nullptr; + } + + mAbortPromise = promise; + return promise.forget(); +} + +void +PaymentRequest::RespondAbortPayment(bool aSuccess) +{ + MOZ_ASSERT(mAbortPromise); + MOZ_ASSERT(mState == eInteractive); + + if (aSuccess) { + mAbortPromise->MaybeResolve(JS::UndefinedHandleValue); + mAbortPromise = nullptr; + RejectShowPayment(NS_ERROR_DOM_ABORT_ERR); + } else { + mAbortPromise->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR); + mAbortPromise = nullptr; + } } void @@ -249,12 +437,25 @@ PaymentRequest::Equals(const nsAString& aInternalId) const return mInternalId.Equals(aInternalId); } +bool +PaymentRequest::ReadyForUpdate() +{ + return mState == eInteractive && !mUpdating; +} + void PaymentRequest::SetUpdating(bool aUpdating) { mUpdating = aUpdating; } +already_AddRefed +PaymentRequest::GetShippingAddress() const +{ + RefPtr address = mShippingAddress; + return address.forget(); +} + void PaymentRequest::GetShippingOption(nsAString& aRetVal) const { diff --git a/dom/payments/PaymentRequest.h b/dom/payments/PaymentRequest.h index 7d984224761f..c2afada6bb06 100644 --- a/dom/payments/PaymentRequest.h +++ b/dom/payments/PaymentRequest.h @@ -17,6 +17,7 @@ namespace mozilla { namespace dom { class EventHandlerNonNull; +class PaymentAddress; class PaymentResponse; class PaymentRequest final : public DOMEventTargetHelper @@ -34,6 +35,9 @@ public: static bool PrefEnabled(JSContext* aCx, JSObject* aObj); + static bool IsValidMethodData(const Sequence& aMethodData, + nsAString& aErrorMsg); + static bool IsValidNumber(const nsAString& aItem, const nsAString& aStr, @@ -57,9 +61,22 @@ public: const PaymentOptions& aOptions, ErrorResult& aRv); - already_AddRefed Show(ErrorResult& aRv); - already_AddRefed Abort(ErrorResult& aRv); already_AddRefed CanMakePayment(ErrorResult& aRv); + void RespondCanMakePayment(bool aResult); + + already_AddRefed Show(ErrorResult& aRv); + void RespondShowPayment(bool aAccept, + const nsAString& aMethodName, + const nsAString& aDetails, + const nsAString& aPayerName, + const nsAString& aPayerEmail, + const nsAString& aPayerPhone, + nsresult aRv = NS_ERROR_DOM_ABORT_ERR); + void RejectShowPayment(nsresult aRejectReason); + void RespondComplete(); + + already_AddRefed Abort(ErrorResult& aRv); + void RespondAbortPayment(bool aResult); void GetId(nsAString& aRetVal) const; void GetInternalId(nsAString& aRetVal); @@ -67,8 +84,10 @@ public: bool Equals(const nsAString& aInternalId) const; + bool ReadyForUpdate(); void SetUpdating(bool aUpdating); + already_AddRefed GetShippingAddress() const; void GetShippingOption(nsAString& aRetVal) const; Nullable GetShippingType() const; @@ -87,6 +106,16 @@ protected: // mId is initialized to details.id if it exists // otherwise, mId has the same value as mInternalId. nsString mId; + // Promise for "PaymentRequest::CanMakePayment" + RefPtr mResultPromise; + // Promise for "PaymentRequest::Show" + RefPtr mAcceptPromise; + // Promise for "PaymentRequest::Abort" + RefPtr mAbortPromise; + // Resolve mAcceptPromise with mResponse if user accepts the request. + RefPtr mResponse; + // It is populated when the user provides a shipping address. + RefPtr mShippingAddress; // It is populated when the user chooses a shipping option. nsString mShippingOption; diff --git a/dom/payments/PaymentRequestManager.cpp b/dom/payments/PaymentRequestManager.cpp index 6cc40b190a9c..ae1dd1b2087d 100644 --- a/dom/payments/PaymentRequestManager.cpp +++ b/dom/payments/PaymentRequestManager.cpp @@ -28,7 +28,6 @@ SerializeFromJSObject(JSContext* aCx, JS::HandleObject aObject, nsAString& aSeri return NS_ERROR_FAILURE; } JS::RootedValue value(aCx, JS::ObjectValue(*aObject)); - //JS::Value value = JS::ObjectValue(*aObject); return serializer->EncodeFromJSVal(value.address(), aCx, aSerializedObject); } @@ -292,6 +291,31 @@ PaymentRequestManager::ReleasePaymentChild(PaymentRequest* aRequest) return NS_OK; } +nsresult +PaymentRequestManager::SendRequestPayment(PaymentRequest* aRequest, + const IPCPaymentActionRequest& aAction, + bool aReleaseAfterSend) +{ + RefPtr requestChild; + nsresult rv = GetPaymentChild(aRequest, getter_AddRefs(requestChild)); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + rv = requestChild->RequestPayment(aAction); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + if (aReleaseAfterSend) { + rv = ReleasePaymentChild(aRequest); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + } + return NS_OK; +} + already_AddRefed PaymentRequestManager::GetSingleton() { @@ -346,7 +370,7 @@ PaymentRequestManager::CreatePayment(nsPIDOMWindowInner* aWindow, IPCPaymentOptions options; ConvertOptions(aOptions, options); - RefPtr paymentRequest = PaymentRequest::CreatePaymentRequest(aWindow, rv); + RefPtr request = PaymentRequest::CreatePaymentRequest(aWindow, rv); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } @@ -359,34 +383,155 @@ PaymentRequestManager::CreatePayment(nsPIDOMWindowInner* aWindow, if (aDetails.mId.WasPassed() && !aDetails.mId.Value().IsEmpty()) { requestId = aDetails.mId.Value(); } else { - paymentRequest->GetInternalId(requestId); - } - paymentRequest->SetId(requestId); - - RefPtr requestChild; - rv = GetPaymentChild(paymentRequest, getter_AddRefs(requestChild)); - if (NS_WARN_IF(NS_FAILED(rv))) { - return rv; + request->GetInternalId(requestId); } + request->SetId(requestId); nsAutoString internalId; - paymentRequest->GetInternalId(internalId); - IPCPaymentCreateActionRequest request(internalId, - methodData, - details, - options); - rv = requestChild->RequestPayment(request); + request->GetInternalId(internalId); + IPCPaymentCreateActionRequest action(internalId, + methodData, + details, + options); + + rv = SendRequestPayment(request, action, true); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } + mRequestQueue.AppendElement(request); + request.forget(aRequest); + return NS_OK; +} - rv = ReleasePaymentChild(paymentRequest); - if (NS_WARN_IF(NS_FAILED(rv))) { - return rv; +nsresult +PaymentRequestManager::CanMakePayment(const nsAString& aRequestId) +{ + RefPtr request = GetPaymentRequestById(aRequestId); + if (!request) { + return NS_ERROR_FAILURE; } - mRequestQueue.AppendElement(paymentRequest); - paymentRequest.forget(aRequest); + nsAutoString requestId(aRequestId); + IPCPaymentCanMakeActionRequest action(requestId); + + return SendRequestPayment(request, action); +} + +nsresult +PaymentRequestManager::ShowPayment(const nsAString& aRequestId) +{ + RefPtr request = GetPaymentRequestById(aRequestId); + if (!request) { + return NS_ERROR_FAILURE; + } + + nsAutoString requestId(aRequestId); + IPCPaymentShowActionRequest action(requestId); + + return SendRequestPayment(request, action); +} + +nsresult +PaymentRequestManager::AbortPayment(const nsAString& aRequestId) +{ + RefPtr request = GetPaymentRequestById(aRequestId); + if (!request) { + return NS_ERROR_FAILURE; + } + + nsAutoString requestId(aRequestId); + IPCPaymentAbortActionRequest action(requestId); + + return SendRequestPayment(request, action); +} + +nsresult +PaymentRequestManager::CompletePayment(const nsAString& aRequestId, + const PaymentComplete& aComplete) +{ + RefPtr request = GetPaymentRequestById(aRequestId); + if (!request) { + return NS_ERROR_FAILURE; + } + + nsString completeStatusString(NS_LITERAL_STRING("unknown")); + uint8_t completeIndex = static_cast(aComplete); + if (completeIndex < ArrayLength(PaymentCompleteValues::strings)) { + completeStatusString.AssignASCII( + PaymentCompleteValues::strings[completeIndex].value); + } + + nsAutoString requestId(aRequestId); + IPCPaymentCompleteActionRequest action(requestId, completeStatusString); + + return SendRequestPayment(request, action); +} + +nsresult +PaymentRequestManager::RespondPayment(const IPCPaymentActionResponse& aResponse) +{ + switch (aResponse.type()) { + case IPCPaymentActionResponse::TIPCPaymentCanMakeActionResponse: { + IPCPaymentCanMakeActionResponse response = aResponse; + RefPtr request = GetPaymentRequestById(response.requestId()); + if (NS_WARN_IF(!request)) { + return NS_ERROR_FAILURE; + } + request->RespondCanMakePayment(response.result()); + nsresult rv = ReleasePaymentChild(request); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + break; + } + case IPCPaymentActionResponse::TIPCPaymentShowActionResponse: { + IPCPaymentShowActionResponse response = aResponse; + RefPtr request = GetPaymentRequestById(response.requestId()); + if (NS_WARN_IF(!request)) { + return NS_ERROR_FAILURE; + } + request->RespondShowPayment(response.isAccepted(), + response.methodName(), + response.data(), + response.payerName(), + response.payerEmail(), + response.payerPhone()); + break; + } + case IPCPaymentActionResponse::TIPCPaymentAbortActionResponse: { + IPCPaymentAbortActionResponse response = aResponse; + RefPtr request = GetPaymentRequestById(response.requestId()); + if (NS_WARN_IF(!request)) { + return NS_ERROR_FAILURE; + } + request->RespondAbortPayment(response.isSucceeded()); + if (response.isSucceeded()) { + mRequestQueue.RemoveElement(request); + nsresult rv = ReleasePaymentChild(request); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + } + break; + } + case IPCPaymentActionResponse::TIPCPaymentCompleteActionResponse: { + IPCPaymentCompleteActionResponse response = aResponse; + RefPtr request = GetPaymentRequestById(response.requestId()); + if (NS_WARN_IF(!request)) { + return NS_ERROR_FAILURE; + } + request->RespondComplete(); + mRequestQueue.RemoveElement(request); + nsresult rv = ReleasePaymentChild(request); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + break; + } + default: { + return NS_ERROR_FAILURE; + } + } return NS_OK; } diff --git a/dom/payments/PaymentRequestManager.h b/dom/payments/PaymentRequestManager.h index d81fe181246a..aa970095c5e1 100644 --- a/dom/payments/PaymentRequestManager.h +++ b/dom/payments/PaymentRequestManager.h @@ -10,6 +10,7 @@ #include "nsISupports.h" #include "PaymentRequest.h" #include "mozilla/dom/PaymentRequestBinding.h" +#include "mozilla/dom/PaymentResponseBinding.h" #include "nsCOMPtr.h" #include "nsTArray.h" @@ -17,6 +18,7 @@ namespace mozilla { namespace dom { class PaymentRequestChild; +class IPCPaymentActionRequest; /* * PaymentRequestManager is a singleton used to manage the created PaymentRequests. @@ -44,9 +46,18 @@ public: const PaymentOptions& aOptions, PaymentRequest** aRequest); + nsresult CanMakePayment(const nsAString& aRequestId); + nsresult ShowPayment(const nsAString& aRequestId); + nsresult AbortPayment(const nsAString& aRequestId); + nsresult CompletePayment(const nsAString& aRequestId, + const PaymentComplete& aComplete); + + nsresult RespondPayment(const IPCPaymentActionResponse& aResponse); + nsresult ReleasePaymentChild(PaymentRequestChild* aPaymentChild); -protected: + +private: PaymentRequestManager() = default; ~PaymentRequestManager() = default; @@ -54,6 +65,10 @@ protected: PaymentRequestChild** aPaymentChild); nsresult ReleasePaymentChild(PaymentRequest* aRequest); + nsresult SendRequestPayment(PaymentRequest* aRequest, + const IPCPaymentActionRequest& action, + bool aReleaseAfterSend = false); + // The container for the created PaymentRequests nsTArray> mRequestQueue; nsRefPtrHashtable, PaymentRequestChild> mPaymentChildHash; diff --git a/dom/payments/PaymentRequestModule.cpp b/dom/payments/PaymentRequestModule.cpp index 05c614ca3a51..0a51a59712f7 100644 --- a/dom/payments/PaymentRequestModule.cpp +++ b/dom/payments/PaymentRequestModule.cpp @@ -6,24 +6,45 @@ #include "mozilla/ModuleUtils.h" #include "PaymentActionRequest.h" +#include "PaymentActionResponse.h" #include "PaymentRequestService.h" using mozilla::dom::PaymentActionRequest; using mozilla::dom::PaymentCreateActionRequest; +using mozilla::dom::PaymentCompleteActionRequest; +using mozilla::dom::PaymentCanMakeActionResponse; +using mozilla::dom::PaymentAbortActionResponse; +using mozilla::dom::PaymentShowActionResponse; +using mozilla::dom::PaymentCompleteActionResponse; using mozilla::dom::PaymentRequestService; NS_GENERIC_FACTORY_CONSTRUCTOR(PaymentActionRequest) NS_GENERIC_FACTORY_CONSTRUCTOR(PaymentCreateActionRequest) +NS_GENERIC_FACTORY_CONSTRUCTOR(PaymentCompleteActionRequest) +NS_GENERIC_FACTORY_CONSTRUCTOR(PaymentCanMakeActionResponse) +NS_GENERIC_FACTORY_CONSTRUCTOR(PaymentAbortActionResponse) +NS_GENERIC_FACTORY_CONSTRUCTOR(PaymentShowActionResponse) +NS_GENERIC_FACTORY_CONSTRUCTOR(PaymentCompleteActionResponse) NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(PaymentRequestService, PaymentRequestService::GetSingleton) NS_DEFINE_NAMED_CID(NS_PAYMENT_ACTION_REQUEST_CID); NS_DEFINE_NAMED_CID(NS_PAYMENT_CREATE_ACTION_REQUEST_CID); +NS_DEFINE_NAMED_CID(NS_PAYMENT_COMPLETE_ACTION_REQUEST_CID); +NS_DEFINE_NAMED_CID(NS_PAYMENT_CANMAKE_ACTION_RESPONSE_CID); +NS_DEFINE_NAMED_CID(NS_PAYMENT_ABORT_ACTION_RESPONSE_CID); +NS_DEFINE_NAMED_CID(NS_PAYMENT_SHOW_ACTION_RESPONSE_CID); +NS_DEFINE_NAMED_CID(NS_PAYMENT_COMPLETE_ACTION_RESPONSE_CID); NS_DEFINE_NAMED_CID(NS_PAYMENT_REQUEST_SERVICE_CID); static const mozilla::Module::CIDEntry kPaymentRequestCIDs[] = { { &kNS_PAYMENT_ACTION_REQUEST_CID, false, nullptr, PaymentActionRequestConstructor}, { &kNS_PAYMENT_CREATE_ACTION_REQUEST_CID, false, nullptr, PaymentCreateActionRequestConstructor}, + { &kNS_PAYMENT_COMPLETE_ACTION_REQUEST_CID, false, nullptr, PaymentCompleteActionRequestConstructor}, + { &kNS_PAYMENT_CANMAKE_ACTION_RESPONSE_CID, false, nullptr, PaymentCanMakeActionResponseConstructor}, + { &kNS_PAYMENT_ABORT_ACTION_RESPONSE_CID, false, nullptr, PaymentAbortActionResponseConstructor}, + { &kNS_PAYMENT_SHOW_ACTION_RESPONSE_CID, false, nullptr, PaymentShowActionResponseConstructor}, + { &kNS_PAYMENT_COMPLETE_ACTION_RESPONSE_CID, false, nullptr, PaymentCompleteActionResponseConstructor}, { &kNS_PAYMENT_REQUEST_SERVICE_CID, true, nullptr, PaymentRequestServiceConstructor }, { nullptr } }; @@ -31,6 +52,11 @@ static const mozilla::Module::CIDEntry kPaymentRequestCIDs[] = { static const mozilla::Module::ContractIDEntry kPaymentRequestContracts[] = { { NS_PAYMENT_ACTION_REQUEST_CONTRACT_ID, &kNS_PAYMENT_ACTION_REQUEST_CID }, { NS_PAYMENT_CREATE_ACTION_REQUEST_CONTRACT_ID, &kNS_PAYMENT_CREATE_ACTION_REQUEST_CID }, + { NS_PAYMENT_COMPLETE_ACTION_REQUEST_CONTRACT_ID, &kNS_PAYMENT_COMPLETE_ACTION_REQUEST_CID }, + { NS_PAYMENT_CANMAKE_ACTION_RESPONSE_CONTRACT_ID, &kNS_PAYMENT_CANMAKE_ACTION_RESPONSE_CID }, + { NS_PAYMENT_ABORT_ACTION_RESPONSE_CONTRACT_ID, &kNS_PAYMENT_ABORT_ACTION_RESPONSE_CID }, + { NS_PAYMENT_SHOW_ACTION_RESPONSE_CONTRACT_ID, &kNS_PAYMENT_SHOW_ACTION_RESPONSE_CID }, + { NS_PAYMENT_COMPLETE_ACTION_RESPONSE_CONTRACT_ID, &kNS_PAYMENT_COMPLETE_ACTION_RESPONSE_CID }, { NS_PAYMENT_REQUEST_SERVICE_CONTRACT_ID, &kNS_PAYMENT_REQUEST_SERVICE_CID }, { nullptr } }; @@ -38,6 +64,11 @@ static const mozilla::Module::ContractIDEntry kPaymentRequestContracts[] = { static const mozilla::Module::CategoryEntry kPaymentRequestCategories[] = { { "payment-request", "PaymentActionRequest", NS_PAYMENT_ACTION_REQUEST_CONTRACT_ID }, { "payment-request", "PaymentCreateActionRequest", NS_PAYMENT_CREATE_ACTION_REQUEST_CONTRACT_ID }, + { "payment-request", "PaymentCompleteActionRequest", NS_PAYMENT_COMPLETE_ACTION_REQUEST_CONTRACT_ID }, + { "payment-request", "PaymentCanMakeActionResponse", NS_PAYMENT_CANMAKE_ACTION_RESPONSE_CONTRACT_ID }, + { "payment-request", "PaymentAbortActionResponse", NS_PAYMENT_ABORT_ACTION_RESPONSE_CONTRACT_ID }, + { "payment-request", "PaymentShowActionResponse", NS_PAYMENT_SHOW_ACTION_RESPONSE_CONTRACT_ID }, + { "payment-request", "PaymentCompleteActionResponse", NS_PAYMENT_COMPLETE_ACTION_RESPONSE_CONTRACT_ID }, { "payment-request", "PaymentRequestService", NS_PAYMENT_REQUEST_SERVICE_CONTRACT_ID }, { nullptr } }; diff --git a/dom/payments/PaymentRequestService.cpp b/dom/payments/PaymentRequestService.cpp index 2bc5cef0a0c9..ad0361553008 100644 --- a/dom/payments/PaymentRequestService.cpp +++ b/dom/payments/PaymentRequestService.cpp @@ -138,15 +138,123 @@ PaymentRequestService::Cleanup() return NS_OK; } +NS_IMETHODIMP +PaymentRequestService::SetTestingUIService(nsIPaymentUIService* aUIService) +{ + // aUIService can be nullptr + mTestingUIService = aUIService; + return NS_OK; +} + +nsresult +PaymentRequestService::CallTestingUIAction(const nsAString& aRequestId, uint32_t aActionType) +{ + nsCOMPtr response; + nsresult rv; + if (mTestingUIService) { + switch (aActionType) { + case nsIPaymentActionRequest::CANMAKE_ACTION: { + rv = mTestingUIService->CanMakePayment(aRequestId, getter_AddRefs(response)); + break; + } + case nsIPaymentActionRequest::SHOW_ACTION: { + rv = mTestingUIService->ShowPayment(aRequestId, getter_AddRefs(response)); + break; + } + case nsIPaymentActionRequest::ABORT_ACTION: { + rv = mTestingUIService->AbortPayment(aRequestId, getter_AddRefs(response)); + break; + } + case nsIPaymentActionRequest::COMPLETE_ACTION: { + rv = mTestingUIService->CompletePayment(aRequestId, getter_AddRefs(response)); + break; + } + default : { + return NS_ERROR_FAILURE; + } + } + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + } else { + // Since there is no UI implementation and no testing UI Service is registered, + // set false response for canMakePayment() and ABORT_SUCCEEDED for abort() + switch (aActionType) { + case nsIPaymentActionRequest::CANMAKE_ACTION: { + nsCOMPtr canMakeResponse = + do_CreateInstance(NS_PAYMENT_CANMAKE_ACTION_RESPONSE_CONTRACT_ID); + MOZ_ASSERT(canMakeResponse); + rv = canMakeResponse->Init(aRequestId, false); + NS_ENSURE_SUCCESS(rv, rv); + response = do_QueryInterface(canMakeResponse); + MOZ_ASSERT(response); + break; + } + case nsIPaymentActionRequest::ABORT_ACTION: { + nsCOMPtr abortResponse = + do_CreateInstance(NS_PAYMENT_ABORT_ACTION_RESPONSE_CONTRACT_ID); + MOZ_ASSERT(abortResponse); + rv = abortResponse->Init(aRequestId, nsIPaymentActionResponse::ABORT_SUCCEEDED); + NS_ENSURE_SUCCESS(rv, rv); + response = do_QueryInterface(abortResponse); + MOZ_ASSERT(response); + break; + } + default : { + break; + } + } + } + if (response) { + rv = RespondPayment(response); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + } + return NS_OK; +} + +NS_IMETHODIMP +PaymentRequestService::RemoveActionCallback(nsIPaymentActionCallback* aCallback) +{ + NS_ENSURE_ARG_POINTER(aCallback); + for (auto iter = mCallbackHashtable.Iter(); !iter.Done(); iter.Next()) { + nsCOMPtr callback = iter.Data(); + MOZ_ASSERT(callback); + if (callback == aCallback) { + iter.Remove(); + return NS_OK; + } + } + return NS_OK; +} + NS_IMETHODIMP PaymentRequestService::RequestPayment(nsIPaymentActionRequest* aRequest) { NS_ENSURE_ARG_POINTER(aRequest); - uint32_t type; - nsresult rv = aRequest->GetType(&type); + + nsAutoString requestId; + nsresult rv = aRequest->GetRequestId(requestId); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } + nsCOMPtr callback; + rv = aRequest->GetCallback(getter_AddRefs(callback)); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + rv = SetActionCallback(requestId, callback); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + uint32_t type; + rv = aRequest->GetType(&type); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + switch (type) { case nsIPaymentActionRequest::CREATE_ACTION: { nsCOMPtr request = @@ -158,38 +266,52 @@ PaymentRequestService::RequestPayment(nsIPaymentActionRequest* aRequest) return rv; } - nsString requestId; - rv = request->GetRequestId(requestId); - if (NS_WARN_IF(NS_FAILED(rv))) { - return rv; - } - nsCOMPtr methodData; rv = request->GetMethodData(getter_AddRefs(methodData)); - if (NS_WARN_IF(NS_FAILED(rv) || !methodData)) { + if (NS_WARN_IF(NS_FAILED(rv))) { return NS_ERROR_FAILURE; } nsCOMPtr details; rv = request->GetDetails(getter_AddRefs(details)); - if (NS_WARN_IF(NS_FAILED(rv) || !details)) { + if (NS_WARN_IF(NS_FAILED(rv))) { return NS_ERROR_FAILURE; } nsCOMPtr options; rv = request->GetOptions(getter_AddRefs(options)); - if (NS_WARN_IF(NS_FAILED(rv) || !options)) { + if (NS_WARN_IF(NS_FAILED(rv))) { return NS_ERROR_FAILURE; } nsCOMPtr payment = - new payments::PaymentRequest(tabId, requestId, methodData, details, options); + new payments::PaymentRequest(tabId, requestId, methodData, details, options); if (!mRequestQueue.AppendElement(payment, mozilla::fallible)) { return NS_ERROR_OUT_OF_MEMORY; } break; } + /* + * TODO: 1. Check basic card support once the Basic Card Payment spec is + * implemented. + * https://www.w3.org/TR/payment-method-basic-card/ + * 2. Check third party payment app support by traversing all + * registered third party payment apps. + */ + case nsIPaymentActionRequest::CANMAKE_ACTION: + /* + * TODO: Launch/inform payment UI here once the UI module is implemented. + */ + case nsIPaymentActionRequest::SHOW_ACTION: + case nsIPaymentActionRequest::ABORT_ACTION: + case nsIPaymentActionRequest::COMPLETE_ACTION: { + rv = CallTestingUIAction(requestId, type); + if (NS_WARN_IF(NS_FAILED(rv))) { + return NS_ERROR_FAILURE; + } + break; + } default: { return NS_ERROR_FAILURE; } @@ -197,5 +319,84 @@ PaymentRequestService::RequestPayment(nsIPaymentActionRequest* aRequest) return NS_OK; } +NS_IMETHODIMP +PaymentRequestService::RespondPayment(nsIPaymentActionResponse* aResponse) +{ + NS_ENSURE_ARG_POINTER(aResponse); + nsAutoString requestId; + nsresult rv = aResponse->GetRequestId(requestId); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr request; + rv = GetPaymentRequestById(requestId, getter_AddRefs(request)); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + nsCOMPtr callback; + if (!mCallbackHashtable.Get(requestId, getter_AddRefs(callback))) { + return NS_ERROR_FAILURE; + } + if (NS_WARN_IF(!callback)) { + return NS_ERROR_FAILURE; + } + rv = callback->RespondPayment(aResponse); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + // Remove nsIPaymentRequest from mRequestQueue while receive succeeded abort + // response or complete response + uint32_t type; + rv = aResponse->GetType(&type); + NS_ENSURE_SUCCESS(rv, rv); + switch (type) { + case nsIPaymentActionResponse::ABORT_ACTION: { + nsCOMPtr response = + do_QueryInterface(aResponse); + MOZ_ASSERT(response); + bool isSucceeded; + rv = response->IsSucceeded(&isSucceeded); + NS_ENSURE_SUCCESS(rv, rv); + if (isSucceeded) { + mRequestQueue.RemoveElement(request); + } + break; + } + case nsIPaymentActionResponse::COMPLETE_ACTION: { + mRequestQueue.RemoveElement(request); + break; + } + default: { + break; + } + } + return NS_OK; +} + +nsresult +PaymentRequestService::SetActionCallback(const nsAString& aRequestId, + nsIPaymentActionCallback* aCallback) +{ + NS_ENSURE_ARG_POINTER(aCallback); + nsCOMPtr callback; + if (mCallbackHashtable.Get(aRequestId, getter_AddRefs(callback))) { + mCallbackHashtable.Remove(aRequestId); + } + mCallbackHashtable.Put(aRequestId, aCallback); + return NS_OK; +} + +nsresult +PaymentRequestService::RemoveActionCallback(const nsAString& aRequestId) +{ + nsCOMPtr callback; + if (!mCallbackHashtable.Get(aRequestId, getter_AddRefs(callback))) { + return NS_ERROR_FAILURE; + } + mCallbackHashtable.Remove(aRequestId); + return NS_OK; +} + } // end of namespace dom } // end of namespace mozilla diff --git a/dom/payments/PaymentRequestService.h b/dom/payments/PaymentRequestService.h index 1a8f2c142ebb..c4837297a02f 100644 --- a/dom/payments/PaymentRequestService.h +++ b/dom/payments/PaymentRequestService.h @@ -36,7 +36,21 @@ public: private: ~PaymentRequestService() = default; + nsresult + SetActionCallback(const nsAString& aRequestId, + nsIPaymentActionCallback* aCallback); + nsresult + RemoveActionCallback(const nsAString& aRequestId); + + // this method is only used for testing + nsresult + CallTestingUIAction(const nsAString& aRequestId, uint32_t aActionType); + FallibleTArray> mRequestQueue; + + nsInterfaceHashtable mCallbackHashtable; + + nsCOMPtr mTestingUIService; }; } // end of namespace dom diff --git a/dom/payments/PaymentRequestUtils.cpp b/dom/payments/PaymentRequestUtils.cpp index dc4158257c0c..6520d3f3eb52 100644 --- a/dom/payments/PaymentRequestUtils.cpp +++ b/dom/payments/PaymentRequestUtils.cpp @@ -38,53 +38,5 @@ ConvertStringstoISupportsStrings(const nsTArray& aStrings, return NS_OK; } -nsresult -ConvertISupportsStringstoStrings(nsIArray* aIStrings, - nsTArray& aStrings) -{ - NS_ENSURE_ARG_POINTER(aIStrings); - uint32_t length; - aStrings.Clear(); - nsresult rv = aIStrings->GetLength(&length); - if (NS_WARN_IF(NS_FAILED(rv))) { - return rv; - } - for (uint32_t index = 0; index < length; ++index) { - nsCOMPtr iString = do_QueryElementAt(aIStrings, index); - if (NS_WARN_IF(!iString)) { - return NS_ERROR_FAILURE; - } - nsString string; - rv = iString->GetData(string); - if (NS_WARN_IF(NS_FAILED(rv))) { - return rv; - } - aStrings.AppendElement(string); - } - return NS_OK; -} - -nsresult -CopyISupportsStrings(nsIArray* aSourceStrings, nsIArray** aTargetStrings) -{ - NS_ENSURE_ARG_POINTER(aTargetStrings); - *aTargetStrings = nullptr; - nsCOMPtr strings = do_CreateInstance(NS_ARRAY_CONTRACTID); - uint32_t length; - nsresult rv = aSourceStrings->GetLength(&length); - if (NS_WARN_IF(NS_FAILED(rv))) { - return rv; - } - for (uint32_t index = 0; index < length; ++index) { - nsCOMPtr string = do_QueryElementAt(aSourceStrings, index); - if (NS_WARN_IF(!string)) { - return NS_ERROR_FAILURE; - } - strings->AppendElement(string, false); - } - strings.forget(aTargetStrings); - return NS_OK; -} - } // end of namespace dom } // end of namespace mozilla diff --git a/dom/payments/PaymentRequestUtils.h b/dom/payments/PaymentRequestUtils.h index 2814927994d7..500108b6fb70 100644 --- a/dom/payments/PaymentRequestUtils.h +++ b/dom/payments/PaymentRequestUtils.h @@ -17,13 +17,6 @@ nsresult ConvertStringstoISupportsStrings(const nsTArray& aStrings, nsIArray** aIStrings); -nsresult -ConvertISupportsStringstoStrings(nsIArray* aIStrings, - nsTArray& aStrings); - -nsresult -CopyISupportsStrings(nsIArray* aSourceStrings, nsIArray** aTargetStrings); - } // end of namespace dom } // end of namespace mozilla diff --git a/dom/payments/PaymentResponse.cpp b/dom/payments/PaymentResponse.cpp new file mode 100644 index 000000000000..bee398a24896 --- /dev/null +++ b/dom/payments/PaymentResponse.cpp @@ -0,0 +1,155 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "mozilla/dom/PaymentResponse.h" + +namespace mozilla { +namespace dom { + +NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(PaymentResponse, mOwner, + mShippingAddress, mPromise) + +NS_IMPL_CYCLE_COLLECTING_ADDREF(PaymentResponse) +NS_IMPL_CYCLE_COLLECTING_RELEASE(PaymentResponse) + +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(PaymentResponse) + NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY + NS_INTERFACE_MAP_ENTRY(nsISupports) +NS_INTERFACE_MAP_END + +PaymentResponse::PaymentResponse(nsPIDOMWindowInner* aWindow, + const nsAString& aInternalId, + const nsAString& aRequestId, + const nsAString& aMethodName, + const nsAString& aShippingOption, + RefPtr aShippingAddress, + const nsAString& aDetails, + const nsAString& aPayerName, + const nsAString& aPayerEmail, + const nsAString& aPayerPhone) + : mOwner(aWindow) + , mCompleteCalled(false) + , mInternalId(aInternalId) + , mRequestId(aRequestId) + , mMethodName(aMethodName) + , mShippingOption(aShippingOption) + , mPayerName(aPayerName) + , mPayerEmail(aPayerEmail) + , mPayerPhone(aPayerPhone) + , mShippingAddress(aShippingAddress) +{ + + // TODO: from https://github.com/w3c/browser-payment-api/issues/480 + // Add payerGivenName + payerFamilyName to PaymentAddress + + // TODO : need to figure how to deserialize aDetails to JSObject + +} + +PaymentResponse::~PaymentResponse() +{ +} + +JSObject* +PaymentResponse::WrapObject(JSContext* aCx, JS::Handle aGivenProto) +{ + return PaymentResponseBinding::Wrap(aCx, this, aGivenProto); +} + +void +PaymentResponse::GetRequestId(nsString& aRetVal) const +{ + aRetVal = mRequestId; +} + +void +PaymentResponse::GetMethodName(nsString& aRetVal) const +{ + aRetVal = mMethodName; +} + +void +PaymentResponse::GetDetails(JSContext* cx, JS::MutableHandle aRetVal) const +{ + // TODO : need to save aDetails as JSObject +} + +void +PaymentResponse::GetShippingOption(nsString& aRetVal) const +{ + aRetVal = mShippingOption; +} + +void +PaymentResponse::GetPayerName(nsString& aRetVal) const +{ + aRetVal = mPayerName; +} + +void PaymentResponse::GetPayerEmail(nsString& aRetVal) const +{ + aRetVal = mPayerEmail; +} + +void PaymentResponse::GetPayerPhone(nsString& aRetVal) const +{ + aRetVal = mPayerPhone; +} + +// TODO: +// Return a raw pointer here to avoid refcounting, but make sure it's safe +// (the object should be kept alive by the callee). +already_AddRefed +PaymentResponse::GetShippingAddress() const +{ + RefPtr address = mShippingAddress; + return address.forget(); +} + +already_AddRefed +PaymentResponse::Complete(PaymentComplete result, ErrorResult& aRv) +{ + if (mCompleteCalled) { + aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR); + return nullptr; + } + + nsCOMPtr global = do_QueryInterface(mOwner); + ErrorResult errResult; + RefPtr promise = Promise::Create(global, errResult); + if (errResult.Failed()) { + aRv.Throw(NS_ERROR_FAILURE); + return nullptr; + } + + mCompleteCalled = true; + + RefPtr manager = PaymentRequestManager::GetSingleton(); + if (NS_WARN_IF(!manager)) { + aRv.Throw(NS_ERROR_FAILURE); + return nullptr; + } + nsresult rv = manager->CompletePayment(mInternalId, result); + if (NS_WARN_IF(NS_FAILED(rv))) { + promise->MaybeReject(NS_ERROR_FAILURE); + return promise.forget(); + } + + mPromise = promise; + return promise.forget(); +} + +void +PaymentResponse::RespondComplete() +{ + MOZ_ASSERT(mPromise); + + mPromise->MaybeResolve(JS::UndefinedHandleValue); + mPromise = nullptr; +} + +} // namespace dom +} // namespace mozilla diff --git a/dom/payments/PaymentResponse.h b/dom/payments/PaymentResponse.h new file mode 100644 index 000000000000..09b36fa976c9 --- /dev/null +++ b/dom/payments/PaymentResponse.h @@ -0,0 +1,89 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_dom_PaymentResponse_h +#define mozilla_dom_PaymentResponse_h + +#include "mozilla/dom/PaymentResponseBinding.h" // PaymentComplete +#include "nsPIDOMWindow.h" +#include "nsWrapperCache.h" + +namespace mozilla { +namespace dom { + +class PaymentAddress; +class Promise; + +class PaymentResponse final : public nsISupports, + public nsWrapperCache +{ +public: + NS_DECL_CYCLE_COLLECTING_ISUPPORTS + NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(PaymentResponse) + + PaymentResponse(nsPIDOMWindowInner* aWindow, + const nsAString& aInternalId, + const nsAString& aRequestId, + const nsAString& aMethodName, + const nsAString& aShippingOption, + RefPtr aShippingAddress, + const nsAString& aDetails, + const nsAString& aPayerName, + const nsAString& aPayerEmail, + const nsAString& aPayerPhone); + + nsPIDOMWindowInner* GetParentObject() const + { + return mOwner; + } + + virtual JSObject* WrapObject(JSContext* aCx, + JS::Handle aGivenProto) override; + + void GetRequestId(nsString& aRetVal) const; + + void GetMethodName(nsString& aRetVal) const; + + void GetDetails(JSContext* cx, JS::MutableHandle aRetVal) const; + + already_AddRefed GetShippingAddress() const; + + void GetShippingOption(nsString& aRetVal) const; + + void GetPayerName(nsString& aRetVal) const; + + void GetPayerEmail(nsString& aRetVal) const; + + void GetPayerPhone(nsString& aRetVal) const; + + // Return a raw pointer here to avoid refcounting, but make sure it's safe + // (the object should be kept alive by the callee). + already_AddRefed Complete(PaymentComplete result, ErrorResult& aRv); + + void RespondComplete(); + +protected: + ~PaymentResponse(); + +private: + nsCOMPtr mOwner; + bool mCompleteCalled; + nsString mInternalId; + nsString mRequestId; + nsString mMethodName; + nsString mShippingOption; + nsString mPayerName; + nsString mPayerEmail; + nsString mPayerPhone; + RefPtr mShippingAddress; + // Promise for "PaymentResponse::Complete" + RefPtr mPromise; +}; + +} // namespace dom +} // namespace mozilla + +#endif // mozilla_dom_PaymentResponse_h diff --git a/dom/payments/ipc/PPaymentRequest.ipdl b/dom/payments/ipc/PPaymentRequest.ipdl index 5d14bc8173d5..b5bdc4374a90 100644 --- a/dom/payments/ipc/PPaymentRequest.ipdl +++ b/dom/payments/ipc/PPaymentRequest.ipdl @@ -75,9 +75,71 @@ struct IPCPaymentCreateActionRequest IPCPaymentOptions options; }; +struct IPCPaymentCanMakeActionRequest +{ + nsString requestId; +}; + +struct IPCPaymentShowActionRequest +{ + nsString requestId; +}; + +struct IPCPaymentAbortActionRequest +{ + nsString requestId; +}; + +struct IPCPaymentCompleteActionRequest +{ + nsString requestId; + nsString completeStatus; +}; + union IPCPaymentActionRequest { IPCPaymentCreateActionRequest; + IPCPaymentCanMakeActionRequest; + IPCPaymentShowActionRequest; + IPCPaymentAbortActionRequest; + IPCPaymentCompleteActionRequest; +}; + +struct IPCPaymentCanMakeActionResponse +{ + nsString requestId; + bool result; +}; + +struct IPCPaymentShowActionResponse +{ + nsString requestId; + bool isAccepted; + nsString methodName; + nsString data; + nsString payerName; + nsString payerEmail; + nsString payerPhone; +}; + +struct IPCPaymentAbortActionResponse +{ + nsString requestId; + bool isSucceeded; +}; + +struct IPCPaymentCompleteActionResponse +{ + nsString requestId; + bool isCompleted; +}; + +union IPCPaymentActionResponse +{ + IPCPaymentCanMakeActionResponse; + IPCPaymentShowActionResponse; + IPCPaymentAbortActionResponse; + IPCPaymentCompleteActionResponse; }; sync protocol PPaymentRequest @@ -88,6 +150,9 @@ parent: async __delete__(); async RequestPayment(IPCPaymentActionRequest aAction); + +child: + async RespondPayment(IPCPaymentActionResponse aResponse); }; } // end of namespace dom diff --git a/dom/payments/ipc/PaymentRequestChild.cpp b/dom/payments/ipc/PaymentRequestChild.cpp index 495e309044e9..3352885bf126 100644 --- a/dom/payments/ipc/PaymentRequestChild.cpp +++ b/dom/payments/ipc/PaymentRequestChild.cpp @@ -21,17 +21,38 @@ PaymentRequestChild::RequestPayment(const IPCPaymentActionRequest& aAction) if (!mActorAlive) { return NS_ERROR_FAILURE; } - SendRequestPayment(aAction); + if (!SendRequestPayment(aAction)) { + return NS_ERROR_FAILURE; + } return NS_OK; } +mozilla::ipc::IPCResult +PaymentRequestChild::RecvRespondPayment(const IPCPaymentActionResponse& aResponse) +{ + if (!mActorAlive) { + return IPC_FAIL_NO_REASON(this); + } + const IPCPaymentActionResponse& response = aResponse; + RefPtr manager = PaymentRequestManager::GetSingleton(); + MOZ_ASSERT(manager); + nsresult rv = manager->RespondPayment(response); + if (NS_WARN_IF(NS_FAILED(rv))) { + return IPC_FAIL_NO_REASON(this); + } + return IPC_OK(); +} + void PaymentRequestChild::ActorDestroy(ActorDestroyReason aWhy) { mActorAlive = false; RefPtr manager = PaymentRequestManager::GetSingleton(); MOZ_ASSERT(manager); - manager->ReleasePaymentChild(this); + nsresult rv = manager->ReleasePaymentChild(this); + if (NS_WARN_IF(NS_FAILED(rv))) { + MOZ_ASSERT(false); + } } void diff --git a/dom/payments/ipc/PaymentRequestChild.h b/dom/payments/ipc/PaymentRequestChild.h index c632f7a58f0c..fa21184e5137 100644 --- a/dom/payments/ipc/PaymentRequestChild.h +++ b/dom/payments/ipc/PaymentRequestChild.h @@ -18,6 +18,9 @@ class PaymentRequestChild final : public PPaymentRequestChild public: PaymentRequestChild(); + virtual mozilla::ipc::IPCResult + RecvRespondPayment(const IPCPaymentActionResponse& aResponse) override; + void ActorDestroy(ActorDestroyReason aWhy) override; void MaybeDelete(); diff --git a/dom/payments/ipc/PaymentRequestParent.cpp b/dom/payments/ipc/PaymentRequestParent.cpp index fbd609c9ed31..b2fb89d2b33c 100644 --- a/dom/payments/ipc/PaymentRequestParent.cpp +++ b/dom/payments/ipc/PaymentRequestParent.cpp @@ -8,7 +8,6 @@ #include "nsArrayUtils.h" #include "nsCOMPtr.h" #include "nsIMutableArray.h" -#include "nsIPaymentActionRequest.h" #include "nsIPaymentRequestService.h" #include "nsISupportsPrimitives.h" #include "nsServiceManagerUtils.h" @@ -18,6 +17,8 @@ namespace mozilla { namespace dom { +NS_IMPL_ISUPPORTS(PaymentRequestParent, nsIPaymentActionCallback) + PaymentRequestParent::PaymentRequestParent(uint64_t aTabId) : mActorAlived(true) , mTabId(aTabId) @@ -27,12 +28,16 @@ PaymentRequestParent::PaymentRequestParent(uint64_t aTabId) mozilla::ipc::IPCResult PaymentRequestParent::RecvRequestPayment(const IPCPaymentActionRequest& aRequest) { - MOZ_ASSERT(mActorAlived); - nsCOMPtr actionRequest; + if (!mActorAlived) { + return IPC_FAIL_NO_REASON(this); + } + nsCOMPtr action; + nsCOMPtr callback = do_QueryInterface(this); + MOZ_ASSERT(callback); nsresult rv; switch (aRequest.type()) { case IPCPaymentActionRequest::TIPCPaymentCreateActionRequest: { - IPCPaymentCreateActionRequest request = aRequest; + const IPCPaymentCreateActionRequest& request = aRequest; nsCOMPtr methodData = do_CreateInstance(NS_ARRAY_CONTRACTID); MOZ_ASSERT(methodData); @@ -60,22 +65,67 @@ PaymentRequestParent::RecvRequestPayment(const IPCPaymentActionRequest& aRequest return IPC_FAIL_NO_REASON(this); } - nsCOMPtr createRequest = + nsCOMPtr createAction = do_CreateInstance(NS_PAYMENT_CREATE_ACTION_REQUEST_CONTRACT_ID); - if (NS_WARN_IF(!createRequest)) { + if (NS_WARN_IF(!createAction)) { return IPC_FAIL_NO_REASON(this); } - rv = createRequest->InitRequest(request.requestId(), - mTabId, - methodData, - details, - options); + rv = createAction->InitRequest(request.requestId(), + callback, + mTabId, + methodData, + details, + options); if (NS_WARN_IF(NS_FAILED(rv))) { return IPC_FAIL_NO_REASON(this); } - actionRequest = do_QueryInterface(createRequest); - MOZ_ASSERT(actionRequest); + action = do_QueryInterface(createAction); + MOZ_ASSERT(action); + break; + } + case IPCPaymentActionRequest::TIPCPaymentCanMakeActionRequest: { + const IPCPaymentCanMakeActionRequest& request = aRequest; + rv = CreateActionRequest(request.requestId(), + nsIPaymentActionRequest::CANMAKE_ACTION, + getter_AddRefs(action)); + if (NS_WARN_IF(NS_FAILED(rv))) { + return IPC_FAIL_NO_REASON(this); + } + break; + } + case IPCPaymentActionRequest::TIPCPaymentShowActionRequest: { + const IPCPaymentShowActionRequest& request = aRequest; + rv = CreateActionRequest(request.requestId(), + nsIPaymentActionRequest::SHOW_ACTION, + getter_AddRefs(action)); + if (NS_WARN_IF(NS_FAILED(rv))) { + return IPC_FAIL_NO_REASON(this); + } + break; + } + case IPCPaymentActionRequest::TIPCPaymentAbortActionRequest: { + const IPCPaymentAbortActionRequest& request = aRequest; + rv = CreateActionRequest(request.requestId(), + nsIPaymentActionRequest::ABORT_ACTION, + getter_AddRefs(action)); + if (NS_WARN_IF(NS_FAILED(rv))) { + return IPC_FAIL_NO_REASON(this); + } + break; + } + case IPCPaymentActionRequest::TIPCPaymentCompleteActionRequest: { + const IPCPaymentCompleteActionRequest& request = aRequest; + nsCOMPtr completeAction = + do_CreateInstance(NS_PAYMENT_COMPLETE_ACTION_REQUEST_CONTRACT_ID); + rv = completeAction->InitRequest(request.requestId(), + callback, + request.completeStatus()); + if (NS_WARN_IF(NS_FAILED(rv))) { + return IPC_FAIL_NO_REASON(this); + } + action = do_QueryInterface(completeAction); + MOZ_ASSERT(action); break; } default: { @@ -85,13 +135,110 @@ PaymentRequestParent::RecvRequestPayment(const IPCPaymentActionRequest& aRequest nsCOMPtr service = do_GetService(NS_PAYMENT_REQUEST_SERVICE_CONTRACT_ID); MOZ_ASSERT(service); - rv = service->RequestPayment(actionRequest); + rv = service->RequestPayment(action); if (NS_WARN_IF(NS_FAILED(rv))) { return IPC_FAIL_NO_REASON(this); } return IPC_OK(); } +NS_IMETHODIMP +PaymentRequestParent::RespondPayment(nsIPaymentActionResponse* aResponse) +{ + if (!NS_IsMainThread()) { + nsCOMPtr self = do_QueryInterface(this); + MOZ_ASSERT(self); + nsCOMPtr response = aResponse; + nsCOMPtr r = NS_NewRunnableFunction([self, response] () + { + self->RespondPayment(response); + }); + return NS_DispatchToMainThread(r); + } + + if (!mActorAlived) { + return NS_ERROR_FAILURE; + } + uint32_t type; + nsresult rv = aResponse->GetType(&type); + NS_ENSURE_SUCCESS(rv, rv); + nsAutoString requestId; + rv = aResponse->GetRequestId(requestId); + NS_ENSURE_SUCCESS(rv, rv); + switch (type) { + case nsIPaymentActionResponse::CANMAKE_ACTION: { + nsCOMPtr response = do_QueryInterface(aResponse); + MOZ_ASSERT(response); + bool result; + rv = response->GetResult(&result); + NS_ENSURE_SUCCESS(rv, rv); + IPCPaymentCanMakeActionResponse actionResponse(requestId, result); + if (!SendRespondPayment(actionResponse)) { + return NS_ERROR_FAILURE; + } + break; + } + case nsIPaymentActionResponse::SHOW_ACTION: { + nsCOMPtr response = + do_QueryInterface(aResponse); + MOZ_ASSERT(response); + bool isAccepted; + NS_ENSURE_SUCCESS(response->IsAccepted(&isAccepted), NS_ERROR_FAILURE); + nsAutoString methodName; + NS_ENSURE_SUCCESS(response->GetMethodName(methodName), NS_ERROR_FAILURE); + nsAutoString data; + NS_ENSURE_SUCCESS(response->GetData(data), NS_ERROR_FAILURE); + nsAutoString payerName; + NS_ENSURE_SUCCESS(response->GetPayerName(payerName), NS_ERROR_FAILURE); + nsAutoString payerEmail; + NS_ENSURE_SUCCESS(response->GetPayerEmail(payerEmail), NS_ERROR_FAILURE); + nsAutoString payerPhone; + NS_ENSURE_SUCCESS(response->GetPayerPhone(payerPhone), NS_ERROR_FAILURE); + IPCPaymentShowActionResponse actionResponse(requestId, + isAccepted, + methodName, + data, + payerName, + payerEmail, + payerPhone); + if (!SendRespondPayment(actionResponse)) { + return NS_ERROR_FAILURE; + } + break; + } + case nsIPaymentActionResponse::ABORT_ACTION: { + nsCOMPtr response = + do_QueryInterface(aResponse); + MOZ_ASSERT(response); + bool isSucceeded; + rv = response->IsSucceeded(&isSucceeded); + NS_ENSURE_SUCCESS(rv, rv); + IPCPaymentAbortActionResponse actionResponse(requestId, isSucceeded); + if (!SendRespondPayment(actionResponse)) { + return NS_ERROR_FAILURE; + } + break; + } + case nsIPaymentActionResponse::COMPLETE_ACTION: { + nsCOMPtr response = + do_QueryInterface(aResponse); + MOZ_ASSERT(response); + bool isCompleted; + rv = response->IsCompleted(&isCompleted); + NS_ENSURE_SUCCESS(rv, rv); + IPCPaymentCompleteActionResponse actionResponse(requestId, isCompleted); + if (!SendRespondPayment(actionResponse)) { + return NS_ERROR_FAILURE; + } + break; + } + default: { + return NS_ERROR_FAILURE; + } + } + return NS_OK; +} + mozilla::ipc::IPCResult PaymentRequestParent::Recv__delete__() { @@ -103,6 +250,34 @@ void PaymentRequestParent::ActorDestroy(ActorDestroyReason aWhy) { mActorAlived = false; + nsCOMPtr service = + do_GetService(NS_PAYMENT_REQUEST_SERVICE_CONTRACT_ID); + MOZ_ASSERT(service); + nsCOMPtr callback = do_QueryInterface(this); + MOZ_ASSERT(callback); + nsresult rv = service->RemoveActionCallback(callback); + if (NS_WARN_IF(NS_FAILED(rv))) { + MOZ_ASSERT(false); + } +} + +nsresult +PaymentRequestParent::CreateActionRequest(const nsAString& aRequestId, + uint32_t aActionType, + nsIPaymentActionRequest** aAction) +{ + NS_ENSURE_ARG_POINTER(aAction); + nsCOMPtr action = + do_CreateInstance(NS_PAYMENT_ACTION_REQUEST_CONTRACT_ID); + MOZ_ASSERT(action); + nsCOMPtr callback = do_QueryInterface(this); + MOZ_ASSERT(callback); + nsresult rv = action->Init(aRequestId, aActionType, callback); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + action.forget(aAction); + return NS_OK; } } // end of namespace dom diff --git a/dom/payments/ipc/PaymentRequestParent.h b/dom/payments/ipc/PaymentRequestParent.h index 95c193c42cbe..2c2214d38dbb 100644 --- a/dom/payments/ipc/PaymentRequestParent.h +++ b/dom/payments/ipc/PaymentRequestParent.h @@ -8,15 +8,16 @@ #define mozilla_dom_PaymentRequestParent_h #include "mozilla/dom/PPaymentRequestParent.h" -#include "nsISupports.h" +#include "nsIPaymentActionRequest.h" namespace mozilla { namespace dom { -class PaymentRequestParent final : public PPaymentRequestParent +class PaymentRequestParent final : public nsIPaymentActionCallback + , public PPaymentRequestParent { -public: - NS_INLINE_DECL_THREADSAFE_REFCOUNTING(PaymentRequestParent) + NS_DECL_THREADSAFE_ISUPPORTS + NS_DECL_NSIPAYMENTACTIONCALLBACK explicit PaymentRequestParent(uint64_t aTabId); @@ -30,6 +31,10 @@ protected: private: ~PaymentRequestParent() = default; + nsresult CreateActionRequest(const nsAString& aRequestId, + uint32_t aActionType, + nsIPaymentActionRequest** aAction); + bool mActorAlived; uint64_t mTabId; }; diff --git a/dom/payments/moz.build b/dom/payments/moz.build index 52ffa275463c..78515defc568 100644 --- a/dom/payments/moz.build +++ b/dom/payments/moz.build @@ -14,18 +14,23 @@ EXPORTS += [ ] EXPORTS.mozilla.dom += [ + 'PaymentAddress.h', 'PaymentRequest.h', 'PaymentRequestManager.h', + 'PaymentResponse.h', ] UNIFIED_SOURCES += [ 'PaymentActionRequest.cpp', + 'PaymentActionResponse.cpp', + 'PaymentAddress.cpp', 'PaymentRequest.cpp', 'PaymentRequestData.cpp', 'PaymentRequestManager.cpp', 'PaymentRequestModule.cpp', 'PaymentRequestService.cpp', 'PaymentRequestUtils.cpp', + 'PaymentResponse.cpp', ] include('/ipc/chromium/chromium-config.mozbuild') diff --git a/dom/webidl/PaymentAddress.webidl b/dom/webidl/PaymentAddress.webidl new file mode 100644 index 000000000000..b3c502492616 --- /dev/null +++ b/dom/webidl/PaymentAddress.webidl @@ -0,0 +1,31 @@ +/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + * + * The origin of this WebIDL file is + * https://www.w3.org/TR/payment-request/#paymentaddress-interface + */ + +[SecureContext, + Func="mozilla::dom::PaymentRequest::PrefEnabled"] +interface PaymentAddress { + // TODO: Use serializer once available. (Bug 863402) + // serializer = {attribute}; + jsonifier; + + readonly attribute DOMString country; + // TODO: Use FrozenArray once available. (Bug 1236777) + // readonly attribute FrozenArray addressLine; + [Frozen, Cached, Pure] + readonly attribute sequence addressLine; + readonly attribute DOMString region; + readonly attribute DOMString city; + readonly attribute DOMString dependentLocality; + readonly attribute DOMString postalCode; + readonly attribute DOMString sortingCode; + readonly attribute DOMString languageCode; + readonly attribute DOMString organization; + readonly attribute DOMString recipient; + readonly attribute DOMString phone; +}; diff --git a/dom/webidl/PaymentRequest.webidl b/dom/webidl/PaymentRequest.webidl index 1f80967f88cd..5819a39fe071 100644 --- a/dom/webidl/PaymentRequest.webidl +++ b/dom/webidl/PaymentRequest.webidl @@ -68,19 +68,15 @@ dictionary PaymentOptions { SecureContext, Func="mozilla::dom::PaymentRequest::PrefEnabled"] interface PaymentRequest : EventTarget { - /* TODO : Add show() support in Bug 1345366 [NewObject] Promise show(); - */ [NewObject] Promise abort(); [NewObject] Promise canMakePayment(); readonly attribute DOMString id; - /* TODO : Add PaymentAddress support in Bug 1345369 readonly attribute PaymentAddress? shippingAddress; - */ readonly attribute DOMString? shippingOption; readonly attribute PaymentShippingType? shippingType; diff --git a/dom/webidl/PaymentResponse.webidl b/dom/webidl/PaymentResponse.webidl new file mode 100644 index 000000000000..5c0319f20788 --- /dev/null +++ b/dom/webidl/PaymentResponse.webidl @@ -0,0 +1,34 @@ +/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + * + * The origin of this WebIDL file is + * https://www.w3.org/TR/payment-request/#paymentresponse-interface + */ + +enum PaymentComplete { + "success", + "fail", + "unknown" +}; + +[SecureContext, + Func="mozilla::dom::PaymentRequest::PrefEnabled"] +interface PaymentResponse { + // TODO: Use serializer once available. (Bug 863402) + // serializer = {attribute}; + jsonifier; + + readonly attribute DOMString requestId; + readonly attribute DOMString methodName; + readonly attribute object details; + readonly attribute PaymentAddress? shippingAddress; + readonly attribute DOMString? shippingOption; + readonly attribute DOMString? payerName; + readonly attribute DOMString? payerEmail; + readonly attribute DOMString? payerPhone; + + [NewObject] + Promise complete(optional PaymentComplete result = "unknown"); +}; diff --git a/dom/webidl/moz.build b/dom/webidl/moz.build index d2d03738b1a6..8b4facf17355 100644 --- a/dom/webidl/moz.build +++ b/dom/webidl/moz.build @@ -724,7 +724,9 @@ WEBIDL_FILES = [ 'PaintWorkletGlobalScope.webidl', 'PannerNode.webidl', 'ParentNode.webidl', + 'PaymentAddress.webidl', 'PaymentRequest.webidl', + 'PaymentResponse.webidl', 'Performance.webidl', 'PerformanceEntry.webidl', 'PerformanceMark.webidl',