| OLD | NEW |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 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/autofill/form_suggestion_controller.h" | 5 #import "ios/chrome/browser/autofill/form_suggestion_controller.h" |
| 6 | 6 |
| 7 #include <memory> | 7 #include <memory> |
| 8 | 8 |
| 9 #include "base/ios/ios_util.h" | 9 #include "base/ios/ios_util.h" |
| 10 #include "base/ios/weak_nsobject.h" | |
| 11 #include "base/mac/foundation_util.h" | 10 #include "base/mac/foundation_util.h" |
| 12 #include "base/mac/scoped_block.h" | 11 #include "base/mac/scoped_block.h" |
| 13 #include "base/mac/scoped_nsobject.h" | |
| 14 #include "base/strings/sys_string_conversions.h" | 12 #include "base/strings/sys_string_conversions.h" |
| 15 #include "base/strings/utf_string_conversions.h" | 13 #include "base/strings/utf_string_conversions.h" |
| 16 #include "components/autofill/core/browser/autofill_popup_delegate.h" | 14 #include "components/autofill/core/browser/autofill_popup_delegate.h" |
| 17 #import "components/autofill/ios/browser/form_suggestion.h" | 15 #import "components/autofill/ios/browser/form_suggestion.h" |
| 18 #import "ios/chrome/browser/autofill/form_input_accessory_view_controller.h" | 16 #import "ios/chrome/browser/autofill/form_input_accessory_view_controller.h" |
| 19 #import "ios/chrome/browser/autofill/form_suggestion_provider.h" | 17 #import "ios/chrome/browser/autofill/form_suggestion_provider.h" |
| 20 #import "ios/chrome/browser/autofill/form_suggestion_view.h" | 18 #import "ios/chrome/browser/autofill/form_suggestion_view.h" |
| 21 #import "ios/chrome/browser/passwords/password_generation_utils.h" | 19 #import "ios/chrome/browser/passwords/password_generation_utils.h" |
| 22 #include "ios/chrome/browser/ui/ui_util.h" | 20 #include "ios/chrome/browser/ui/ui_util.h" |
| 23 #import "ios/web/public/url_scheme_util.h" | 21 #import "ios/web/public/url_scheme_util.h" |
| 24 #import "ios/web/public/web_state/js/crw_js_injection_receiver.h" | 22 #import "ios/web/public/web_state/js/crw_js_injection_receiver.h" |
| 25 #import "ios/web/public/web_state/ui/crw_web_view_proxy.h" | 23 #import "ios/web/public/web_state/ui/crw_web_view_proxy.h" |
| 26 #import "ios/web/public/web_state/web_state.h" | 24 #import "ios/web/public/web_state/web_state.h" |
| 27 | 25 |
| 26 #if !defined(__has_feature) || !__has_feature(objc_arc) |
| 27 #error "This file requires ARC support." |
| 28 #endif |
| 29 |
| 28 namespace { | 30 namespace { |
| 29 | 31 |
| 30 // Struct that describes suggestion state. | 32 // Struct that describes suggestion state. |
| 31 struct AutofillSuggestionState { | 33 struct AutofillSuggestionState { |
| 32 AutofillSuggestionState(const std::string& form_name, | 34 AutofillSuggestionState(const std::string& form_name, |
| 33 const std::string& field_name, | 35 const std::string& field_name, |
| 34 const std::string& typed_value); | 36 const std::string& typed_value); |
| 35 // The name of the form for autofill. | 37 // The name of the form for autofill. |
| 36 std::string form_name; | 38 std::string form_name; |
| 37 // The name of the field for autofill. | 39 // The name of the field for autofill. |
| 38 std::string field_name; | 40 std::string field_name; |
| 39 // The user-typed value in the field. | 41 // The user-typed value in the field. |
| 40 std::string typed_value; | 42 std::string typed_value; |
| 41 // The suggestions for the form field. An array of |FormSuggestion|. | 43 // The suggestions for the form field. An array of |FormSuggestion|. |
| 42 base::scoped_nsobject<NSArray> suggestions; | 44 NSArray* suggestions; |
| 43 }; | 45 }; |
| 44 | 46 |
| 45 AutofillSuggestionState::AutofillSuggestionState(const std::string& form_name, | 47 AutofillSuggestionState::AutofillSuggestionState(const std::string& form_name, |
| 46 const std::string& field_name, | 48 const std::string& field_name, |
| 47 const std::string& typed_value) | 49 const std::string& typed_value) |
| 48 : form_name(form_name), field_name(field_name), typed_value(typed_value) { | 50 : form_name(form_name), field_name(field_name), typed_value(typed_value) { |
| 49 } | 51 } |
| 50 | 52 |
| 51 } // namespace | 53 } // namespace |
| 52 | 54 |
| 53 @interface FormSuggestionController () <FormInputAccessoryViewProvider> { | 55 @interface FormSuggestionController () <FormInputAccessoryViewProvider> { |
| 54 // Form navigation delegate. | 56 // Form navigation delegate. |
| 55 base::WeakNSProtocol<id<FormInputAccessoryViewDelegate>> _delegate; | 57 __weak id<FormInputAccessoryViewDelegate> _delegate; |
| 56 | 58 |
| 57 // Callback to update the accessory view. | 59 // Callback to update the accessory view. |
| 58 base::mac::ScopedBlock<AccessoryViewReadyCompletion> | 60 AccessoryViewReadyCompletion accessoryViewUpdateBlock_; |
| 59 accessoryViewUpdateBlock_; | |
| 60 | 61 |
| 61 // Autofill suggestion state. | 62 // Autofill suggestion state. |
| 62 std::unique_ptr<AutofillSuggestionState> _suggestionState; | 63 std::unique_ptr<AutofillSuggestionState> _suggestionState; |
| 63 | 64 |
| 64 // Providers for suggestions, sorted according to the order in which | 65 // Providers for suggestions, sorted according to the order in which |
| 65 // they should be asked for suggestions, with highest priority in front. | 66 // they should be asked for suggestions, with highest priority in front. |
| 66 base::scoped_nsobject<NSArray> _suggestionProviders; | 67 NSArray* _suggestionProviders; |
| 67 | 68 |
| 68 // Access to WebView from the CRWWebController. | 69 // Access to WebView from the CRWWebController. |
| 69 base::scoped_nsprotocol<id<CRWWebViewProxy>> _webViewProxy; | 70 id<CRWWebViewProxy> _webViewProxy; |
| 70 } | 71 } |
| 71 | 72 |
| 72 // Returns an autoreleased input accessory view that shows |suggestions|. | 73 // Returns an autoreleased input accessory view that shows |suggestions|. |
| 73 - (UIView*)suggestionViewWithSuggestions:(NSArray*)suggestions; | 74 - (UIView*)suggestionViewWithSuggestions:(NSArray*)suggestions; |
| 74 | 75 |
| 75 // Updates keyboard for |suggestionState|. | 76 // Updates keyboard for |suggestionState|. |
| 76 - (void)updateKeyboard:(AutofillSuggestionState*)suggestionState; | 77 - (void)updateKeyboard:(AutofillSuggestionState*)suggestionState; |
| 77 | 78 |
| 78 // Updates keyboard with |suggestions|. | 79 // Updates keyboard with |suggestions|. |
| 79 - (void)updateKeyboardWithSuggestions:(NSArray*)suggestions; | 80 - (void)updateKeyboardWithSuggestions:(NSArray*)suggestions; |
| 80 | 81 |
| 81 // Clears state in between page loads. | 82 // Clears state in between page loads. |
| 82 - (void)resetSuggestionState; | 83 - (void)resetSuggestionState; |
| 83 | 84 |
| 84 @end | 85 @end |
| 85 | 86 |
| 86 @implementation FormSuggestionController { | 87 @implementation FormSuggestionController { |
| 87 // Bridge to observe the web state from Objective-C. | 88 // Bridge to observe the web state from Objective-C. |
| 88 std::unique_ptr<web::WebStateObserverBridge> _webStateObserverBridge; | 89 std::unique_ptr<web::WebStateObserverBridge> _webStateObserverBridge; |
| 89 | 90 |
| 90 // Manager for FormSuggestion JavaScripts. | 91 // Manager for FormSuggestion JavaScripts. |
| 91 base::scoped_nsobject<JsSuggestionManager> _jsSuggestionManager; | 92 JsSuggestionManager* _jsSuggestionManager; |
| 92 | 93 |
| 93 // The provider for the current set of suggestions. | 94 // The provider for the current set of suggestions. |
| 94 __unsafe_unretained id<FormSuggestionProvider> _provider; // weak | 95 __unsafe_unretained id<FormSuggestionProvider> _provider; // weak |
| 95 } | 96 } |
| 96 | 97 |
| 97 - (instancetype)initWithWebState:(web::WebState*)webState | 98 - (instancetype)initWithWebState:(web::WebState*)webState |
| 98 providers:(NSArray*)providers | 99 providers:(NSArray*)providers |
| 99 JsSuggestionManager:(JsSuggestionManager*)jsSuggestionManager { | 100 JsSuggestionManager:(JsSuggestionManager*)jsSuggestionManager { |
| 100 self = [super init]; | 101 self = [super init]; |
| 101 if (self) { | 102 if (self) { |
| 102 _webStateObserverBridge.reset( | 103 _webStateObserverBridge.reset( |
| 103 new web::WebStateObserverBridge(webState, self)); | 104 new web::WebStateObserverBridge(webState, self)); |
| 104 _webViewProxy.reset([webState->GetWebViewProxy() retain]); | 105 _webViewProxy = webState->GetWebViewProxy(); |
| 105 _jsSuggestionManager.reset([jsSuggestionManager retain]); | 106 _jsSuggestionManager = jsSuggestionManager; |
| 106 _suggestionProviders.reset([providers copy]); | 107 _suggestionProviders = [providers copy]; |
| 107 } | 108 } |
| 108 return self; | 109 return self; |
| 109 } | 110 } |
| 110 | 111 |
| 111 - (instancetype)initWithWebState:(web::WebState*)webState | 112 - (instancetype)initWithWebState:(web::WebState*)webState |
| 112 providers:(NSArray*)providers { | 113 providers:(NSArray*)providers { |
| 113 JsSuggestionManager* jsSuggestionManager = | 114 JsSuggestionManager* jsSuggestionManager = |
| 114 base::mac::ObjCCast<JsSuggestionManager>( | 115 base::mac::ObjCCast<JsSuggestionManager>( |
| 115 [webState->GetJSInjectionReceiver() | 116 [webState->GetJSInjectionReceiver() |
| 116 instanceOfClass:[JsSuggestionManager class]]); | 117 instanceOfClass:[JsSuggestionManager class]]); |
| (...skipping 29 matching lines...) Expand all Loading... |
| 146 if (trustLevel != web::URLVerificationTrustLevel::kAbsolute) { | 147 if (trustLevel != web::URLVerificationTrustLevel::kAbsolute) { |
| 147 DLOG(WARNING) << "Page load not handled on untrusted page"; | 148 DLOG(WARNING) << "Page load not handled on untrusted page"; |
| 148 return; | 149 return; |
| 149 } | 150 } |
| 150 | 151 |
| 151 if (web::UrlHasWebScheme(pageURL) && webState->ContentIsHTML()) | 152 if (web::UrlHasWebScheme(pageURL) && webState->ContentIsHTML()) |
| 152 [_jsSuggestionManager inject]; | 153 [_jsSuggestionManager inject]; |
| 153 } | 154 } |
| 154 | 155 |
| 155 - (void)setWebViewProxy:(id<CRWWebViewProxy>)webViewProxy { | 156 - (void)setWebViewProxy:(id<CRWWebViewProxy>)webViewProxy { |
| 156 _webViewProxy.reset([webViewProxy retain]); | 157 _webViewProxy = webViewProxy; |
| 157 } | 158 } |
| 158 | 159 |
| 159 - (void)retrieveSuggestionsForFormNamed:(const std::string&)formName | 160 - (void)retrieveSuggestionsForFormNamed:(const std::string&)formName |
| 160 fieldName:(const std::string&)fieldName | 161 fieldName:(const std::string&)fieldName |
| 161 type:(const std::string&)type | 162 type:(const std::string&)type |
| 162 webState:(web::WebState*)webState { | 163 webState:(web::WebState*)webState { |
| 163 base::WeakNSObject<FormSuggestionController> weakSelf(self); | 164 __weak FormSuggestionController* weakSelf = self; |
| 164 base::scoped_nsobject<NSString> strongFormName( | 165 NSString* strongFormName = [base::SysUTF8ToNSString(formName) copy]; |
| 165 [base::SysUTF8ToNSString(formName) copy]); | 166 NSString* strongFieldName = [base::SysUTF8ToNSString(fieldName) copy]; |
| 166 base::scoped_nsobject<NSString> strongFieldName( | 167 NSString* strongType = [base::SysUTF8ToNSString(type) copy]; |
| 167 [base::SysUTF8ToNSString(fieldName) copy]); | 168 NSString* strongValue = |
| 168 base::scoped_nsobject<NSString> strongType( | 169 [base::SysUTF8ToNSString(_suggestionState.get()->typed_value) copy]; |
| 169 [base::SysUTF8ToNSString(type) copy]); | |
| 170 base::scoped_nsobject<NSString> strongValue( | |
| 171 [base::SysUTF8ToNSString(_suggestionState.get()->typed_value) copy]); | |
| 172 | 170 |
| 173 // Build a block for each provider that will invoke its completion with YES | 171 // Build a block for each provider that will invoke its completion with YES |
| 174 // if the provider can provide suggestions for the specified form/field/type | 172 // if the provider can provide suggestions for the specified form/field/type |
| 175 // and NO otherwise. | 173 // and NO otherwise. |
| 176 base::scoped_nsobject<NSMutableArray> findProviderBlocks( | 174 NSMutableArray* findProviderBlocks = [[NSMutableArray alloc] init]; |
| 177 [[NSMutableArray alloc] init]); | |
| 178 for (NSUInteger i = 0; i < [_suggestionProviders count]; i++) { | 175 for (NSUInteger i = 0; i < [_suggestionProviders count]; i++) { |
| 179 base::mac::ScopedBlock<passwords::PipelineBlock> block( | 176 passwords::PipelineBlock block = |
| 180 ^(void (^completion)(BOOL success)) { | 177 ^(void (^completion)(BOOL success)) { |
| 181 // Access all the providers through |self| to guarantee that both | 178 // Access all the providers through |self| to guarantee that both |
| 182 // |self| and all the providers exist when the block is executed. | 179 // |self| and all the providers exist when the block is executed. |
| 183 // |_suggestionProviders| is immutable, so the subscripting is | 180 // |_suggestionProviders| is immutable, so the subscripting is |
| 184 // always valid. | 181 // always valid. |
| 185 base::scoped_nsobject<FormSuggestionController> strongSelf( | 182 FormSuggestionController* strongSelf = weakSelf; |
| 186 [weakSelf retain]); | |
| 187 if (!strongSelf) | 183 if (!strongSelf) |
| 188 return; | 184 return; |
| 189 id<FormSuggestionProvider> provider = | 185 id<FormSuggestionProvider> provider = |
| 190 strongSelf.get()->_suggestionProviders[i]; | 186 strongSelf->_suggestionProviders[i]; |
| 191 [provider checkIfSuggestionsAvailableForForm:strongFormName | 187 [provider checkIfSuggestionsAvailableForForm:strongFormName |
| 192 field:strongFieldName | 188 field:strongFieldName |
| 193 type:strongType | 189 type:strongType |
| 194 typedValue:strongValue | 190 typedValue:strongValue |
| 195 webState:webState | 191 webState:webState |
| 196 completionHandler:completion]; | 192 completionHandler:completion]; |
| 197 }, | 193 }; |
| 198 base::scoped_policy::RETAIN); | |
| 199 [findProviderBlocks addObject:block]; | 194 [findProviderBlocks addObject:block]; |
| 200 } | 195 } |
| 201 | 196 |
| 202 // Once the suggestions are retrieved, update the suggestions UI. | 197 // Once the suggestions are retrieved, update the suggestions UI. |
| 203 SuggestionsReadyCompletion readyCompletion = | 198 SuggestionsReadyCompletion readyCompletion = |
| 204 ^(NSArray* suggestions, id<FormSuggestionProvider> provider) { | 199 ^(NSArray* suggestions, id<FormSuggestionProvider> provider) { |
| 205 [weakSelf onSuggestionsReady:suggestions provider:provider]; | 200 [weakSelf onSuggestionsReady:suggestions provider:provider]; |
| 206 }; | 201 }; |
| 207 | 202 |
| 208 // Once a provider is found, use it to retrieve suggestions. | 203 // Once a provider is found, use it to retrieve suggestions. |
| 209 passwords::PipelineCompletionBlock completion = ^(NSUInteger providerIndex) { | 204 passwords::PipelineCompletionBlock completion = ^(NSUInteger providerIndex) { |
| 210 if (providerIndex == NSNotFound) { | 205 if (providerIndex == NSNotFound) { |
| 211 [weakSelf onNoSuggestionsAvailable]; | 206 [weakSelf onNoSuggestionsAvailable]; |
| 212 return; | 207 return; |
| 213 } | 208 } |
| 214 base::scoped_nsobject<FormSuggestionController> strongSelf( | 209 FormSuggestionController* strongSelf = weakSelf; |
| 215 [weakSelf retain]); | |
| 216 if (!strongSelf) | 210 if (!strongSelf) |
| 217 return; | 211 return; |
| 218 id<FormSuggestionProvider> provider = | 212 id<FormSuggestionProvider> provider = |
| 219 strongSelf.get()->_suggestionProviders[providerIndex]; | 213 strongSelf->_suggestionProviders[providerIndex]; |
| 220 [provider retrieveSuggestionsForForm:strongFormName | 214 [provider retrieveSuggestionsForForm:strongFormName |
| 221 field:strongFieldName | 215 field:strongFieldName |
| 222 type:strongType | 216 type:strongType |
| 223 typedValue:strongValue | 217 typedValue:strongValue |
| 224 webState:webState | 218 webState:webState |
| 225 completionHandler:readyCompletion]; | 219 completionHandler:readyCompletion]; |
| 226 }; | 220 }; |
| 227 | 221 |
| 228 // Run all the blocks in |findProviderBlocks| until one invokes its | 222 // Run all the blocks in |findProviderBlocks| until one invokes its |
| 229 // completion with YES. The first one to do so will be passed to | 223 // completion with YES. The first one to do so will be passed to |
| 230 // |completion|. | 224 // |completion|. |
| 231 passwords::RunSearchPipeline(findProviderBlocks, completion); | 225 passwords::RunSearchPipeline(findProviderBlocks, completion); |
| 232 } | 226 } |
| 233 | 227 |
| 234 - (void)onSuggestionsReady:(NSArray*)suggestions | 228 - (void)onSuggestionsReady:(NSArray*)suggestions |
| 235 provider:(id<FormSuggestionProvider>)provider { | 229 provider:(id<FormSuggestionProvider>)provider { |
| 236 // TODO(ios): crbug.com/249916. If we can also pass in the form/field for | 230 // TODO(ios): crbug.com/249916. If we can also pass in the form/field for |
| 237 // which |suggestions| are, we should check here if |suggestions| are for | 231 // which |suggestions| are, we should check here if |suggestions| are for |
| 238 // the current active element. If not, reset |_suggestionState|. | 232 // the current active element. If not, reset |_suggestionState|. |
| 239 if (!_suggestionState) { | 233 if (!_suggestionState) { |
| 240 // The suggestion state was reset in between the call to Autofill API (e.g. | 234 // The suggestion state was reset in between the call to Autofill API (e.g. |
| 241 // OnQueryFormFieldAutofill) and this method being called back. Results are | 235 // OnQueryFormFieldAutofill) and this method being called back. Results are |
| 242 // therefore no longer relevant. | 236 // therefore no longer relevant. |
| 243 return; | 237 return; |
| 244 } | 238 } |
| 245 | 239 |
| 246 _provider = provider; | 240 _provider = provider; |
| 247 _suggestionState->suggestions.reset([suggestions copy]); | 241 _suggestionState->suggestions = [suggestions copy]; |
| 248 [self updateKeyboard:_suggestionState.get()]; | 242 [self updateKeyboard:_suggestionState.get()]; |
| 249 } | 243 } |
| 250 | 244 |
| 251 - (void)resetSuggestionState { | 245 - (void)resetSuggestionState { |
| 252 _provider = nil; | 246 _provider = nil; |
| 253 _suggestionState.reset(); | 247 _suggestionState.reset(); |
| 254 } | 248 } |
| 255 | 249 |
| 256 - (void)clearSuggestions { | 250 - (void)clearSuggestions { |
| 257 // Note that other parts of the suggestionsState are not reset. | 251 // Note that other parts of the suggestionsState are not reset. |
| 258 if (!_suggestionState.get()) | 252 if (!_suggestionState.get()) |
| 259 return; | 253 return; |
| 260 _suggestionState->suggestions.reset([[NSArray alloc] init]); | 254 _suggestionState->suggestions = [[NSArray alloc] init]; |
| 261 [self updateKeyboard:_suggestionState.get()]; | 255 [self updateKeyboard:_suggestionState.get()]; |
| 262 } | 256 } |
| 263 | 257 |
| 264 - (void)updateKeyboard:(AutofillSuggestionState*)suggestionState { | 258 - (void)updateKeyboard:(AutofillSuggestionState*)suggestionState { |
| 265 if (!suggestionState) { | 259 if (!suggestionState) { |
| 266 if (accessoryViewUpdateBlock_) | 260 if (accessoryViewUpdateBlock_) |
| 267 accessoryViewUpdateBlock_.get()(nil, self); | 261 accessoryViewUpdateBlock_(nil, self); |
| 268 } else { | 262 } else { |
| 269 [self updateKeyboardWithSuggestions:suggestionState->suggestions]; | 263 [self updateKeyboardWithSuggestions:suggestionState->suggestions]; |
| 270 } | 264 } |
| 271 } | 265 } |
| 272 | 266 |
| 273 - (void)updateKeyboardWithSuggestions:(NSArray*)suggestions { | 267 - (void)updateKeyboardWithSuggestions:(NSArray*)suggestions { |
| 274 if (accessoryViewUpdateBlock_) { | 268 if (accessoryViewUpdateBlock_) { |
| 275 accessoryViewUpdateBlock_.get()( | 269 accessoryViewUpdateBlock_([self suggestionViewWithSuggestions:suggestions], |
| 276 [self suggestionViewWithSuggestions:suggestions], self); | 270 self); |
| 277 } | 271 } |
| 278 } | 272 } |
| 279 | 273 |
| 280 - (UIView*)suggestionViewWithSuggestions:(NSArray*)suggestions { | 274 - (UIView*)suggestionViewWithSuggestions:(NSArray*)suggestions { |
| 281 CGRect frame = [_webViewProxy keyboardAccessory].frame; | 275 CGRect frame = [_webViewProxy keyboardAccessory].frame; |
| 282 // Force the desired height on iPad where the height of the | 276 // Force the desired height on iPad where the height of the |
| 283 // inputAccessoryView is 0. | 277 // inputAccessoryView is 0. |
| 284 if (IsIPadIdiom()) { | 278 if (IsIPadIdiom()) { |
| 285 frame.size.height = autofill::kInputAccessoryHeight; | 279 frame.size.height = autofill::kInputAccessoryHeight; |
| 286 } | 280 } |
| 287 base::scoped_nsobject<FormSuggestionView> view([[FormSuggestionView alloc] | 281 FormSuggestionView* view = |
| 288 initWithFrame:frame | 282 [[FormSuggestionView alloc] initWithFrame:frame |
| 289 client:self | 283 client:self |
| 290 suggestions:suggestions]); | 284 suggestions:suggestions]; |
| 291 return view.autorelease(); | 285 return view; |
| 292 } | 286 } |
| 293 | 287 |
| 294 - (void)didSelectSuggestion:(FormSuggestion*)suggestion { | 288 - (void)didSelectSuggestion:(FormSuggestion*)suggestion { |
| 295 if (!_suggestionState) | 289 if (!_suggestionState) |
| 296 return; | 290 return; |
| 297 | 291 |
| 298 // Send the suggestion to the provider. Upon completion advance the cursor | 292 // Send the suggestion to the provider. Upon completion advance the cursor |
| 299 // for single-field Autofill, or close the keyboard for full-form Autofill. | 293 // for single-field Autofill, or close the keyboard for full-form Autofill. |
| 300 base::WeakNSObject<FormSuggestionController> weakSelf(self); | 294 __weak FormSuggestionController* weakSelf = self; |
| 301 [_provider | 295 [_provider |
| 302 didSelectSuggestion:suggestion | 296 didSelectSuggestion:suggestion |
| 303 forField:base::SysUTF8ToNSString(_suggestionState->field_name) | 297 forField:base::SysUTF8ToNSString(_suggestionState->field_name) |
| 304 form:base::SysUTF8ToNSString(_suggestionState->form_name) | 298 form:base::SysUTF8ToNSString(_suggestionState->form_name) |
| 305 completionHandler:^{ | 299 completionHandler:^{ |
| 306 [[weakSelf accessoryViewDelegate] closeKeyboardWithoutButtonPress]; | 300 [[weakSelf accessoryViewDelegate] closeKeyboardWithoutButtonPress]; |
| 307 }]; | 301 }]; |
| 308 _provider = nil; | 302 _provider = nil; |
| 309 } | 303 } |
| 310 | 304 |
| 311 - (id<FormInputAccessoryViewProvider>)accessoryViewProvider { | 305 - (id<FormInputAccessoryViewProvider>)accessoryViewProvider { |
| 312 return self; | 306 return self; |
| 313 } | 307 } |
| 314 | 308 |
| 315 #pragma mark FormInputAccessoryViewProvider | 309 #pragma mark FormInputAccessoryViewProvider |
| 316 | 310 |
| 317 - (id<FormInputAccessoryViewDelegate>)accessoryViewDelegate { | 311 - (id<FormInputAccessoryViewDelegate>)accessoryViewDelegate { |
| 318 return _delegate.get(); | 312 return _delegate; |
| 319 } | 313 } |
| 320 | 314 |
| 321 - (void)setAccessoryViewDelegate:(id<FormInputAccessoryViewDelegate>)delegate { | 315 - (void)setAccessoryViewDelegate:(id<FormInputAccessoryViewDelegate>)delegate { |
| 322 _delegate.reset(delegate); | 316 _delegate = delegate; |
| 323 } | 317 } |
| 324 | 318 |
| 325 - (void) | 319 - (void) |
| 326 checkIfAccessoryViewIsAvailableForFormNamed:(const std::string&)formName | 320 checkIfAccessoryViewIsAvailableForFormNamed:(const std::string&)formName |
| 327 fieldName:(const std::string&)fieldName | 321 fieldName:(const std::string&)fieldName |
| 328 webState:(web::WebState*)webState | 322 webState:(web::WebState*)webState |
| 329 completionHandler: | 323 completionHandler: |
| 330 (AccessoryViewAvailableCompletion) | 324 (AccessoryViewAvailableCompletion) |
| 331 completionHandler { | 325 completionHandler { |
| 332 [self processPage:webState]; | 326 [self processPage:webState]; |
| 333 completionHandler(YES); | 327 completionHandler(YES); |
| 334 } | 328 } |
| 335 | 329 |
| 336 - (void)retrieveAccessoryViewForFormNamed:(const std::string&)formName | 330 - (void)retrieveAccessoryViewForFormNamed:(const std::string&)formName |
| 337 fieldName:(const std::string&)fieldName | 331 fieldName:(const std::string&)fieldName |
| 338 value:(const std::string&)value | 332 value:(const std::string&)value |
| 339 type:(const std::string&)type | 333 type:(const std::string&)type |
| 340 webState:(web::WebState*)webState | 334 webState:(web::WebState*)webState |
| 341 accessoryViewUpdateBlock: | 335 accessoryViewUpdateBlock: |
| 342 (AccessoryViewReadyCompletion)accessoryViewUpdateBlock { | 336 (AccessoryViewReadyCompletion)accessoryViewUpdateBlock { |
| 343 _suggestionState.reset( | 337 _suggestionState.reset( |
| 344 new AutofillSuggestionState(formName, fieldName, value)); | 338 new AutofillSuggestionState(formName, fieldName, value)); |
| 345 accessoryViewUpdateBlock([self suggestionViewWithSuggestions:@[]], self); | 339 accessoryViewUpdateBlock([self suggestionViewWithSuggestions:@[]], self); |
| 346 accessoryViewUpdateBlock_.reset([accessoryViewUpdateBlock copy]); | 340 accessoryViewUpdateBlock_ = [accessoryViewUpdateBlock copy]; |
| 347 [self retrieveSuggestionsForFormNamed:formName | 341 [self retrieveSuggestionsForFormNamed:formName |
| 348 fieldName:fieldName | 342 fieldName:fieldName |
| 349 type:type | 343 type:type |
| 350 webState:webState]; | 344 webState:webState]; |
| 351 } | 345 } |
| 352 | 346 |
| 353 - (void)inputAccessoryViewControllerDidReset: | 347 - (void)inputAccessoryViewControllerDidReset: |
| 354 (FormInputAccessoryViewController*)controller { | 348 (FormInputAccessoryViewController*)controller { |
| 355 accessoryViewUpdateBlock_.reset(); | 349 accessoryViewUpdateBlock_ = nil; |
| 356 [self resetSuggestionState]; | 350 [self resetSuggestionState]; |
| 357 } | 351 } |
| 358 | 352 |
| 359 - (void)resizeAccessoryView { | 353 - (void)resizeAccessoryView { |
| 360 [self updateKeyboard:_suggestionState.get()]; | 354 [self updateKeyboard:_suggestionState.get()]; |
| 361 } | 355 } |
| 362 | 356 |
| 363 - (BOOL)getLogKeyboardAccessoryMetrics { | 357 - (BOOL)getLogKeyboardAccessoryMetrics { |
| 364 return YES; | 358 return YES; |
| 365 } | 359 } |
| 366 | 360 |
| 367 @end | 361 @end |
| OLD | NEW |