Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(293)

Side by Side Diff: ios/chrome/browser/payments/payment_request_manager.mm

Issue 2701923003: [Payment Request] Error message screen (Closed)
Patch Set: Created 3 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2016 The Chromium Authors. All rights reserved. 1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #import "ios/chrome/browser/payments/payment_request_manager.h" 5 #import "ios/chrome/browser/payments/payment_request_manager.h"
6 6
7 #include "base/ios/ios_util.h" 7 #include "base/ios/ios_util.h"
8 #import "base/ios/weak_nsobject.h" 8 #import "base/ios/weak_nsobject.h"
9 #import "base/mac/bind_objc_block.h" 9 #import "base/mac/bind_objc_block.h"
10 #include "base/mac/foundation_util.h" 10 #include "base/mac/foundation_util.h"
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after
79 // True when close has been called and the PaymentRequest coordinator has 79 // True when close has been called and the PaymentRequest coordinator has
80 // been destroyed. 80 // been destroyed.
81 BOOL _closed; 81 BOOL _closed;
82 82
83 // Coordinator used to create and present the PaymentRequest view controller. 83 // Coordinator used to create and present the PaymentRequest view controller.
84 base::scoped_nsobject<PaymentRequestCoordinator> _paymentRequestCoordinator; 84 base::scoped_nsobject<PaymentRequestCoordinator> _paymentRequestCoordinator;
85 85
86 // Timer used to periodically unblock the webview's JS event queue. 86 // Timer used to periodically unblock the webview's JS event queue.
87 base::scoped_nsobject<NSTimer> _unblockEventQueueTimer; 87 base::scoped_nsobject<NSTimer> _unblockEventQueueTimer;
88 88
89 // Timer used to close the UI if the page does not call 89 // Timer used to complete the Payment Request flow and close the UI if the
90 // PaymentResponse.complete() in a timely fashion. 90 // page does not call PaymentResponse.complete() in a timely fashion.
91 base::scoped_nsobject<NSTimer> _paymentResponseTimeoutTimer; 91 base::scoped_nsobject<NSTimer> _paymentResponseTimeoutTimer;
92
93 // Timer used to cancel the Payment Request flow and close the UI if the
94 // page does not call settle the pending update promise in a timely fashion.
95 base::scoped_nsobject<NSTimer> _updateEventTimeoutTimer;
92 } 96 }
93 97
94 // Synchronous method executed by -asynchronouslyEnablePaymentRequest: 98 // Synchronous method executed by -asynchronouslyEnablePaymentRequest:
95 - (void)doEnablePaymentRequest:(BOOL)enabled; 99 - (void)doEnablePaymentRequest:(BOOL)enabled;
96 100
97 // Initialize the PaymentRequest JavaScript. 101 // Initialize the PaymentRequest JavaScript.
98 - (void)initializeWebViewForPaymentRequest; 102 - (void)initializeWebViewForPaymentRequest;
99 103
100 // Handler for injected JavaScript callbacks. 104 // Handler for injected JavaScript callbacks.
101 - (BOOL)handleScriptCommand:(const base::DictionaryValue&)JSONCommand; 105 - (BOOL)handleScriptCommand:(const base::DictionaryValue&)JSONCommand;
102 106
103 // Handles invocations of PaymentRequest.show(). The value of the JavaScript 107 // Handles invocations of PaymentRequest.show(). The value of the JavaScript
104 // PaymentRequest object should be provided in |message|. Returns YES if the 108 // PaymentRequest object should be provided in |message|. Returns YES if the
105 // invocation was successful. 109 // invocation was successful.
106 - (BOOL)handleRequestShow:(const base::DictionaryValue&)message; 110 - (BOOL)handleRequestShow:(const base::DictionaryValue&)message;
107 111
112 // Called by |_paymentResponseTimeoutTimer|, invokes handleResponseComplete:
113 // as if PaymentResponse.complete() was invoked with the default "unkown"
lpromero 2017/02/20 17:14:07 *unknown
Moe 2017/02/21 05:07:06 Done.
114 // argument.
115 - (BOOL)handleResponseComplete;
116
108 // Handles invocations of PaymentResponse.complete(). Returns YES if the 117 // Handles invocations of PaymentResponse.complete(). Returns YES if the
109 // invocation was successful. 118 // invocation was successful.
110 - (BOOL)handleResponseComplete; 119 - (BOOL)handleResponseComplete:(const base::DictionaryValue&)message;
111 120
112 // Handles invocations of PaymentRequestUpdateEvent.updateWith(). Returns YES if 121 // Handles invocations of PaymentRequestUpdateEvent.updateWith(). Returns YES if
113 // the invocation was successful. 122 // the invocation was successful.
114 - (BOOL)handleUpdatePaymentDetails:(const base::DictionaryValue&)message; 123 - (BOOL)handleUpdatePaymentDetails:(const base::DictionaryValue&)message;
115 124
116 // Establishes a timer that periodically prompts the JS manager to execute a 125 // Establishes a timer that periodically prompts the JS manager to execute a
117 // noop. This works around an issue where the JS event queue is blocked while 126 // noop. This works around an issue where the JS event queue is blocked while
118 // presenting the Payment Request UI. 127 // presenting the Payment Request UI.
119 - (void)setUnblockEventQueueTimer; 128 - (void)setUnblockEventQueueTimer;
120 129
121 // Establishes a timer that calls handleResponseComplete when it times out. Per 130 // Establishes a timer that calls handleResponseComplete when it times out. Per
122 // the spec, if the page does not call PaymentResponse.complete() within some 131 // the spec, if the page does not call PaymentResponse.complete() within some
123 // timeout period, user agents may behave as if the complete() method was 132 // timeout period, user agents may behave as if the complete() method was
124 // called with no arguments. 133 // called with no arguments.
125 - (void)setPaymentResponseTimeoutTimer; 134 - (void)setPaymentResponseTimeoutTimer;
126 135
136 // Establishes a timer that dismisses the Payment Request UI when it times out.
137 // Per the spec, implementations may choose to consider a timeout for the
138 // promise provided with the PaymentRequestUpdateEvent.updateWith() call. If the
139 // promise doesn't get settled in a reasonable amount of time, it is as if it
140 // was rejected.
141 - (void)setUpdateEventTimeoutTimer;
142
127 @end 143 @end
128 144
129 @implementation PaymentRequestManager 145 @implementation PaymentRequestManager
130 146
131 @synthesize enabled = _enabled; 147 @synthesize enabled = _enabled;
132 @synthesize webState = _webState; 148 @synthesize webState = _webState;
133 @synthesize browserState = _browserState; 149 @synthesize browserState = _browserState;
134 150
135 - (instancetype)initWithBaseViewController:(UIViewController*)viewController 151 - (instancetype)initWithBaseViewController:(UIViewController*)viewController
136 browserState: 152 browserState:
(...skipping 131 matching lines...) Expand 10 before | Expand all | Expand 10 after
268 return NO; 284 return NO;
269 } 285 }
270 286
271 if (command == "paymentRequest.requestShow") { 287 if (command == "paymentRequest.requestShow") {
272 return [self handleRequestShow:JSONCommand]; 288 return [self handleRequestShow:JSONCommand];
273 } 289 }
274 if (command == "paymentRequest.requestCancel") { 290 if (command == "paymentRequest.requestCancel") {
275 return [self handleRequestCancel]; 291 return [self handleRequestCancel];
276 } 292 }
277 if (command == "paymentRequest.responseComplete") { 293 if (command == "paymentRequest.responseComplete") {
278 return [self handleResponseComplete]; 294 return [self handleResponseComplete:JSONCommand];
279 } 295 }
280 if (command == "paymentRequest.updatePaymentDetails") { 296 if (command == "paymentRequest.updatePaymentDetails") {
281 return [self handleUpdatePaymentDetails:JSONCommand]; 297 return [self handleUpdatePaymentDetails:JSONCommand];
282 } 298 }
283 return NO; 299 return NO;
284 } 300 }
285 301
286 - (BOOL)handleRequestShow:(const base::DictionaryValue&)message { 302 - (BOOL)handleRequestShow:(const base::DictionaryValue&)message {
287 // TODO(crbug.com/602666): check that there's not already a pending request. 303 // TODO(crbug.com/602666): check that there's not already a pending request.
288 // TODO(crbug.com/602666): compare our supported payment types (i.e. autofill 304 // TODO(crbug.com/602666): compare our supported payment types (i.e. autofill
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
327 [_paymentRequestCoordinator start]; 343 [_paymentRequestCoordinator start];
328 344
329 return YES; 345 return YES;
330 } 346 }
331 347
332 - (BOOL)handleRequestCancel { 348 - (BOOL)handleRequestCancel {
333 // TODO(crbug.com/602666): Check that there is already a pending request. 349 // TODO(crbug.com/602666): Check that there is already a pending request.
334 350
335 [_unblockEventQueueTimer invalidate]; 351 [_unblockEventQueueTimer invalidate];
336 [_paymentResponseTimeoutTimer invalidate]; 352 [_paymentResponseTimeoutTimer invalidate];
353 [_updateEventTimeoutTimer invalidate];
337 354
338 [self cancelRequestWithErrorMessage:@"Request canceled by the page."]; 355 void (^callback)() = ^{
356 [self cancelRequestWithErrorMessage:@"Request canceled."];
357 };
358
359 [_paymentRequestCoordinator displayErrorWithCallback:callback];
339 360
340 return YES; 361 return YES;
341 } 362 }
342 363
343 - (BOOL)handleResponseComplete { 364 - (BOOL)handleResponseComplete {
365 base::DictionaryValue command;
366 command.SetString("result", "unknown");
367 return [self handleResponseComplete:command];
368 }
369
370 - (BOOL)handleResponseComplete:(const base::DictionaryValue&)message {
344 // TODO(crbug.com/602666): Check that there *is* a pending response here. 371 // TODO(crbug.com/602666): Check that there *is* a pending response here.
345 // TODO(crbug.com/602666): Indicate success or failure in the UI.
346 372
347 [_unblockEventQueueTimer invalidate]; 373 [_unblockEventQueueTimer invalidate];
348 [_paymentResponseTimeoutTimer invalidate]; 374 [_paymentResponseTimeoutTimer invalidate];
375 [_updateEventTimeoutTimer invalidate];
349 376
350 [self dismissUI]; 377 [_unblockEventQueueTimer invalidate];
351 378
352 [_paymentRequestJsManager resolveResponsePromiseWithCompletionHandler:nil]; 379 std::string result;
380 if (!message.GetString("result", &result)) {
381 DLOG(ERROR) << "JS message parameter 'result' is missing";
382 return NO;
383 }
384
385 void (^callback)() = ^{
386 [self dismissUI];
lpromero 2017/02/20 17:14:07 There seems to be a retain cycle. self retains _pa
Moe 2017/02/21 05:07:06 Done.
387 [_paymentRequestJsManager resolveResponsePromiseWithCompletionHandler:nil];
388 };
389
390 // Display UI indicating failure if the value of |result| is "fail".
391 if (result == "fail") {
392 [_paymentRequestCoordinator displayErrorWithCallback:callback];
393 } else {
394 callback();
395 }
353 396
354 return YES; 397 return YES;
355 } 398 }
356 399
357 - (BOOL)handleUpdatePaymentDetails:(const base::DictionaryValue&)message { 400 - (BOOL)handleUpdatePaymentDetails:(const base::DictionaryValue&)message {
358 // TODO(crbug.com/602666): Check that there is already a pending request. 401 // TODO(crbug.com/602666): Check that there is already a pending request.
359 402
360 [_unblockEventQueueTimer invalidate]; 403 [_unblockEventQueueTimer invalidate];
361 404
362 const base::DictionaryValue* paymentDetailsData = nullptr; 405 const base::DictionaryValue* paymentDetailsData = nullptr;
(...skipping 23 matching lines...) Expand all
386 429
387 - (void)setPaymentResponseTimeoutTimer { 430 - (void)setPaymentResponseTimeoutTimer {
388 _paymentResponseTimeoutTimer.reset( 431 _paymentResponseTimeoutTimer.reset(
389 [[NSTimer scheduledTimerWithTimeInterval:kTimeoutInterval 432 [[NSTimer scheduledTimerWithTimeInterval:kTimeoutInterval
390 target:self 433 target:self
391 selector:@selector(handleResponseComplete) 434 selector:@selector(handleResponseComplete)
392 userInfo:nil 435 userInfo:nil
393 repeats:NO] retain]); 436 repeats:NO] retain]);
394 } 437 }
395 438
439 - (void)setUpdateEventTimeoutTimer {
440 _updateEventTimeoutTimer.reset(
441 [[NSTimer scheduledTimerWithTimeInterval:kTimeoutInterval
442 target:self
443 selector:@selector(handleRequestCancel)
444 userInfo:nil
445 repeats:NO] retain]);
446 }
447
396 - (void)dismissUI { 448 - (void)dismissUI {
397 [_paymentRequestCoordinator stop]; 449 [_paymentRequestCoordinator stop];
398 _paymentRequestCoordinator.reset(); 450 _paymentRequestCoordinator.reset();
399 } 451 }
400 452
401 - (BOOL)webStateContentIsSecureHTML { 453 - (BOOL)webStateContentIsSecureHTML {
402 if (![self webState]) { 454 if (![self webState]) {
403 return NO; 455 return NO;
404 } 456 }
405 457
406 if (!web::UrlHasWebScheme([self webState]->GetLastCommittedURL()) || 458 if (!web::UrlHasWebScheme([self webState]->GetLastCommittedURL()) ||
407 ![self webState]->ContentIsHTML()) { 459 ![self webState]->ContentIsHTML()) {
408 return NO; 460 return NO;
409 } 461 }
410 462
411 const web::NavigationItem* navigationItem = 463 const web::NavigationItem* navigationItem =
412 [self webState]->GetNavigationManager()->GetLastCommittedItem(); 464 [self webState]->GetNavigationManager()->GetLastCommittedItem();
413 return navigationItem && 465 return navigationItem &&
414 navigationItem->GetSSL().security_style == 466 navigationItem->GetSSL().security_style ==
415 web::SECURITY_STYLE_AUTHENTICATED; 467 web::SECURITY_STYLE_AUTHENTICATED;
416 } 468 }
417 469
418 #pragma mark - PaymentRequestCoordinatorDelegate methods 470 #pragma mark - PaymentRequestCoordinatorDelegate methods
419 471
420 - (void)paymentRequestCoordinatorDidCancel: 472 - (void)paymentRequestCoordinatorDidCancel:
421 (PaymentRequestCoordinator*)coordinator { 473 (PaymentRequestCoordinator*)coordinator {
422 [self cancelRequestWithErrorMessage:@"Request canceled by user."]; 474 [self cancelRequestWithErrorMessage:@"Request canceled."];
423 } 475 }
424 476
425 - (void)paymentRequestCoordinator:(PaymentRequestCoordinator*)coordinator 477 - (void)paymentRequestCoordinator:(PaymentRequestCoordinator*)coordinator
426 didConfirmWithPaymentResponse:(web::PaymentResponse)paymentResponse { 478 didConfirmWithPaymentResponse:(web::PaymentResponse)paymentResponse {
427 [_paymentRequestJsManager 479 [_paymentRequestJsManager
428 resolveRequestPromiseWithPaymentResponse:paymentResponse 480 resolveRequestPromiseWithPaymentResponse:paymentResponse
429 completionHandler:nil]; 481 completionHandler:nil];
430 [self setUnblockEventQueueTimer]; 482 [self setUnblockEventQueueTimer];
431 [self setPaymentResponseTimeoutTimer]; 483 [self setPaymentResponseTimeoutTimer];
432 } 484 }
433 485
434 - (void)paymentRequestCoordinator:(PaymentRequestCoordinator*)coordinator 486 - (void)paymentRequestCoordinator:(PaymentRequestCoordinator*)coordinator
435 didSelectShippingAddress:(web::PaymentAddress)shippingAddress { 487 didSelectShippingAddress:(web::PaymentAddress)shippingAddress {
436 [_paymentRequestJsManager updateShippingAddress:shippingAddress 488 [_paymentRequestJsManager updateShippingAddress:shippingAddress
437 completionHandler:nil]; 489 completionHandler:nil];
438 [self setUnblockEventQueueTimer]; 490 [self setUnblockEventQueueTimer];
491 [self setUpdateEventTimeoutTimer];
439 } 492 }
440 493
441 - (void)paymentRequestCoordinator:(PaymentRequestCoordinator*)coordinator 494 - (void)paymentRequestCoordinator:(PaymentRequestCoordinator*)coordinator
442 didSelectShippingOption:(web::PaymentShippingOption)shippingOption { 495 didSelectShippingOption:(web::PaymentShippingOption)shippingOption {
443 [_paymentRequestJsManager updateShippingOption:shippingOption 496 [_paymentRequestJsManager updateShippingOption:shippingOption
444 completionHandler:nil]; 497 completionHandler:nil];
445 [self setUnblockEventQueueTimer]; 498 [self setUnblockEventQueueTimer];
499 [self setUpdateEventTimeoutTimer];
446 } 500 }
447 501
448 #pragma mark - CRWWebStateObserver methods 502 #pragma mark - CRWWebStateObserver methods
449 503
450 - (void)webState:(web::WebState*)webState 504 - (void)webState:(web::WebState*)webState
451 didCommitNavigationWithDetails: 505 didCommitNavigationWithDetails:
452 (const web::LoadCommittedDetails&)load_details { 506 (const web::LoadCommittedDetails&)load_details {
453 [self dismissUI]; 507 [self dismissUI];
454 _isScriptInjected = NO; 508 _isScriptInjected = NO;
455 [self enableCurrentWebState]; 509 [self enableCurrentWebState];
456 [self initializeWebViewForPaymentRequest]; 510 [self initializeWebViewForPaymentRequest];
457 } 511 }
458 512
459 @end 513 @end
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698