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

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

Issue 2701923003: [Payment Request] Error message screen (Closed)
Patch Set: ARCified 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/block_types.h"
7 #include "base/ios/ios_util.h" 8 #include "base/ios/ios_util.h"
8 #import "base/mac/bind_objc_block.h" 9 #import "base/mac/bind_objc_block.h"
9 #include "base/mac/foundation_util.h" 10 #include "base/mac/foundation_util.h"
10 #include "base/memory/ptr_util.h" 11 #include "base/memory/ptr_util.h"
11 #include "base/strings/sys_string_conversions.h" 12 #include "base/strings/sys_string_conversions.h"
12 #import "base/values.h" 13 #import "base/values.h"
13 #include "components/autofill/core/browser/autofill_manager.h" 14 #include "components/autofill/core/browser/autofill_manager.h"
14 #include "components/autofill/core/browser/personal_data_manager.h" 15 #include "components/autofill/core/browser/personal_data_manager.h"
15 #include "components/autofill/ios/browser/autofill_driver_ios.h" 16 #include "components/autofill/ios/browser/autofill_driver_ios.h"
16 #include "ios/chrome/browser/autofill/personal_data_manager_factory.h" 17 #include "ios/chrome/browser/autofill/personal_data_manager_factory.h"
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after
81 // True when close has been called and the PaymentRequest coordinator has 82 // True when close has been called and the PaymentRequest coordinator has
82 // been destroyed. 83 // been destroyed.
83 BOOL _closed; 84 BOOL _closed;
84 85
85 // Coordinator used to create and present the PaymentRequest view controller. 86 // Coordinator used to create and present the PaymentRequest view controller.
86 PaymentRequestCoordinator* _paymentRequestCoordinator; 87 PaymentRequestCoordinator* _paymentRequestCoordinator;
87 88
88 // Timer used to periodically unblock the webview's JS event queue. 89 // Timer used to periodically unblock the webview's JS event queue.
89 NSTimer* _unblockEventQueueTimer; 90 NSTimer* _unblockEventQueueTimer;
90 91
91 // Timer used to close the UI if the page does not call 92 // Timer used to complete the Payment Request flow and close the UI if the
92 // PaymentResponse.complete() in a timely fashion. 93 // page does not call PaymentResponse.complete() in a timely fashion.
93 NSTimer* _paymentResponseTimeoutTimer; 94 NSTimer* _paymentResponseTimeoutTimer;
95
96 // Timer used to cancel the Payment Request flow and close the UI if the
97 // page does not settle the pending update promise in a timely fashion.
98 NSTimer* _updateEventTimeoutTimer;
94 } 99 }
95 100
96 // Synchronous method executed by -asynchronouslyEnablePaymentRequest: 101 // Synchronous method executed by -asynchronouslyEnablePaymentRequest:
97 - (void)doEnablePaymentRequest:(BOOL)enabled; 102 - (void)doEnablePaymentRequest:(BOOL)enabled;
98 103
99 // Initialize the PaymentRequest JavaScript. 104 // Initialize the PaymentRequest JavaScript.
100 - (void)initializeWebViewForPaymentRequest; 105 - (void)initializeWebViewForPaymentRequest;
101 106
102 // Handler for injected JavaScript callbacks. 107 // Handler for injected JavaScript callbacks.
103 - (BOOL)handleScriptCommand:(const base::DictionaryValue&)JSONCommand; 108 - (BOOL)handleScriptCommand:(const base::DictionaryValue&)JSONCommand;
104 109
105 // Handles invocations of PaymentRequest.show(). The value of the JavaScript 110 // Handles invocations of PaymentRequest.show(). The value of the JavaScript
106 // PaymentRequest object should be provided in |message|. Returns YES if the 111 // PaymentRequest object should be provided in |message|. Returns YES if the
107 // invocation was successful. 112 // invocation was successful.
108 - (BOOL)handleRequestShow:(const base::DictionaryValue&)message; 113 - (BOOL)handleRequestShow:(const base::DictionaryValue&)message;
109 114
115 // Called by |_paymentResponseTimeoutTimer|, invokes handleResponseComplete:
116 // as if PaymentResponse.complete() was invoked with the default "unknown"
117 // argument.
118 - (BOOL)handleResponseComplete;
119
110 // Handles invocations of PaymentResponse.complete(). Returns YES if the 120 // Handles invocations of PaymentResponse.complete(). Returns YES if the
111 // invocation was successful. 121 // invocation was successful.
112 - (BOOL)handleResponseComplete; 122 - (BOOL)handleResponseComplete:(const base::DictionaryValue&)message;
113 123
114 // Handles invocations of PaymentRequestUpdateEvent.updateWith(). Returns YES if 124 // Handles invocations of PaymentRequestUpdateEvent.updateWith(). Returns YES if
115 // the invocation was successful. 125 // the invocation was successful.
116 - (BOOL)handleUpdatePaymentDetails:(const base::DictionaryValue&)message; 126 - (BOOL)handleUpdatePaymentDetails:(const base::DictionaryValue&)message;
117 127
118 // Establishes a timer that periodically prompts the JS manager to execute a 128 // Establishes a timer that periodically prompts the JS manager to execute a
119 // noop. This works around an issue where the JS event queue is blocked while 129 // noop. This works around an issue where the JS event queue is blocked while
120 // presenting the Payment Request UI. 130 // presenting the Payment Request UI.
121 - (void)setUnblockEventQueueTimer; 131 - (void)setUnblockEventQueueTimer;
122 132
123 // Establishes a timer that calls handleResponseComplete when it times out. Per 133 // Establishes a timer that calls handleResponseComplete when it times out. Per
124 // the spec, if the page does not call PaymentResponse.complete() within some 134 // the spec, if the page does not call PaymentResponse.complete() within some
125 // timeout period, user agents may behave as if the complete() method was 135 // timeout period, user agents may behave as if the complete() method was
126 // called with no arguments. 136 // called with no arguments.
127 - (void)setPaymentResponseTimeoutTimer; 137 - (void)setPaymentResponseTimeoutTimer;
128 138
139 // Establishes a timer that dismisses the Payment Request UI when it times out.
140 // Per the spec, implementations may choose to consider a timeout for the
141 // promise provided with the PaymentRequestUpdateEvent.updateWith() call. If the
142 // promise doesn't get settled in a reasonable amount of time, it is as if it
143 // was rejected.
144 - (void)setUpdateEventTimeoutTimer;
145
129 @end 146 @end
130 147
131 @implementation PaymentRequestManager 148 @implementation PaymentRequestManager
132 149
133 @synthesize enabled = _enabled; 150 @synthesize enabled = _enabled;
134 @synthesize webState = _webState; 151 @synthesize webState = _webState;
135 @synthesize browserState = _browserState; 152 @synthesize browserState = _browserState;
136 153
137 - (instancetype)initWithBaseViewController:(UIViewController*)viewController 154 - (instancetype)initWithBaseViewController:(UIViewController*)viewController
138 browserState: 155 browserState:
(...skipping 129 matching lines...) Expand 10 before | Expand all | Expand 10 after
268 return NO; 285 return NO;
269 } 286 }
270 287
271 if (command == "paymentRequest.requestShow") { 288 if (command == "paymentRequest.requestShow") {
272 return [self handleRequestShow:JSONCommand]; 289 return [self handleRequestShow:JSONCommand];
273 } 290 }
274 if (command == "paymentRequest.requestCancel") { 291 if (command == "paymentRequest.requestCancel") {
275 return [self handleRequestCancel]; 292 return [self handleRequestCancel];
276 } 293 }
277 if (command == "paymentRequest.responseComplete") { 294 if (command == "paymentRequest.responseComplete") {
278 return [self handleResponseComplete]; 295 return [self handleResponseComplete:JSONCommand];
279 } 296 }
280 if (command == "paymentRequest.updatePaymentDetails") { 297 if (command == "paymentRequest.updatePaymentDetails") {
281 return [self handleUpdatePaymentDetails:JSONCommand]; 298 return [self handleUpdatePaymentDetails:JSONCommand];
282 } 299 }
283 return NO; 300 return NO;
284 } 301 }
285 302
286 - (BOOL)handleRequestShow:(const base::DictionaryValue&)message { 303 - (BOOL)handleRequestShow:(const base::DictionaryValue&)message {
287 // TODO(crbug.com/602666): check that there's not already a pending request. 304 // 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 305 // 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]; 344 [_paymentRequestCoordinator start];
328 345
329 return YES; 346 return YES;
330 } 347 }
331 348
332 - (BOOL)handleRequestCancel { 349 - (BOOL)handleRequestCancel {
333 // TODO(crbug.com/602666): Check that there is already a pending request. 350 // TODO(crbug.com/602666): Check that there is already a pending request.
334 351
335 [_unblockEventQueueTimer invalidate]; 352 [_unblockEventQueueTimer invalidate];
336 [_paymentResponseTimeoutTimer invalidate]; 353 [_paymentResponseTimeoutTimer invalidate];
354 [_updateEventTimeoutTimer invalidate];
337 355
338 [self cancelRequestWithErrorMessage:@"Request canceled by the page."]; 356 __weak PaymentRequestManager* weakSelf = self;
357 ProceduralBlock callback = ^{
358 PaymentRequestManager* strongSelf = weakSelf;
359 [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
360 };
361
362 [_paymentRequestCoordinator displayErrorWithCallback:callback];
339 363
340 return YES; 364 return YES;
341 } 365 }
342 366
343 - (BOOL)handleResponseComplete { 367 - (BOOL)handleResponseComplete {
368 base::DictionaryValue command;
369 command.SetString("result", "unknown");
370 return [self handleResponseComplete:command];
371 }
372
373 - (BOOL)handleResponseComplete:(const base::DictionaryValue&)message {
344 // TODO(crbug.com/602666): Check that there *is* a pending response here. 374 // 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 375
347 [_unblockEventQueueTimer invalidate]; 376 [_unblockEventQueueTimer invalidate];
348 [_paymentResponseTimeoutTimer invalidate]; 377 [_paymentResponseTimeoutTimer invalidate];
378 [_updateEventTimeoutTimer invalidate];
349 379
350 [self dismissUI]; 380 std::string result;
381 if (!message.GetString("result", &result)) {
382 DLOG(ERROR) << "JS message parameter 'result' is missing";
383 return NO;
384 }
351 385
352 [_paymentRequestJsManager resolveResponsePromiseWithCompletionHandler:nil]; 386 __weak PaymentRequestManager* weakSelf = self;
387 ProceduralBlock callback = ^{
388 PaymentRequestManager* strongSelf = weakSelf;
lpromero 2017/02/23 09:17:41 Add early return if strongSelf == nil.
Moe 2017/02/23 14:44:01 Done.
389 [strongSelf dismissUI];
390 [_paymentRequestJsManager resolveResponsePromiseWithCompletionHandler:nil];
lpromero 2017/02/23 09:17:41 strongSelf->_paymentRequestJsManager, otherwise yo
Moe 2017/02/23 14:44:01 Done!
391 };
392
393 // Display UI indicating failure if the value of |result| is "fail".
394 if (result == "fail") {
395 [_paymentRequestCoordinator displayErrorWithCallback:callback];
396 } else {
397 callback();
398 }
353 399
354 return YES; 400 return YES;
355 } 401 }
356 402
357 - (BOOL)handleUpdatePaymentDetails:(const base::DictionaryValue&)message { 403 - (BOOL)handleUpdatePaymentDetails:(const base::DictionaryValue&)message {
358 // TODO(crbug.com/602666): Check that there is already a pending request. 404 // TODO(crbug.com/602666): Check that there is already a pending request.
359 405
360 [_unblockEventQueueTimer invalidate]; 406 [_unblockEventQueueTimer invalidate];
407 [_updateEventTimeoutTimer invalidate];
361 408
362 const base::DictionaryValue* paymentDetailsData = nullptr; 409 const base::DictionaryValue* paymentDetailsData = nullptr;
363 web::PaymentDetails paymentDetails; 410 web::PaymentDetails paymentDetails;
364 if (!message.GetDictionary("payment_details", &paymentDetailsData)) { 411 if (!message.GetDictionary("payment_details", &paymentDetailsData)) {
365 DLOG(ERROR) << "JS message parameter 'payment_details' is missing"; 412 DLOG(ERROR) << "JS message parameter 'payment_details' is missing";
366 return NO; 413 return NO;
367 } 414 }
368 if (!paymentDetails.FromDictionaryValue(*paymentDetailsData)) { 415 if (!paymentDetails.FromDictionaryValue(*paymentDetailsData)) {
369 DLOG(ERROR) << "JS message parameter 'payment_details' is invalid"; 416 DLOG(ERROR) << "JS message parameter 'payment_details' is invalid";
370 return NO; 417 return NO;
(...skipping 15 matching lines...) Expand all
386 433
387 - (void)setPaymentResponseTimeoutTimer { 434 - (void)setPaymentResponseTimeoutTimer {
388 _paymentResponseTimeoutTimer = 435 _paymentResponseTimeoutTimer =
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]; 440 repeats:NO];
394 } 441 }
395 442
443 - (void)setUpdateEventTimeoutTimer {
444 _updateEventTimeoutTimer =
445 [NSTimer scheduledTimerWithTimeInterval:kTimeoutInterval
446 target:self
447 selector:@selector(handleRequestCancel)
448 userInfo:nil
449 repeats:NO];
450 }
451
396 - (void)dismissUI { 452 - (void)dismissUI {
397 [_paymentRequestCoordinator stop]; 453 [_paymentRequestCoordinator stop];
398 _paymentRequestCoordinator = nil; 454 _paymentRequestCoordinator = nil;
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