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

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

Issue 2701923003: [Payment Request] Error message screen (Closed)
Patch Set: Addressed comments 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.
lpromero 2017/02/21 16:51:08 Should "call" be removed?
Moe 2017/02/21 22:56:15 Done.
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 "unknown"
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 base::WeakNSObject<PaymentRequestManager> weakSelf(self);
356 void (^callback)() = ^{
357 base::scoped_nsobject<PaymentRequestManager> strongSelf([weakSelf retain]);
358 [strongSelf cancelRequestWithErrorMessage:@"Request canceled."];
359 };
360
361 [_paymentRequestCoordinator displayErrorWithCallback:callback];
339 362
340 return YES; 363 return YES;
341 } 364 }
342 365
343 - (BOOL)handleResponseComplete { 366 - (BOOL)handleResponseComplete {
367 base::DictionaryValue command;
368 command.SetString("result", "unknown");
369 return [self handleResponseComplete:command];
370 }
371
372 - (BOOL)handleResponseComplete:(const base::DictionaryValue&)message {
344 // TODO(crbug.com/602666): Check that there *is* a pending response here. 373 // 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 374
347 [_unblockEventQueueTimer invalidate]; 375 [_unblockEventQueueTimer invalidate];
348 [_paymentResponseTimeoutTimer invalidate]; 376 [_paymentResponseTimeoutTimer invalidate];
377 [_updateEventTimeoutTimer invalidate];
349 378
350 [self dismissUI]; 379 [_unblockEventQueueTimer invalidate];
351 380
352 [_paymentRequestJsManager resolveResponsePromiseWithCompletionHandler:nil]; 381 std::string result;
382 if (!message.GetString("result", &result)) {
383 DLOG(ERROR) << "JS message parameter 'result' is missing";
384 return NO;
385 }
386
387 base::WeakNSObject<PaymentRequestManager> weakSelf(self);
388 void (^callback)() = ^{
389 base::scoped_nsobject<PaymentRequestManager> strongSelf([weakSelf retain]);
390 [strongSelf dismissUI];
391 [_paymentRequestJsManager resolveResponsePromiseWithCompletionHandler:nil];
392 };
393
394 // Display UI indicating failure if the value of |result| is "fail".
395 if (result == "fail") {
396 [_paymentRequestCoordinator displayErrorWithCallback:callback];
397 } else {
398 callback();
399 }
353 400
354 return YES; 401 return YES;
355 } 402 }
356 403
357 - (BOOL)handleUpdatePaymentDetails:(const base::DictionaryValue&)message { 404 - (BOOL)handleUpdatePaymentDetails:(const base::DictionaryValue&)message {
358 // TODO(crbug.com/602666): Check that there is already a pending request. 405 // TODO(crbug.com/602666): Check that there is already a pending request.
359 406
360 [_unblockEventQueueTimer invalidate]; 407 [_unblockEventQueueTimer invalidate];
361 408
362 const base::DictionaryValue* paymentDetailsData = nullptr; 409 const base::DictionaryValue* paymentDetailsData = nullptr;
(...skipping 23 matching lines...) Expand all
386 433
387 - (void)setPaymentResponseTimeoutTimer { 434 - (void)setPaymentResponseTimeoutTimer {
388 _paymentResponseTimeoutTimer.reset( 435 _paymentResponseTimeoutTimer.reset(
389 [[NSTimer scheduledTimerWithTimeInterval:kTimeoutInterval 436 [[NSTimer scheduledTimerWithTimeInterval:kTimeoutInterval
390 target:self 437 target:self
391 selector:@selector(handleResponseComplete) 438 selector:@selector(handleResponseComplete)
392 userInfo:nil 439 userInfo:nil
393 repeats:NO] retain]); 440 repeats:NO] retain]);
394 } 441 }
395 442
443 - (void)setUpdateEventTimeoutTimer {
444 _updateEventTimeoutTimer.reset(
445 [[NSTimer scheduledTimerWithTimeInterval:kTimeoutInterval
446 target:self
447 selector:@selector(handleRequestCancel)
448 userInfo:nil
449 repeats:NO] retain]);
450 }
451
396 - (void)dismissUI { 452 - (void)dismissUI {
397 [_paymentRequestCoordinator stop]; 453 [_paymentRequestCoordinator stop];
398 _paymentRequestCoordinator.reset(); 454 _paymentRequestCoordinator.reset();
399 } 455 }
400 456
401 - (BOOL)webStateContentIsSecureHTML { 457 - (BOOL)webStateContentIsSecureHTML {
402 if (![self webState]) { 458 if (![self webState]) {
403 return NO; 459 return NO;
404 } 460 }
405 461
406 if (!web::UrlHasWebScheme([self webState]->GetLastCommittedURL()) || 462 if (!web::UrlHasWebScheme([self webState]->GetLastCommittedURL()) ||
407 ![self webState]->ContentIsHTML()) { 463 ![self webState]->ContentIsHTML()) {
408 return NO; 464 return NO;
409 } 465 }
410 466
411 const web::NavigationItem* navigationItem = 467 const web::NavigationItem* navigationItem =
412 [self webState]->GetNavigationManager()->GetLastCommittedItem(); 468 [self webState]->GetNavigationManager()->GetLastCommittedItem();
413 return navigationItem && 469 return navigationItem &&
414 navigationItem->GetSSL().security_style == 470 navigationItem->GetSSL().security_style ==
415 web::SECURITY_STYLE_AUTHENTICATED; 471 web::SECURITY_STYLE_AUTHENTICATED;
416 } 472 }
417 473
418 #pragma mark - PaymentRequestCoordinatorDelegate methods 474 #pragma mark - PaymentRequestCoordinatorDelegate methods
419 475
420 - (void)paymentRequestCoordinatorDidCancel: 476 - (void)paymentRequestCoordinatorDidCancel:
421 (PaymentRequestCoordinator*)coordinator { 477 (PaymentRequestCoordinator*)coordinator {
422 [self cancelRequestWithErrorMessage:@"Request canceled by user."]; 478 [self cancelRequestWithErrorMessage:@"Request canceled."];
423 } 479 }
424 480
425 - (void)paymentRequestCoordinator:(PaymentRequestCoordinator*)coordinator 481 - (void)paymentRequestCoordinator:(PaymentRequestCoordinator*)coordinator
426 didConfirmWithPaymentResponse:(web::PaymentResponse)paymentResponse { 482 didConfirmWithPaymentResponse:(web::PaymentResponse)paymentResponse {
427 [_paymentRequestJsManager 483 [_paymentRequestJsManager
428 resolveRequestPromiseWithPaymentResponse:paymentResponse 484 resolveRequestPromiseWithPaymentResponse:paymentResponse
429 completionHandler:nil]; 485 completionHandler:nil];
430 [self setUnblockEventQueueTimer]; 486 [self setUnblockEventQueueTimer];
431 [self setPaymentResponseTimeoutTimer]; 487 [self setPaymentResponseTimeoutTimer];
432 } 488 }
433 489
434 - (void)paymentRequestCoordinator:(PaymentRequestCoordinator*)coordinator 490 - (void)paymentRequestCoordinator:(PaymentRequestCoordinator*)coordinator
435 didSelectShippingAddress:(web::PaymentAddress)shippingAddress { 491 didSelectShippingAddress:(web::PaymentAddress)shippingAddress {
436 [_paymentRequestJsManager updateShippingAddress:shippingAddress 492 [_paymentRequestJsManager updateShippingAddress:shippingAddress
437 completionHandler:nil]; 493 completionHandler:nil];
438 [self setUnblockEventQueueTimer]; 494 [self setUnblockEventQueueTimer];
495 [self setUpdateEventTimeoutTimer];
439 } 496 }
440 497
441 - (void)paymentRequestCoordinator:(PaymentRequestCoordinator*)coordinator 498 - (void)paymentRequestCoordinator:(PaymentRequestCoordinator*)coordinator
442 didSelectShippingOption:(web::PaymentShippingOption)shippingOption { 499 didSelectShippingOption:(web::PaymentShippingOption)shippingOption {
443 [_paymentRequestJsManager updateShippingOption:shippingOption 500 [_paymentRequestJsManager updateShippingOption:shippingOption
444 completionHandler:nil]; 501 completionHandler:nil];
445 [self setUnblockEventQueueTimer]; 502 [self setUnblockEventQueueTimer];
503 [self setUpdateEventTimeoutTimer];
446 } 504 }
447 505
448 #pragma mark - CRWWebStateObserver methods 506 #pragma mark - CRWWebStateObserver methods
449 507
450 - (void)webState:(web::WebState*)webState 508 - (void)webState:(web::WebState*)webState
451 didCommitNavigationWithDetails: 509 didCommitNavigationWithDetails:
452 (const web::LoadCommittedDetails&)load_details { 510 (const web::LoadCommittedDetails&)load_details {
453 [self dismissUI]; 511 [self dismissUI];
454 _isScriptInjected = NO; 512 _isScriptInjected = NO;
455 [self enableCurrentWebState]; 513 [self enableCurrentWebState];
456 [self initializeWebViewForPaymentRequest]; 514 [self initializeWebViewForPaymentRequest];
457 } 515 }
458 516
459 @end 517 @end
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698