Chromium Code Reviews| Index: ios/chrome/browser/payments/payment_request_manager.mm |
| diff --git a/ios/chrome/browser/payments/payment_request_manager.mm b/ios/chrome/browser/payments/payment_request_manager.mm |
| index 5bab9194d65f113d863ccfc166c7dc50593dbf85..4d6d9fb9cb707eda4d1201fe18759f1634a1a18c 100644 |
| --- a/ios/chrome/browser/payments/payment_request_manager.mm |
| +++ b/ios/chrome/browser/payments/payment_request_manager.mm |
| @@ -4,6 +4,7 @@ |
| #import "ios/chrome/browser/payments/payment_request_manager.h" |
| +#include "base/ios/block_types.h" |
| #include "base/ios/ios_util.h" |
| #import "base/mac/bind_objc_block.h" |
| #include "base/mac/foundation_util.h" |
| @@ -88,9 +89,13 @@ const NSTimeInterval kTimeoutInterval = 60.0; |
| // Timer used to periodically unblock the webview's JS event queue. |
| NSTimer* _unblockEventQueueTimer; |
| - // Timer used to close the UI if the page does not call |
| - // PaymentResponse.complete() in a timely fashion. |
| + // Timer used to complete the Payment Request flow and close the UI if the |
| + // page does not call PaymentResponse.complete() in a timely fashion. |
| NSTimer* _paymentResponseTimeoutTimer; |
| + |
| + // Timer used to cancel the Payment Request flow and close the UI if the |
| + // page does not settle the pending update promise in a timely fashion. |
| + NSTimer* _updateEventTimeoutTimer; |
| } |
| // Synchronous method executed by -asynchronouslyEnablePaymentRequest: |
| @@ -107,9 +112,14 @@ const NSTimeInterval kTimeoutInterval = 60.0; |
| // invocation was successful. |
| - (BOOL)handleRequestShow:(const base::DictionaryValue&)message; |
| +// Called by |_paymentResponseTimeoutTimer|, invokes handleResponseComplete: |
| +// as if PaymentResponse.complete() was invoked with the default "unknown" |
| +// argument. |
| +- (BOOL)handleResponseComplete; |
| + |
| // Handles invocations of PaymentResponse.complete(). Returns YES if the |
| // invocation was successful. |
| -- (BOOL)handleResponseComplete; |
| +- (BOOL)handleResponseComplete:(const base::DictionaryValue&)message; |
| // Handles invocations of PaymentRequestUpdateEvent.updateWith(). Returns YES if |
| // the invocation was successful. |
| @@ -126,6 +136,13 @@ const NSTimeInterval kTimeoutInterval = 60.0; |
| // called with no arguments. |
| - (void)setPaymentResponseTimeoutTimer; |
| +// Establishes a timer that dismisses the Payment Request UI when it times out. |
| +// Per the spec, implementations may choose to consider a timeout for the |
| +// promise provided with the PaymentRequestUpdateEvent.updateWith() call. If the |
| +// promise doesn't get settled in a reasonable amount of time, it is as if it |
| +// was rejected. |
| +- (void)setUpdateEventTimeoutTimer; |
| + |
| @end |
| @implementation PaymentRequestManager |
| @@ -275,7 +292,7 @@ const NSTimeInterval kTimeoutInterval = 60.0; |
| return [self handleRequestCancel]; |
| } |
| if (command == "paymentRequest.responseComplete") { |
| - return [self handleResponseComplete]; |
| + return [self handleResponseComplete:JSONCommand]; |
| } |
| if (command == "paymentRequest.updatePaymentDetails") { |
| return [self handleUpdatePaymentDetails:JSONCommand]; |
| @@ -334,22 +351,51 @@ const NSTimeInterval kTimeoutInterval = 60.0; |
| [_unblockEventQueueTimer invalidate]; |
| [_paymentResponseTimeoutTimer invalidate]; |
| + [_updateEventTimeoutTimer invalidate]; |
| - [self cancelRequestWithErrorMessage:@"Request canceled by the page."]; |
| + __weak PaymentRequestManager* weakSelf = self; |
| + ProceduralBlock callback = ^{ |
| + PaymentRequestManager* strongSelf = weakSelf; |
| + [strongSelf cancelRequestWithErrorMessage:@"Request canceled."]; |
|
lpromero
2017/02/23 09:17:41
Add early return if strongSelf == nil. The behavio
Moe
2017/02/23 14:44:01
That makes sense. The base ACRify CL removes the e
|
| + }; |
| + |
| + [_paymentRequestCoordinator displayErrorWithCallback:callback]; |
| return YES; |
| } |
| - (BOOL)handleResponseComplete { |
| + base::DictionaryValue command; |
| + command.SetString("result", "unknown"); |
| + return [self handleResponseComplete:command]; |
| +} |
| + |
| +- (BOOL)handleResponseComplete:(const base::DictionaryValue&)message { |
| // TODO(crbug.com/602666): Check that there *is* a pending response here. |
| - // TODO(crbug.com/602666): Indicate success or failure in the UI. |
| [_unblockEventQueueTimer invalidate]; |
| [_paymentResponseTimeoutTimer invalidate]; |
| + [_updateEventTimeoutTimer invalidate]; |
| - [self dismissUI]; |
| + std::string result; |
| + if (!message.GetString("result", &result)) { |
| + DLOG(ERROR) << "JS message parameter 'result' is missing"; |
| + return NO; |
| + } |
| - [_paymentRequestJsManager resolveResponsePromiseWithCompletionHandler:nil]; |
| + __weak PaymentRequestManager* weakSelf = self; |
| + ProceduralBlock callback = ^{ |
| + PaymentRequestManager* strongSelf = weakSelf; |
|
lpromero
2017/02/23 09:17:41
Add early return if strongSelf == nil.
Moe
2017/02/23 14:44:01
Done.
|
| + [strongSelf dismissUI]; |
| + [_paymentRequestJsManager resolveResponsePromiseWithCompletionHandler:nil]; |
|
lpromero
2017/02/23 09:17:41
strongSelf->_paymentRequestJsManager, otherwise yo
Moe
2017/02/23 14:44:01
Done!
|
| + }; |
| + |
| + // Display UI indicating failure if the value of |result| is "fail". |
| + if (result == "fail") { |
| + [_paymentRequestCoordinator displayErrorWithCallback:callback]; |
| + } else { |
| + callback(); |
| + } |
| return YES; |
| } |
| @@ -358,6 +404,7 @@ const NSTimeInterval kTimeoutInterval = 60.0; |
| // TODO(crbug.com/602666): Check that there is already a pending request. |
| [_unblockEventQueueTimer invalidate]; |
| + [_updateEventTimeoutTimer invalidate]; |
| const base::DictionaryValue* paymentDetailsData = nullptr; |
| web::PaymentDetails paymentDetails; |
| @@ -393,6 +440,15 @@ const NSTimeInterval kTimeoutInterval = 60.0; |
| repeats:NO]; |
| } |
| +- (void)setUpdateEventTimeoutTimer { |
| + _updateEventTimeoutTimer = |
| + [NSTimer scheduledTimerWithTimeInterval:kTimeoutInterval |
| + target:self |
| + selector:@selector(handleRequestCancel) |
| + userInfo:nil |
| + repeats:NO]; |
| +} |
| + |
| - (void)dismissUI { |
| [_paymentRequestCoordinator stop]; |
| _paymentRequestCoordinator = nil; |
| @@ -419,7 +475,7 @@ const NSTimeInterval kTimeoutInterval = 60.0; |
| - (void)paymentRequestCoordinatorDidCancel: |
| (PaymentRequestCoordinator*)coordinator { |
| - [self cancelRequestWithErrorMessage:@"Request canceled by user."]; |
| + [self cancelRequestWithErrorMessage:@"Request canceled."]; |
| } |
| - (void)paymentRequestCoordinator:(PaymentRequestCoordinator*)coordinator |
| @@ -436,6 +492,7 @@ const NSTimeInterval kTimeoutInterval = 60.0; |
| [_paymentRequestJsManager updateShippingAddress:shippingAddress |
| completionHandler:nil]; |
| [self setUnblockEventQueueTimer]; |
| + [self setUpdateEventTimeoutTimer]; |
| } |
| - (void)paymentRequestCoordinator:(PaymentRequestCoordinator*)coordinator |
| @@ -443,6 +500,7 @@ const NSTimeInterval kTimeoutInterval = 60.0; |
| [_paymentRequestJsManager updateShippingOption:shippingOption |
| completionHandler:nil]; |
| [self setUnblockEventQueueTimer]; |
| + [self setUpdateEventTimeoutTimer]; |
| } |
| #pragma mark - CRWWebStateObserver methods |