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/ios_util.h" | 7 #include "base/ios/ios_util.h" |
8 #import "base/ios/weak_nsobject.h" | |
9 #import "base/mac/bind_objc_block.h" | 8 #import "base/mac/bind_objc_block.h" |
10 #include "base/mac/foundation_util.h" | 9 #include "base/mac/foundation_util.h" |
11 #include "base/mac/scoped_nsobject.h" | |
12 #include "base/memory/ptr_util.h" | 10 #include "base/memory/ptr_util.h" |
13 #include "base/strings/sys_string_conversions.h" | 11 #include "base/strings/sys_string_conversions.h" |
14 #import "base/values.h" | 12 #import "base/values.h" |
15 #include "components/autofill/core/browser/autofill_manager.h" | 13 #include "components/autofill/core/browser/autofill_manager.h" |
16 #include "components/autofill/core/browser/personal_data_manager.h" | 14 #include "components/autofill/core/browser/personal_data_manager.h" |
17 #include "components/autofill/ios/browser/autofill_driver_ios.h" | 15 #include "components/autofill/ios/browser/autofill_driver_ios.h" |
18 #include "ios/chrome/browser/autofill/personal_data_manager_factory.h" | 16 #include "ios/chrome/browser/autofill/personal_data_manager_factory.h" |
19 #include "ios/chrome/browser/browser_state/chrome_browser_state.h" | 17 #include "ios/chrome/browser/browser_state/chrome_browser_state.h" |
20 #import "ios/chrome/browser/payments/js_payment_request_manager.h" | 18 #import "ios/chrome/browser/payments/js_payment_request_manager.h" |
21 #include "ios/chrome/browser/payments/payment_request.h" | 19 #include "ios/chrome/browser/payments/payment_request.h" |
22 #import "ios/chrome/browser/payments/payment_request_coordinator.h" | 20 #import "ios/chrome/browser/payments/payment_request_coordinator.h" |
23 #include "ios/web/public/favicon_status.h" | 21 #include "ios/web/public/favicon_status.h" |
24 #include "ios/web/public/navigation_item.h" | 22 #include "ios/web/public/navigation_item.h" |
25 #include "ios/web/public/navigation_manager.h" | 23 #include "ios/web/public/navigation_manager.h" |
26 #include "ios/web/public/payments/payment_request.h" | 24 #include "ios/web/public/payments/payment_request.h" |
27 #include "ios/web/public/ssl_status.h" | 25 #include "ios/web/public/ssl_status.h" |
28 #import "ios/web/public/url_scheme_util.h" | 26 #import "ios/web/public/url_scheme_util.h" |
29 #import "ios/web/public/web_state/crw_web_view_proxy.h" | 27 #import "ios/web/public/web_state/crw_web_view_proxy.h" |
30 #import "ios/web/public/web_state/js/crw_js_injection_receiver.h" | 28 #import "ios/web/public/web_state/js/crw_js_injection_receiver.h" |
31 #include "ios/web/public/web_state/url_verification_constants.h" | 29 #include "ios/web/public/web_state/url_verification_constants.h" |
32 #include "ios/web/public/web_state/web_state.h" | 30 #include "ios/web/public/web_state/web_state.h" |
33 #import "ios/web/public/web_state/web_state_observer_bridge.h" | 31 #import "ios/web/public/web_state/web_state_observer_bridge.h" |
34 | 32 |
| 33 #if !defined(__has_feature) || !__has_feature(objc_arc) |
| 34 #error "This file requires ARC support." |
| 35 #endif |
| 36 |
35 namespace { | 37 namespace { |
36 // Command prefix for injected JavaScript. | 38 // Command prefix for injected JavaScript. |
37 const std::string kCommandPrefix = "paymentRequest"; | 39 const std::string kCommandPrefix = "paymentRequest"; |
38 | 40 |
39 // Time interval between attempts to unblock the webview's JS event queue. | 41 // Time interval between attempts to unblock the webview's JS event queue. |
40 const NSTimeInterval kNoopInterval = 0.1; | 42 const NSTimeInterval kNoopInterval = 0.1; |
41 | 43 |
42 // Time interval before closing the UI if the page has not yet called | 44 // Time interval before closing the UI if the page has not yet called |
43 // PaymentResponse.complete(). | 45 // PaymentResponse.complete(). |
44 const NSTimeInterval kTimeoutInterval = 60.0; | 46 const NSTimeInterval kTimeoutInterval = 60.0; |
45 | 47 |
46 } // namespace | 48 } // namespace |
47 | 49 |
48 @interface PaymentRequestManager ()<CRWWebStateObserver, | 50 @interface PaymentRequestManager ()<CRWWebStateObserver, |
49 PaymentRequestCoordinatorDelegate> { | 51 PaymentRequestCoordinatorDelegate> { |
50 // View controller used to present the PaymentRequest view controller. | 52 // View controller used to present the PaymentRequest view controller. |
51 base::WeakNSObject<UIViewController> _baseViewController; | 53 __weak UIViewController* _baseViewController; |
52 | 54 |
53 // PersonalDataManager used to manage user credit cards and addresses. | 55 // PersonalDataManager used to manage user credit cards and addresses. |
54 autofill::PersonalDataManager* _personalDataManager; | 56 autofill::PersonalDataManager* _personalDataManager; |
55 | 57 |
56 // Object that owns an instance of web::PaymentRequest as provided by the page | 58 // Object that owns an instance of web::PaymentRequest as provided by the page |
57 // invoking the PaymentRequest API. Also caches credit cards and addresses | 59 // invoking the PaymentRequest API. Also caches credit cards and addresses |
58 // provided by the _personalDataManager and manages selected ones for the | 60 // provided by the _personalDataManager and manages selected ones for the |
59 // current PaymentRequest flow. | 61 // current PaymentRequest flow. |
60 std::unique_ptr<PaymentRequest> _paymentRequest; | 62 std::unique_ptr<PaymentRequest> _paymentRequest; |
61 | 63 |
62 // WebState for the tab this object is attached to. | 64 // WebState for the tab this object is attached to. |
63 web::WebState* _webState; | 65 web::WebState* _webState; |
64 | 66 |
65 // Observer for |_webState|. | 67 // Observer for |_webState|. |
66 std::unique_ptr<web::WebStateObserverBridge> _webStateObserver; | 68 std::unique_ptr<web::WebStateObserverBridge> _webStateObserver; |
67 | 69 |
68 // Object that manages JavaScript injection into the web view. | 70 // Object that manages JavaScript injection into the web view. |
69 base::WeakNSObject<JSPaymentRequestManager> _paymentRequestJsManager; | 71 __weak JSPaymentRequestManager* _paymentRequestJsManager; |
70 | 72 |
71 // Boolean to track if the current WebState is enabled (JS callback is set | 73 // Boolean to track if the current WebState is enabled (JS callback is set |
72 // up). | 74 // up). |
73 BOOL _webStateEnabled; | 75 BOOL _webStateEnabled; |
74 | 76 |
75 // Boolean to track if the script has been injected in the current page. This | 77 // Boolean to track if the script has been injected in the current page. This |
76 // is a faster check than asking the JS controller. | 78 // is a faster check than asking the JS controller. |
77 BOOL _isScriptInjected; | 79 BOOL _isScriptInjected; |
78 | 80 |
79 // True when close has been called and the PaymentRequest coordinator has | 81 // True when close has been called and the PaymentRequest coordinator has |
80 // been destroyed. | 82 // been destroyed. |
81 BOOL _closed; | 83 BOOL _closed; |
82 | 84 |
83 // Coordinator used to create and present the PaymentRequest view controller. | 85 // Coordinator used to create and present the PaymentRequest view controller. |
84 base::scoped_nsobject<PaymentRequestCoordinator> _paymentRequestCoordinator; | 86 PaymentRequestCoordinator* _paymentRequestCoordinator; |
85 | 87 |
86 // Timer used to periodically unblock the webview's JS event queue. | 88 // Timer used to periodically unblock the webview's JS event queue. |
87 base::scoped_nsobject<NSTimer> _unblockEventQueueTimer; | 89 NSTimer* _unblockEventQueueTimer; |
88 | 90 |
89 // Timer used to close the UI if the page does not call | 91 // Timer used to close the UI if the page does not call |
90 // PaymentResponse.complete() in a timely fashion. | 92 // PaymentResponse.complete() in a timely fashion. |
91 base::scoped_nsobject<NSTimer> _paymentResponseTimeoutTimer; | 93 NSTimer* _paymentResponseTimeoutTimer; |
92 } | 94 } |
93 | 95 |
94 // Synchronous method executed by -asynchronouslyEnablePaymentRequest: | 96 // Synchronous method executed by -asynchronouslyEnablePaymentRequest: |
95 - (void)doEnablePaymentRequest:(BOOL)enabled; | 97 - (void)doEnablePaymentRequest:(BOOL)enabled; |
96 | 98 |
97 // Initialize the PaymentRequest JavaScript. | 99 // Initialize the PaymentRequest JavaScript. |
98 - (void)initializeWebViewForPaymentRequest; | 100 - (void)initializeWebViewForPaymentRequest; |
99 | 101 |
100 // Handler for injected JavaScript callbacks. | 102 // Handler for injected JavaScript callbacks. |
101 - (BOOL)handleScriptCommand:(const base::DictionaryValue&)JSONCommand; | 103 - (BOOL)handleScriptCommand:(const base::DictionaryValue&)JSONCommand; |
(...skipping 27 matching lines...) Expand all Loading... |
129 @implementation PaymentRequestManager | 131 @implementation PaymentRequestManager |
130 | 132 |
131 @synthesize enabled = _enabled; | 133 @synthesize enabled = _enabled; |
132 @synthesize webState = _webState; | 134 @synthesize webState = _webState; |
133 @synthesize browserState = _browserState; | 135 @synthesize browserState = _browserState; |
134 | 136 |
135 - (instancetype)initWithBaseViewController:(UIViewController*)viewController | 137 - (instancetype)initWithBaseViewController:(UIViewController*)viewController |
136 browserState: | 138 browserState: |
137 (ios::ChromeBrowserState*)browserState { | 139 (ios::ChromeBrowserState*)browserState { |
138 if ((self = [super init])) { | 140 if ((self = [super init])) { |
139 _baseViewController.reset(viewController); | 141 _baseViewController = viewController; |
140 | 142 |
141 _browserState = browserState; | 143 _browserState = browserState; |
142 | 144 |
143 _personalDataManager = | 145 _personalDataManager = |
144 autofill::PersonalDataManagerFactory::GetForBrowserState( | 146 autofill::PersonalDataManagerFactory::GetForBrowserState( |
145 browserState->GetOriginalChromeBrowserState()); | 147 browserState->GetOriginalChromeBrowserState()); |
146 } | 148 } |
147 return self; | 149 return self; |
148 } | 150 } |
149 | 151 |
150 - (instancetype)init { | 152 - (instancetype)init { |
151 NOTREACHED(); | 153 NOTREACHED(); |
152 return nil; | 154 return nil; |
153 } | 155 } |
154 | 156 |
155 - (void)setWebState:(web::WebState*)webState { | 157 - (void)setWebState:(web::WebState*)webState { |
156 [self disconnectWebState]; | 158 [self disconnectWebState]; |
157 if (webState) { | 159 if (webState) { |
158 _paymentRequestJsManager.reset( | 160 _paymentRequestJsManager = |
159 base::mac::ObjCCastStrict<JSPaymentRequestManager>( | 161 base::mac::ObjCCastStrict<JSPaymentRequestManager>( |
160 [webState->GetJSInjectionReceiver() | 162 [webState->GetJSInjectionReceiver() |
161 instanceOfClass:[JSPaymentRequestManager class]])); | 163 instanceOfClass:[JSPaymentRequestManager class]]); |
162 _webState = webState; | 164 _webState = webState; |
163 _webStateObserver.reset(new web::WebStateObserverBridge(webState, self)); | 165 _webStateObserver.reset(new web::WebStateObserverBridge(webState, self)); |
164 [self enableCurrentWebState]; | 166 [self enableCurrentWebState]; |
165 } else { | 167 } else { |
166 _webState = nullptr; | 168 _webState = nullptr; |
167 } | 169 } |
168 } | 170 } |
169 | 171 |
170 - (void)enablePaymentRequest:(BOOL)enabled { | 172 - (void)enablePaymentRequest:(BOOL)enabled { |
171 // Asynchronously enables PaymentRequest, so that some preferences | 173 // Asynchronously enables PaymentRequest, so that some preferences |
172 // (UIAccessibilityIsVoiceOverRunning(), for example) have time to synchronize | 174 // (UIAccessibilityIsVoiceOverRunning(), for example) have time to synchronize |
173 // with their own notifications. | 175 // with their own notifications. |
174 base::WeakNSObject<PaymentRequestManager> weakSelf(self); | 176 __weak PaymentRequestManager* weakSelf = self; |
175 dispatch_async(dispatch_get_main_queue(), ^{ | 177 dispatch_async(dispatch_get_main_queue(), ^{ |
176 [weakSelf doEnablePaymentRequest:enabled]; | 178 [weakSelf doEnablePaymentRequest:enabled]; |
177 }); | 179 }); |
178 } | 180 } |
179 | 181 |
180 - (void)doEnablePaymentRequest:(BOOL)enabled { | 182 - (void)doEnablePaymentRequest:(BOOL)enabled { |
181 BOOL changing = _enabled != enabled; | 183 BOOL changing = _enabled != enabled; |
182 if (changing) { | 184 if (changing) { |
183 if (!enabled) { | 185 if (!enabled) { |
184 [self dismissUI]; | 186 [self dismissUI]; |
(...skipping 23 matching lines...) Expand all Loading... |
208 [self dismissUI]; | 210 [self dismissUI]; |
209 } | 211 } |
210 | 212 |
211 - (void)enableCurrentWebState { | 213 - (void)enableCurrentWebState { |
212 if (![self webState]) { | 214 if (![self webState]) { |
213 return; | 215 return; |
214 } | 216 } |
215 | 217 |
216 if (_enabled) { | 218 if (_enabled) { |
217 if (!_webStateEnabled) { | 219 if (!_webStateEnabled) { |
218 base::WeakNSObject<PaymentRequestManager> weakSelf(self); | 220 __weak PaymentRequestManager* weakSelf = self; |
219 auto callback = | 221 auto callback = base::BindBlockArc( |
220 base::BindBlock(^bool(const base::DictionaryValue& JSON, | 222 ^bool(const base::DictionaryValue& JSON, const GURL& originURL, |
221 const GURL& originURL, bool userIsInteracting) { | 223 bool userIsInteracting) { |
222 base::scoped_nsobject<PaymentRequestManager> strongSelf( | |
223 [weakSelf retain]); | |
224 // |originURL| and |userIsInteracting| aren't used. | 224 // |originURL| and |userIsInteracting| aren't used. |
225 return [strongSelf handleScriptCommand:JSON]; | 225 return [weakSelf handleScriptCommand:JSON]; |
226 }); | 226 }); |
227 [self webState]->AddScriptCommandCallback(callback, kCommandPrefix); | 227 [self webState]->AddScriptCommandCallback(callback, kCommandPrefix); |
228 | 228 |
229 _webStateEnabled = YES; | 229 _webStateEnabled = YES; |
230 } | 230 } |
231 } else { | 231 } else { |
232 [self disableCurrentWebState]; | 232 [self disableCurrentWebState]; |
233 } | 233 } |
234 } | 234 } |
235 | 235 |
236 - (void)disableCurrentWebState { | 236 - (void)disableCurrentWebState { |
237 if (_webStateEnabled) { | 237 if (_webStateEnabled) { |
238 _webState->RemoveScriptCommandCallback(kCommandPrefix); | 238 _webState->RemoveScriptCommandCallback(kCommandPrefix); |
239 _webStateEnabled = NO; | 239 _webStateEnabled = NO; |
240 } | 240 } |
241 } | 241 } |
242 | 242 |
243 - (void)disconnectWebState { | 243 - (void)disconnectWebState { |
244 if (_webState) { | 244 if (_webState) { |
245 _paymentRequestJsManager.reset(); | 245 _paymentRequestJsManager = nil; |
246 _webStateObserver.reset(); | 246 _webStateObserver.reset(); |
247 [self disableCurrentWebState]; | 247 [self disableCurrentWebState]; |
248 } | 248 } |
249 } | 249 } |
250 | 250 |
251 - (void)initializeWebViewForPaymentRequest { | 251 - (void)initializeWebViewForPaymentRequest { |
252 if (_enabled) { | 252 if (_enabled) { |
253 DCHECK(_webStateEnabled); | 253 DCHECK(_webStateEnabled); |
254 | 254 |
255 [_paymentRequestJsManager inject]; | 255 [_paymentRequestJsManager inject]; |
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
307 UIImage* pageFavicon = nil; | 307 UIImage* pageFavicon = nil; |
308 web::NavigationItem* navigationItem = | 308 web::NavigationItem* navigationItem = |
309 [self webState]->GetNavigationManager()->GetVisibleItem(); | 309 [self webState]->GetNavigationManager()->GetVisibleItem(); |
310 if (navigationItem && !navigationItem->GetFavicon().image.IsEmpty()) | 310 if (navigationItem && !navigationItem->GetFavicon().image.IsEmpty()) |
311 pageFavicon = navigationItem->GetFavicon().image.ToUIImage(); | 311 pageFavicon = navigationItem->GetFavicon().image.ToUIImage(); |
312 NSString* pageTitle = base::SysUTF16ToNSString([self webState]->GetTitle()); | 312 NSString* pageTitle = base::SysUTF16ToNSString([self webState]->GetTitle()); |
313 NSString* pageHost = | 313 NSString* pageHost = |
314 base::SysUTF8ToNSString([self webState]->GetLastCommittedURL().host()); | 314 base::SysUTF8ToNSString([self webState]->GetLastCommittedURL().host()); |
315 autofill::AutofillManager* autofillManager = | 315 autofill::AutofillManager* autofillManager = |
316 autofill::AutofillDriverIOS::FromWebState(_webState)->autofill_manager(); | 316 autofill::AutofillDriverIOS::FromWebState(_webState)->autofill_manager(); |
317 _paymentRequestCoordinator.reset([[PaymentRequestCoordinator alloc] | 317 _paymentRequestCoordinator = [[PaymentRequestCoordinator alloc] |
318 initWithBaseViewController:_baseViewController]); | 318 initWithBaseViewController:_baseViewController]; |
319 [_paymentRequestCoordinator setPaymentRequest:_paymentRequest.get()]; | 319 [_paymentRequestCoordinator setPaymentRequest:_paymentRequest.get()]; |
320 [_paymentRequestCoordinator setAutofillManager:autofillManager]; | 320 [_paymentRequestCoordinator setAutofillManager:autofillManager]; |
321 [_paymentRequestCoordinator setBrowserState:_browserState]; | 321 [_paymentRequestCoordinator setBrowserState:_browserState]; |
322 [_paymentRequestCoordinator setPageFavicon:pageFavicon]; | 322 [_paymentRequestCoordinator setPageFavicon:pageFavicon]; |
323 [_paymentRequestCoordinator setPageTitle:pageTitle]; | 323 [_paymentRequestCoordinator setPageTitle:pageTitle]; |
324 [_paymentRequestCoordinator setPageHost:pageHost]; | 324 [_paymentRequestCoordinator setPageHost:pageHost]; |
325 [_paymentRequestCoordinator setDelegate:self]; | 325 [_paymentRequestCoordinator setDelegate:self]; |
326 | 326 |
327 [_paymentRequestCoordinator start]; | 327 [_paymentRequestCoordinator start]; |
328 | 328 |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
369 DLOG(ERROR) << "JS message parameter 'payment_details' is invalid"; | 369 DLOG(ERROR) << "JS message parameter 'payment_details' is invalid"; |
370 return NO; | 370 return NO; |
371 } | 371 } |
372 | 372 |
373 [_paymentRequestCoordinator updatePaymentDetails:paymentDetails]; | 373 [_paymentRequestCoordinator updatePaymentDetails:paymentDetails]; |
374 | 374 |
375 return YES; | 375 return YES; |
376 } | 376 } |
377 | 377 |
378 - (void)setUnblockEventQueueTimer { | 378 - (void)setUnblockEventQueueTimer { |
379 _unblockEventQueueTimer.reset( | 379 _unblockEventQueueTimer = |
380 [[NSTimer scheduledTimerWithTimeInterval:kNoopInterval | 380 [NSTimer scheduledTimerWithTimeInterval:kNoopInterval |
381 target:_paymentRequestJsManager | 381 target:_paymentRequestJsManager |
382 selector:@selector(executeNoop) | 382 selector:@selector(executeNoop) |
383 userInfo:nil | 383 userInfo:nil |
384 repeats:YES] retain]); | 384 repeats:YES]; |
385 } | 385 } |
386 | 386 |
387 - (void)setPaymentResponseTimeoutTimer { | 387 - (void)setPaymentResponseTimeoutTimer { |
388 _paymentResponseTimeoutTimer.reset( | 388 _paymentResponseTimeoutTimer = |
389 [[NSTimer scheduledTimerWithTimeInterval:kTimeoutInterval | 389 [NSTimer scheduledTimerWithTimeInterval:kTimeoutInterval |
390 target:self | 390 target:self |
391 selector:@selector(handleResponseComplete) | 391 selector:@selector(handleResponseComplete) |
392 userInfo:nil | 392 userInfo:nil |
393 repeats:NO] retain]); | 393 repeats:NO]; |
394 } | 394 } |
395 | 395 |
396 - (void)dismissUI { | 396 - (void)dismissUI { |
397 [_paymentRequestCoordinator stop]; | 397 [_paymentRequestCoordinator stop]; |
398 _paymentRequestCoordinator.reset(); | 398 _paymentRequestCoordinator = nil; |
399 } | 399 } |
400 | 400 |
401 - (BOOL)webStateContentIsSecureHTML { | 401 - (BOOL)webStateContentIsSecureHTML { |
402 if (![self webState]) { | 402 if (![self webState]) { |
403 return NO; | 403 return NO; |
404 } | 404 } |
405 | 405 |
406 if (!web::UrlHasWebScheme([self webState]->GetLastCommittedURL()) || | 406 if (!web::UrlHasWebScheme([self webState]->GetLastCommittedURL()) || |
407 ![self webState]->ContentIsHTML()) { | 407 ![self webState]->ContentIsHTML()) { |
408 return NO; | 408 return NO; |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
450 - (void)webState:(web::WebState*)webState | 450 - (void)webState:(web::WebState*)webState |
451 didCommitNavigationWithDetails: | 451 didCommitNavigationWithDetails: |
452 (const web::LoadCommittedDetails&)load_details { | 452 (const web::LoadCommittedDetails&)load_details { |
453 [self dismissUI]; | 453 [self dismissUI]; |
454 _isScriptInjected = NO; | 454 _isScriptInjected = NO; |
455 [self enableCurrentWebState]; | 455 [self enableCurrentWebState]; |
456 [self initializeWebViewForPaymentRequest]; | 456 [self initializeWebViewForPaymentRequest]; |
457 } | 457 } |
458 | 458 |
459 @end | 459 @end |
OLD | NEW |