Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 |
| OLD | NEW |