Commit b91e2cbe authored by Moe Ahmadi's avatar Moe Ahmadi Committed by Commit Bot

[AF][IOS] Folds AutofillController into AutofillAgent and AutofillTabHelper

AutofillController for the most part forwards calls from AutofillClient
and AutofillDriver to AutofillAgent. This complicates understanding and
debugging the logic. It also has some logic (e.g., adding clear form and
gpay logo to the list of suggestions) that has been a source of confusion
in past. This CL gets rid of AutofillController by:
-Removing the middle man for the AutofillClient and AutofillDriver calls.
-Moving the logic to setup AutofillDriver to AutofillTabHelper.
-Merging its tests into AutofillAgent and JSAutofillManager tests.

Change-Id: I207ec8137a8d4b0cfc1c42de8cd06b8f4de33e67
Reviewed-on: https://chromium-review.googlesource.com/c/1310353
Commit-Queue: Moe Ahmadi <mahmadi@chromium.org>
Reviewed-by: default avatarOlivier Robin <olivierrobin@chromium.org>
Reviewed-by: default avatarSergio Collazos <sczs@chromium.org>
Reviewed-by: default avatarJohn Wu <jzw@chromium.org>
Cr-Commit-Position: refs/heads/master@{#611967}
parent ea30604c
......@@ -5,18 +5,10 @@
#define COMPONENTS_AUTOFILL_IOS_BROWSER_AUTOFILL_AGENT_H
#import <Foundation/Foundation.h>
#include <vector>
#include "base/memory/weak_ptr.h"
#include "components/autofill/core/browser/autofill_metrics.h"
#include "components/autofill/core/common/form_data_predictions.h"
#import "components/autofill/ios/browser/autofill_client_ios_bridge.h"
#import "components/autofill/ios/browser/autofill_driver_ios_bridge.h"
#import "components/autofill/ios/browser/form_suggestion_provider.h"
#import "ios/web/public/web_state/web_state_observer_bridge.h"
namespace autofill {
class AutofillPopupDelegate;
struct FormData;
}
class PrefService;
......@@ -28,7 +20,9 @@ class WebState;
// AutofillManager for metrics and to retrieve suggestions, and fills forms in
// response to user interaction with suggestions. This is the iOS counterpart
// to the upstream class autofill::AutofillAgent.
@interface AutofillAgent : NSObject<FormSuggestionProvider>
@interface AutofillAgent : NSObject <AutofillClientIOSBridge,
AutofillDriverIOSBridge,
FormSuggestionProvider>
// Designated initializer. Arguments |prefService| and |webState| should not be
// null.
......@@ -38,26 +32,6 @@ class WebState;
- (instancetype)init NS_UNAVAILABLE;
// Callback by AutofillController when suggestions are ready.
- (void)onSuggestionsReady:(NSArray<FormSuggestion*>*)suggestions
popupDelegate:
(const base::WeakPtr<autofill::AutofillPopupDelegate>&)
delegate;
// The supplied data should be filled into the form in |frame|.
- (void)onFormDataFilled:(const autofill::FormData&)result
inFrame:(web::WebFrame*)frame;
// Detatches from the web state.
- (void)detachFromWebState;
// Renders the field type predictions specified in |forms| in |frame|. This
// method is a no-op if the kAutofillShowTypePredictions experiment is not
// enabled.
- (void)renderAutofillTypePredictions:
(const std::vector<autofill::FormDataPredictions>&)forms
inFrame:(web::WebFrame*)frame;
@end
#endif // COMPONENTS_AUTOFILL_IOS_BROWSER_AUTOFILL_AGENT_H
......@@ -9,6 +9,7 @@
#include "base/test/scoped_feature_list.h"
#include "components/autofill/core/browser/autofill_test_utils.h"
#include "components/autofill/core/browser/popup_item_ids.h"
#include "components/autofill/core/browser/suggestion.h"
#include "components/autofill/core/browser/test_autofill_client.h"
#include "components/autofill/core/common/autofill_features.h"
#include "components/autofill/core/common/autofill_prefs.h"
......@@ -89,12 +90,6 @@ class AutofillAgentTests : public PlatformTest {
webState:&test_web_state_];
}
void TearDown() override {
[autofill_agent_ detachFromWebState];
PlatformTest::TearDown();
}
web::TestWebThreadBundle thread_bundle_;
web::TestBrowserState test_browser_state_;
web::TestWebState test_web_state_;
......@@ -119,6 +114,12 @@ TEST_F(AutofillAgentTests, OnFormDataFilledTest) {
autofill::features::kAutofillEnableIFrameSupportOniOS);
disabled_features.push_back(web::features::kWebFrameMessaging);
scoped_feature_list.InitWithFeatures(enabled_features, disabled_features);
std::string locale("en");
autofill::AutofillDriverIOS::PrepareForWebStateWebFrameAndDelegate(
&test_web_state_, &client_, nil, locale,
autofill::AutofillManager::DISABLE_AUTOFILL_DOWNLOAD_MANAGER);
autofill::FormData form;
form.origin = GURL("https://myform.com");
form.action = GURL("https://myform.com/submit");
......@@ -166,7 +167,7 @@ TEST_F(AutofillAgentTests, OnFormDataFilledTest) {
@"\"number\":{\"section\":\"\",\"value\":\"number_value\"}},"
@"\"formName\":\"CC form\"}, \"\");"
completionHandler:[OCMArg any]];
[autofill_agent_ onFormDataFilled:form
[autofill_agent_ fillFormData:form
inFrame:web::GetMainWebFrame(&test_web_state_)];
test_web_state_.WasShown();
......@@ -185,6 +186,12 @@ TEST_F(AutofillAgentTests, OnFormDataFilledTestWithFrameMessaging) {
autofill::features::kAutofillEnableIFrameSupportOniOS);
enabled_features.push_back(web::features::kWebFrameMessaging);
scoped_feature_list.InitWithFeatures(enabled_features, disabled_features);
std::string locale("en");
autofill::AutofillDriverIOS::PrepareForWebStateWebFrameAndDelegate(
&test_web_state_, &client_, nil, locale,
autofill::AutofillManager::DISABLE_AUTOFILL_DOWNLOAD_MANAGER);
autofill::FormData form;
form.origin = GURL("https://myform.com");
form.action = GURL("https://myform.com/submit");
......@@ -224,7 +231,7 @@ TEST_F(AutofillAgentTests, OnFormDataFilledTestWithFrameMessaging) {
field.value = base::ASCIIToUTF16("");
field.is_autofilled = true;
form.fields.push_back(field);
[autofill_agent_ onFormDataFilled:form
[autofill_agent_ fillFormData:form
inFrame:web::GetMainWebFrame(&test_web_state_)];
test_web_state_.WasShown();
EXPECT_EQ(
......@@ -246,6 +253,12 @@ TEST_F(AutofillAgentTests, OnFormDataFilledWithNameCollisionTest) {
autofill::features::kAutofillEnableIFrameSupportOniOS);
disabled_features.push_back(web::features::kWebFrameMessaging);
scoped_feature_list.InitWithFeatures(enabled_features, disabled_features);
std::string locale("en");
autofill::AutofillDriverIOS::PrepareForWebStateWebFrameAndDelegate(
&test_web_state_, &client_, nil, locale,
autofill::AutofillManager::DISABLE_AUTOFILL_DOWNLOAD_MANAGER);
autofill::FormData form;
form.origin = GURL("https://myform.com");
form.action = GURL("https://myform.com/submit");
......@@ -284,7 +297,7 @@ TEST_F(AutofillAgentTests, OnFormDataFilledWithNameCollisionTest) {
@"2\"},\"region\":{\"section\":\"\",\"value\":\"California\"}},"
@"\"formName\":\"\"}, \"\");"
completionHandler:[OCMArg any]];
[autofill_agent_ onFormDataFilled:form
[autofill_agent_ fillFormData:form
inFrame:web::GetMainWebFrame(&test_web_state_)];
test_web_state_.WasShown();
......@@ -303,6 +316,12 @@ TEST_F(AutofillAgentTests,
autofill::features::kAutofillEnableIFrameSupportOniOS);
enabled_features.push_back(web::features::kWebFrameMessaging);
scoped_feature_list.InitWithFeatures(enabled_features, disabled_features);
std::string locale("en");
autofill::AutofillDriverIOS::PrepareForWebStateWebFrameAndDelegate(
&test_web_state_, &client_, nil, locale,
autofill::AutofillManager::DISABLE_AUTOFILL_DOWNLOAD_MANAGER);
autofill::FormData form;
form.origin = GURL("https://myform.com");
form.action = GURL("https://myform.com/submit");
......@@ -334,7 +353,7 @@ TEST_F(AutofillAgentTests,
field.is_autofilled = true;
form.fields.push_back(field);
// Fields are in alphabetical order.
[autofill_agent_ onFormDataFilled:form
[autofill_agent_ fillFormData:form
inFrame:web::GetMainWebFrame(&test_web_state_)];
test_web_state_.WasShown();
EXPECT_EQ(
......@@ -503,30 +522,21 @@ TEST_F(AutofillAgentTests,
EXPECT_FALSE(completion_handler_success);
}
// Tests that when Autofill suggestions are made available to AutofillManager
// Tests that when Autofill suggestions are made available to AutofillAgent
// "Clear Form" is moved to the start of the list and the order of other
// suggestions remains unchanged.
TEST_F(AutofillAgentTests, onSuggestionsReady_ClearForm) {
__block NSArray<FormSuggestion*>* completion_handler_suggestions = nil;
__block BOOL completion_handler_called = NO;
// Make the suggestions available to AutofillManager.
NSArray* suggestions = @[
[FormSuggestion suggestionWithValue:@""
displayDescription:nil
icon:@""
identifier:123],
[FormSuggestion suggestionWithValue:@""
displayDescription:nil
icon:@""
identifier:321],
[FormSuggestion suggestionWithValue:@""
displayDescription:nil
icon:@""
identifier:autofill::POPUP_ITEM_ID_CLEAR_FORM]
];
// Make the suggestions available to AutofillAgent.
std::vector<autofill::Suggestion> suggestions;
suggestions.push_back(autofill::Suggestion("", "", "", 123));
suggestions.push_back(autofill::Suggestion("", "", "", 321));
suggestions.push_back(
autofill::Suggestion("", "", "", POPUP_ITEM_ID_CLEAR_FORM));
[autofill_agent_
onSuggestionsReady:suggestions
showAutofillPopup:suggestions
popupDelegate:base::WeakPtr<autofill::AutofillPopupDelegate>()];
// Retrieves the suggestions.
......@@ -559,33 +569,22 @@ TEST_F(AutofillAgentTests, onSuggestionsReady_ClearForm) {
EXPECT_EQ(321, completion_handler_suggestions[2].identifier);
}
// Tests that when Autofill suggestions are made available to AutofillManager
// Tests that when Autofill suggestions are made available to AutofillAgent
// GPay icon remains as the first suggestion.
TEST_F(AutofillAgentTests, onSuggestionsReady_ClearFormWithGPay) {
__block NSArray<FormSuggestion*>* completion_handler_suggestions = nil;
__block BOOL completion_handler_called = NO;
// Make the suggestions available to AutofillManager.
NSArray* suggestions = @[
[FormSuggestion suggestionWithValue:@""
displayDescription:nil
icon:@""
identifier:POPUP_ITEM_ID_GOOGLE_PAY_BRANDING],
[FormSuggestion suggestionWithValue:@""
displayDescription:nil
icon:@""
identifier:123],
[FormSuggestion suggestionWithValue:@""
displayDescription:nil
icon:@""
identifier:321],
[FormSuggestion suggestionWithValue:@""
displayDescription:nil
icon:@""
identifier:POPUP_ITEM_ID_CLEAR_FORM]
];
// Make the suggestions available to AutofillAgent.
std::vector<autofill::Suggestion> suggestions;
suggestions.push_back(
autofill::Suggestion("", "", "", POPUP_ITEM_ID_GOOGLE_PAY_BRANDING));
suggestions.push_back(autofill::Suggestion("", "", "", 123));
suggestions.push_back(autofill::Suggestion("", "", "", 321));
suggestions.push_back(
autofill::Suggestion("", "", "", POPUP_ITEM_ID_CLEAR_FORM));
[autofill_agent_
onSuggestionsReady:suggestions
showAutofillPopup:suggestions
popupDelegate:base::WeakPtr<autofill::AutofillPopupDelegate>()];
// Retrieves the suggestions.
......@@ -636,6 +635,7 @@ TEST_F(AutofillAgentTests, FrameInitializationOrder) {
&test_web_state_, &client_, nil, locale,
autofill::AutofillManager::DISABLE_AUTOFILL_DOWNLOAD_MANAGER);
// Remove the current main frame.
test_web_state_.RemoveWebFrame(fake_main_frame_->GetFrameId());
// Add frame when page is loading.
......@@ -708,7 +708,8 @@ TEST_F(AutofillAgentTests, FrameInitializationOrderFrames) {
autofill::AutofillDriverIOS::PrepareForWebStateWebFrameAndDelegate(
&test_web_state_, &client_, nil, locale,
autofill::AutofillManager::DISABLE_AUTOFILL_DOWNLOAD_MANAGER);
// Remove the current main frame
// Remove the current main frame.
test_web_state_.RemoveWebFrame(fake_main_frame_->GetFrameId());
// Both frames available, then page loaded.
......
......@@ -98,7 +98,7 @@ void AutofillDriverIOS::SendFormDataToRenderer(
int query_id,
RendererFormDataAction action,
const FormData& data) {
[bridge_ onFormDataFilled:query_id inFrame:web_frame_ result:data];
[bridge_ fillFormData:data inFrame:web_frame_];
}
void AutofillDriverIOS::PropagateAutofillPredictions(
......@@ -108,9 +108,8 @@ void AutofillDriverIOS::PropagateAutofillPredictions(
void AutofillDriverIOS::SendAutofillTypePredictionsToRenderer(
const std::vector<FormStructure*>& forms) {
[bridge_ sendAutofillTypePredictionsToRenderer:
FormStructure::GetFieldTypePredictions(forms)
toFrame:web_frame_];
[bridge_ fillFormDataPredictions:FormStructure::GetFieldTypePredictions(forms)
inFrame:web_frame_];
}
void AutofillDriverIOS::RendererShouldAcceptDataListSuggestion(
......
......@@ -22,13 +22,12 @@ class WebFrame;
// Interface used to pipe form data from AutofillDriverIOS to the embedder.
@protocol AutofillDriverIOSBridge
- (void)onFormDataFilled:(uint16_t)query_id
inFrame:(web::WebFrame*)frame
result:(const autofill::FormData&)result;
- (void)fillFormData:(const autofill::FormData&)form
inFrame:(web::WebFrame*)frame;
- (void)sendAutofillTypePredictionsToRenderer:
- (void)fillFormDataPredictions:
(const std::vector<autofill::FormDataPredictions>&)forms
toFrame:(web::WebFrame*)frame;
inFrame:(web::WebFrame*)frame;
@end
......
......@@ -95,8 +95,6 @@ source_set("autofill_shared") {
source_set("autofill_internal") {
configs += [ "//build/config/compiler:enable_arc" ]
sources = [
"autofill_controller.h",
"autofill_controller.mm",
"autofill_tab_helper.h",
"autofill_tab_helper.mm",
]
......
// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef IOS_CHROME_BROWSER_AUTOFILL_AUTOFILL_CONTROLLER_H_
#define IOS_CHROME_BROWSER_AUTOFILL_AUTOFILL_CONTROLLER_H_
#import <UIKit/UIKit.h>
#include <vector>
#include "components/autofill/core/common/form_data_predictions.h"
@class AutofillAgent;
@protocol FormSuggestionProvider;
namespace ios {
class ChromeBrowserState;
}
namespace password_manager {
class PasswordGenerationManager;
}
namespace web {
class WebFrame;
class WebState;
}
// Handles Autofill.
@interface AutofillController : NSObject
@property(nonatomic, readonly) ios::ChromeBrowserState* browserState;
@property(weak, nonatomic, readonly) id<FormSuggestionProvider>
suggestionProvider;
// Designated initializer. Neither |browserState| nor |webState| should be null.
// |downloadEnabled| should be NO for tests to stop the system making external
// network requests.
- (instancetype)
initWithBrowserState:(ios::ChromeBrowserState*)browserState
webState:(web::WebState*)webState
autofillAgent:(AutofillAgent*)autofillAgent
passwordGenerationManager:
(password_manager::PasswordGenerationManager*)passwordGenerationManager
downloadEnabled:(BOOL)downloadEnabled NS_DESIGNATED_INITIALIZER;
// Convenience initializer. The autofill agent will be created from the
// given webstate.
// The system will start making external network requests.
- (instancetype)initWithBrowserState:(ios::ChromeBrowserState*)browserState
passwordGenerationManager:
(password_manager::PasswordGenerationManager*)
passwordGenerationManager
webState:(web::WebState*)webState;
- (instancetype)init NS_UNAVAILABLE;
// Detaches itself from the supplied |webState|.
- (void)detachFromWebState;
// Sends the field type predictions specified in |forms| to the renderer. This
// method is a no-op if the appropriate experiment is not set.
- (void)sendAutofillTypePredictionsToRenderer:
(const std::vector<autofill::FormDataPredictions>&)forms
toFrame:(web::WebFrame*)frame;
// Sets a weak reference to the view controller used to present UI.
- (void)setBaseViewController:(UIViewController*)baseViewController;
@end
#endif // IOS_CHROME_BROWSER_AUTOFILL_AUTOFILL_CONTROLLER_H_
// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#import "ios/chrome/browser/autofill/autofill_controller.h"
#include <stdint.h>
#include <memory>
#include <utility>
#include "base/strings/sys_string_conversions.h"
#include "base/strings/utf_string_conversions.h"
#include "components/autofill/core/browser/autofill_manager.h"
#include "components/autofill/core/browser/popup_item_ids.h"
#import "components/autofill/ios/browser/autofill_agent.h"
#import "components/autofill/ios/browser/autofill_client_ios_bridge.h"
#include "components/autofill/ios/browser/autofill_driver_ios.h"
#include "components/autofill/ios/browser/autofill_driver_ios_bridge.h"
#include "components/autofill/ios/browser/autofill_switches.h"
#import "components/autofill/ios/browser/form_suggestion.h"
#import "components/autofill/ios/browser/form_suggestion_provider.h"
#include "components/infobars/core/infobar_manager.h"
#include "components/pref_registry/pref_registry_syncable.h"
#include "components/prefs/pref_service.h"
#include "ios/chrome/browser/application_context.h"
#include "ios/chrome/browser/browser_state/chrome_browser_state.h"
#include "ios/chrome/browser/infobars/infobar_manager_impl.h"
#include "ios/chrome/browser/pref_names.h"
#import "ios/chrome/browser/ui/autofill/chrome_autofill_client_ios.h"
#include "ios/web/public/web_state/web_frame.h"
#include "ios/web/public/web_state/web_frame_util.h"
#import "ios/web/public/web_state/web_frames_manager.h"
#import "ios/web/public/web_state/web_state.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
#endif
using autofill::AutofillPopupDelegate;
@interface AutofillController ()<AutofillClientIOSBridge,
AutofillDriverIOSBridge> {
AutofillAgent* _autofillAgent;
std::unique_ptr<autofill::ChromeAutofillClientIOS> _autofillClient;
web::WebState* _webState;
}
@end
@implementation AutofillController
@synthesize browserState = _browserState;
- (instancetype)initWithBrowserState:(ios::ChromeBrowserState*)browserState
webState:(web::WebState*)webState
autofillAgent:(AutofillAgent*)autofillAgent
passwordGenerationManager:
(password_manager::PasswordGenerationManager*)
passwordGenerationManager
downloadEnabled:(BOOL)downloadEnabled {
DCHECK(browserState);
DCHECK(webState);
self = [super init];
if (self) {
_browserState = browserState;
_webState = webState;
infobars::InfoBarManager* infobarManager =
InfoBarManagerImpl::FromWebState(webState);
DCHECK(infobarManager);
_autofillClient.reset(new autofill::ChromeAutofillClientIOS(
browserState, webState, infobarManager, self,
passwordGenerationManager));
autofill::AutofillDriverIOS::PrepareForWebStateWebFrameAndDelegate(
webState, _autofillClient.get(), self,
GetApplicationContext()->GetApplicationLocale(),
downloadEnabled
? autofill::AutofillManager::ENABLE_AUTOFILL_DOWNLOAD_MANAGER
: autofill::AutofillManager::DISABLE_AUTOFILL_DOWNLOAD_MANAGER);
_autofillAgent = autofillAgent;
}
return self;
}
- (instancetype)initWithBrowserState:(ios::ChromeBrowserState*)browserState
passwordGenerationManager:
(password_manager::PasswordGenerationManager*)
passwordGenerationManager
webState:(web::WebState*)webState {
AutofillAgent* autofillAgent =
[[AutofillAgent alloc] initWithPrefService:browserState->GetPrefs()
webState:webState];
return [self initWithBrowserState:browserState
webState:webState
autofillAgent:autofillAgent
passwordGenerationManager:passwordGenerationManager
downloadEnabled:YES];
}
- (void)dealloc {
DCHECK(!_autofillAgent); // detachFromWebController must have been called.
}
- (id<FormSuggestionProvider>)suggestionProvider {
return _autofillAgent;
}
- (void)detachFromWebState {
[_autofillAgent detachFromWebState];
_autofillAgent = nil;
_webState = nullptr;
}
- (void)setBaseViewController:(UIViewController*)baseViewController {
_autofillClient->SetBaseViewController(baseViewController);
}
// Return the AutofillManager associated to |frame|.
// If autofill in iframes is disabled, ignore the frame parameter and return the
// AutofillManager associated with |_webState|.
- (autofill::AutofillManager*)autofillManagerForFrame:(web::WebFrame*)frame {
if (!_webState) {
return nil;
}
if (autofill::switches::IsAutofillIFrameMessagingEnabled() && !frame) {
return nil;
}
return autofill::AutofillDriverIOS::FromWebStateAndWebFrame(_webState, frame)
->autofill_manager();
}
#pragma mark - AutofillClientIOSBridge
- (void)
showAutofillPopup:(const std::vector<autofill::Suggestion>&)popup_suggestions
popupDelegate:(const base::WeakPtr<AutofillPopupDelegate>&)delegate {
// Convert the suggestions into an NSArray for the keyboard.
NSMutableArray* suggestions = [[NSMutableArray alloc] init];
for (size_t i = 0; i < popup_suggestions.size(); ++i) {
// In the Chromium implementation the identifiers represent rows on the
// drop down of options. These include elements that aren't relevant to us
// such as separators ... see blink::WebAutofillClient::MenuItemIDSeparator
// for example. We can't include that enum because it's from WebKit, but
// fortunately almost all the entries we are interested in (profile or
// autofill entries) are zero or positive. Negative entries we are
// interested in is autofill::POPUP_ITEM_ID_CLEAR_FORM, used to show the
// "clear form" button and autofill::POPUP_ITEM_ID_GOOGLE_PAY_BRANDING, used
// to show the "Google Pay" branding.
NSString* value = nil;
NSString* displayDescription = nil;
if (popup_suggestions[i].frontend_id >= 0) {
// Value will contain the text to be filled in the selected element while
// displayDescription will contain a summary of the data to be filled in
// the other elements.
value = base::SysUTF16ToNSString(popup_suggestions[i].value);
displayDescription = base::SysUTF16ToNSString(popup_suggestions[i].label);
} else if (popup_suggestions[i].frontend_id ==
autofill::POPUP_ITEM_ID_CLEAR_FORM) {
// Show the "clear form" button.
value = base::SysUTF16ToNSString(popup_suggestions[i].value);
} else if (popup_suggestions[i].frontend_id ==
autofill::POPUP_ITEM_ID_GOOGLE_PAY_BRANDING) {
// Show "GPay branding" icon
value = base::SysUTF16ToNSString(popup_suggestions[i].value);
}
if (!value)
continue;
FormSuggestion* suggestion = [FormSuggestion
suggestionWithValue:value
displayDescription:displayDescription
icon:base::SysUTF16ToNSString(popup_suggestions[i].icon)
identifier:popup_suggestions[i].frontend_id];
[suggestions addObject:suggestion];
}
[_autofillAgent onSuggestionsReady:suggestions popupDelegate:delegate];
// The parameter is an optional callback.
if (delegate)
delegate->OnPopupShown();
}
- (void)hideAutofillPopup {
[_autofillAgent onSuggestionsReady:@[]
popupDelegate:base::WeakPtr<AutofillPopupDelegate>()];
}
#pragma mark - AutofillDriverIOSBridge
- (void)onFormDataFilled:(uint16_t)query_id
inFrame:(web::WebFrame*)frame
result:(const autofill::FormData&)result {
[_autofillAgent onFormDataFilled:result inFrame:frame];
autofill::AutofillManager* manager = [self autofillManagerForFrame:frame];
if (manager)
manager->OnDidFillAutofillFormData(result, base::TimeTicks::Now());
}
- (void)sendAutofillTypePredictionsToRenderer:
(const std::vector<autofill::FormDataPredictions>&)forms
toFrame:(web::WebFrame*)frame {
[_autofillAgent renderAutofillTypePredictions:forms inFrame:frame];
}
@end
......@@ -2,8 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#import "ios/chrome/browser/autofill/autofill_controller.h"
#include <memory>
#include <vector>
......@@ -219,15 +217,16 @@ class AutofillControllerTest : public ChromeWebTest {
// Histogram tester for these tests.
std::unique_ptr<base::HistogramTester> histogram_tester_;
std::unique_ptr<autofill::ChromeAutofillClientIOS> autofill_client_;
AutofillAgent* autofill_agent_;
// Retrieves suggestions according to form events.
TestSuggestionController* suggestion_controller_;
// Retrieves accessory views according to form events.
FormInputAccessoryMediator* accessory_mediator_;
// Manages autofill for a single page.
AutofillController* autofill_controller_;
DISALLOW_COPY_AND_ASSIGN(AutofillControllerTest);
};
......@@ -239,20 +238,28 @@ void AutofillControllerTest::SetUp() {
// default.
chrome_browser_state_->CreateWebDataService();
AutofillAgent* agent = [[AutofillAgent alloc]
IOSSecurityStateTabHelper::CreateForWebState(web_state());
autofill_agent_ = [[AutofillAgent alloc]
initWithPrefService:chrome_browser_state_->GetPrefs()
webState:web_state()];
suggestion_controller_ =
[[TestSuggestionController alloc] initWithWebState:web_state()
providers:@[ autofill_agent_ ]];
InfoBarManagerImpl::CreateForWebState(web_state());
IOSSecurityStateTabHelper::CreateForWebState(web_state());
autofill_controller_ = [[AutofillController alloc]
initWithBrowserState:chrome_browser_state_.get()
webState:web_state()
autofillAgent:agent
passwordGenerationManager:nullptr
downloadEnabled:NO];
suggestion_controller_ = [[TestSuggestionController alloc]
initWithWebState:web_state()
providers:@[ [autofill_controller_ suggestionProvider] ]];
infobars::InfoBarManager* infobar_manager =
InfoBarManagerImpl::FromWebState(web_state());
autofill_client_.reset(new autofill::ChromeAutofillClientIOS(
chrome_browser_state_.get(), web_state(), infobar_manager,
autofill_agent_,
/*password_generation_manager=*/nullptr));
std::string locale("en");
autofill::AutofillDriverIOS::PrepareForWebStateWebFrameAndDelegate(
web_state(), autofill_client_.get(), /*autofill_agent=*/nil, locale,
autofill::AutofillManager::DISABLE_AUTOFILL_DOWNLOAD_MANAGER);
accessory_mediator_ =
[[FormInputAccessoryMediator alloc] initWithConsumer:nil
webStateList:NULL];
......@@ -267,7 +274,6 @@ void AutofillControllerTest::SetUp() {
}
void AutofillControllerTest::TearDown() {
[autofill_controller_ detachFromWebState];
[suggestion_controller_ detachFromWebState];
ChromeWebTest::TearDown();
......
......@@ -5,19 +5,29 @@
#ifndef IOS_CHROME_BROWSER_AUTOFILL_AUTOFILL_TAB_HELPER_H_
#define IOS_CHROME_BROWSER_AUTOFILL_AUTOFILL_TAB_HELPER_H_
#include <memory>
#include "base/macros.h"
#import "ios/web/public/web_state/web_state_observer.h"
#import "ios/web/public/web_state/web_state_user_data.h"
@class AutofillController;
@class AutofillAgent;
@protocol FormSuggestionProvider;
@class UIViewController;
namespace autofill {
class ChromeAutofillClientIOS;
}
namespace password_manager {
class PasswordGenerationManager;
}
// Class binding an AutofillController to a WebState.
namespace ios {
class ChromeBrowserState;
}
// Class binding an instance of AutofillAgent to a WebState.
class AutofillTabHelper : public web::WebStateObserver,
public web::WebStateUserData<AutofillTabHelper> {
public:
......@@ -31,8 +41,7 @@ class AutofillTabHelper : public web::WebStateObserver,
// Sets a weak reference to the view controller used to present UI.
void SetBaseViewController(UIViewController* base_view_controller);
// Returns an object that can provide suggestions from the PasswordController.
// May return nil.
// Returns an object that can provide Autofill suggestions.
id<FormSuggestionProvider> GetSuggestionProvider();
private:
......@@ -43,8 +52,14 @@ class AutofillTabHelper : public web::WebStateObserver,
// web::WebStateObserver implementation.
void WebStateDestroyed(web::WebState* web_state) override;
// The Objective-C autofill controller instance.
__strong AutofillController* controller_;
// The BrowserState associated with this WebState.
ios::ChromeBrowserState* browser_state_;
// The Objective-C AutofillAgent instance.
__strong AutofillAgent* autofill_agent_;
// The iOS AutofillClient instance.
std::unique_ptr<autofill::ChromeAutofillClientIOS> autofill_client_;
DISALLOW_COPY_AND_ASSIGN(AutofillTabHelper);
};
......
......@@ -6,8 +6,12 @@
#include "base/logging.h"
#include "base/memory/ptr_util.h"
#import "ios/chrome/browser/autofill/autofill_controller.h"
#import "components/autofill/ios/browser/autofill_agent.h"
#include "components/autofill/ios/browser/autofill_driver_ios.h"
#include "ios/chrome/browser/application_context.h"
#include "ios/chrome/browser/browser_state/chrome_browser_state.h"
#include "ios/chrome/browser/infobars/infobar_manager_impl.h"
#import "ios/chrome/browser/ui/autofill/chrome_autofill_client_ios.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
......@@ -29,26 +33,37 @@ void AutofillTabHelper::CreateForWebState(
void AutofillTabHelper::SetBaseViewController(
UIViewController* base_view_controller) {
[controller_ setBaseViewController:base_view_controller];
autofill_client_->SetBaseViewController(base_view_controller);
}
id<FormSuggestionProvider> AutofillTabHelper::GetSuggestionProvider() {
return controller_.suggestionProvider;
return autofill_agent_;
}
AutofillTabHelper::AutofillTabHelper(
web::WebState* web_state,
password_manager::PasswordGenerationManager* password_generation_manager)
: controller_([[AutofillController alloc]
initWithBrowserState:ios::ChromeBrowserState::FromBrowserState(
web_state->GetBrowserState())
passwordGenerationManager:password_generation_manager
: browser_state_(ios::ChromeBrowserState::FromBrowserState(
web_state->GetBrowserState())),
autofill_agent_([[AutofillAgent alloc]
initWithPrefService:browser_state_->GetPrefs()
webState:web_state]) {
web_state->AddObserver(this);
infobars::InfoBarManager* infobar_manager =
InfoBarManagerImpl::FromWebState(web_state);
DCHECK(infobar_manager);
autofill_client_ = std::make_unique<autofill::ChromeAutofillClientIOS>(
browser_state_, web_state, infobar_manager, autofill_agent_,
password_generation_manager);
autofill::AutofillDriverIOS::PrepareForWebStateWebFrameAndDelegate(
web_state, autofill_client_.get(), autofill_agent_,
GetApplicationContext()->GetApplicationLocale(),
autofill::AutofillManager::ENABLE_AUTOFILL_DOWNLOAD_MANAGER);
}
void AutofillTabHelper::WebStateDestroyed(web::WebState* web_state) {
[controller_ detachFromWebState];
autofill_agent_ = nil;
web_state->RemoveObserver(this);
controller_ = nil;
}
......@@ -21,12 +21,12 @@
#import "components/autofill/ios/browser/autofill_agent.h"
#include "components/autofill/ios/browser/autofill_driver_ios.h"
#include "ios/chrome/browser/autofill/address_normalizer_factory.h"
#import "ios/chrome/browser/autofill/autofill_controller.h"
#import "ios/chrome/browser/autofill/form_suggestion_controller.h"
#include "ios/chrome/browser/browser_state/test_chrome_browser_state.h"
#include "ios/chrome/browser/chrome_paths.h"
#include "ios/chrome/browser/infobars/infobar_manager_impl.h"
#include "ios/chrome/browser/ssl/ios_security_state_tab_helper.h"
#import "ios/chrome/browser/ui/autofill/chrome_autofill_client_ios.h"
#include "ios/chrome/browser/web/chrome_web_client.h"
#import "ios/chrome/browser/web/chrome_web_test.h"
#include "ios/web/public/web_state/web_frame.h"
......@@ -113,8 +113,9 @@ class FormStructureBrowserTest
std::string FormStructuresToString(
const AutofillManager::FormStructureMap& forms);
FormSuggestionController* suggestionController_;
AutofillController* autofillController_;
std::unique_ptr<autofill::ChromeAutofillClientIOS> autofill_client_;
AutofillAgent* autofill_agent_;
FormSuggestionController* suggestion_controller_;
private:
base::test::ScopedFeatureList feature_list_;
......@@ -142,24 +143,29 @@ void FormStructureBrowserTest::SetUp() {
AddressNormalizerFactory::GetInstance();
IOSSecurityStateTabHelper::CreateForWebState(web_state());
InfoBarManagerImpl::CreateForWebState(web_state());
AutofillAgent* autofillAgent = [[AutofillAgent alloc]
autofill_agent_ = [[AutofillAgent alloc]
initWithPrefService:chrome_browser_state_->GetPrefs()
webState:web_state()];
suggestionController_ =
suggestion_controller_ =
[[FormSuggestionController alloc] initWithWebState:web_state()
providers:@[ autofillAgent ]];
autofillController_ = [[AutofillController alloc]
initWithBrowserState:chrome_browser_state_.get()
webState:web_state()
autofillAgent:autofillAgent
passwordGenerationManager:nullptr
downloadEnabled:NO];
providers:@[ autofill_agent_ ]];
InfoBarManagerImpl::CreateForWebState(web_state());
infobars::InfoBarManager* infobar_manager =
InfoBarManagerImpl::FromWebState(web_state());
autofill_client_.reset(new autofill::ChromeAutofillClientIOS(
chrome_browser_state_.get(), web_state(), infobar_manager,
autofill_agent_,
/*password_generation_manager=*/nullptr));
std::string locale("en");
autofill::AutofillDriverIOS::PrepareForWebStateWebFrameAndDelegate(
web_state(), autofill_client_.get(), /*autofill_agent=*/nil, locale,
autofill::AutofillManager::DISABLE_AUTOFILL_DOWNLOAD_MANAGER);
}
void FormStructureBrowserTest::TearDown() {
[autofillController_ detachFromWebState];
ChromeWebTest::TearDown();
}
......
......@@ -214,6 +214,7 @@ source_set("unit_tests") {
"//components/autofill/core/browser",
"//components/autofill/core/browser:test_support",
"//components/autofill/ios/browser",
"//components/leveldb_proto:leveldb_proto",
"//components/payments/core",
"//components/payments/core:test_support",
"//components/payments/mojom",
......
......@@ -14,10 +14,10 @@
#include "components/autofill/core/browser/autofill_test_utils.h"
#import "components/autofill/ios/browser/autofill_agent.h"
#include "components/autofill/ios/browser/autofill_driver_ios.h"
#import "ios/chrome/browser/autofill/autofill_controller.h"
#include "ios/chrome/browser/infobars/infobar_manager_impl.h"
#include "ios/chrome/browser/payments/payment_request_unittest_base.h"
#include "ios/chrome/browser/ui/autofill/card_unmask_prompt_view_bridge.h"
#import "ios/chrome/browser/ui/autofill/chrome_autofill_client_ios.h"
#import "ios/chrome/test/scoped_key_window.h"
#import "ios/web/public/test/fakes/crw_test_js_injection_receiver.h"
#include "ios/web/public/test/fakes/fake_web_frame.h"
......@@ -70,30 +70,29 @@ class PaymentRequestFullCardRequesterTest : public PaymentRequestUnitTestBase,
[[CRWTestJSInjectionReceiver alloc] init];
web_state()->SetJSInjectionReceiver(injectionReceiver);
AutofillAgent* autofill_agent =
[[AutofillAgent alloc] initWithPrefService:browser_state()->GetPrefs()
webState:web_state()];
InfoBarManagerImpl::CreateForWebState(web_state());
web_state()->CreateWebFramesManager();
auto main_frame = std::make_unique<web::FakeWebFrame>("main", true, GURL());
web_state()->AddWebFrame(std::move(main_frame));
autofill_controller_ =
[[AutofillController alloc] initWithBrowserState:browser_state()
webState:web_state()
autofillAgent:autofill_agent
passwordGenerationManager:nullptr
downloadEnabled:NO];
}
// PlatformTest:
void TearDown() override {
[autofill_controller_ detachFromWebState];
autofill_agent_ =
[[AutofillAgent alloc] initWithPrefService:browser_state()->GetPrefs()
webState:web_state()];
DoTearDown();
InfoBarManagerImpl::CreateForWebState(web_state());
infobars::InfoBarManager* infobar_manager =
InfoBarManagerImpl::FromWebState(web_state());
autofill_client_.reset(new autofill::ChromeAutofillClientIOS(
browser_state(), web_state(), infobar_manager, autofill_agent_,
/*password_generation_manager=*/nullptr));
std::string locale("en");
autofill::AutofillDriverIOS::PrepareForWebStateWebFrameAndDelegate(
web_state(), autofill_client_.get(), nil, locale,
autofill::AutofillManager::DISABLE_AUTOFILL_DOWNLOAD_MANAGER);
}
// Manages autofill for a single page.
AutofillController* autofill_controller_;
std::unique_ptr<autofill::ChromeAutofillClientIOS> autofill_client_;
AutofillAgent* autofill_agent_;
};
// Tests that the FullCardRequester presents and dismisses the card unmask
......
......@@ -18,7 +18,6 @@
#include "components/strings/grit/components_strings.h"
#include "components/unified_consent/feature.h"
#include "ios/chrome/browser/application_context.h"
#import "ios/chrome/browser/autofill/autofill_controller.h"
#include "ios/chrome/browser/browser_state/chrome_browser_state.h"
#include "ios/chrome/browser/chrome_url_constants.h"
#include "ios/chrome/browser/experimental_flags.h"
......
......@@ -15,7 +15,6 @@
#include "components/sync_preferences/pref_service_mock_factory.h"
#include "components/sync_preferences/pref_service_syncable.h"
#include "ios/chrome/browser/application_context.h"
#import "ios/chrome/browser/autofill/autofill_controller.h"
#include "ios/chrome/browser/browser_state/test_chrome_browser_state.h"
#include "ios/chrome/browser/experimental_flags.h"
#include "ios/chrome/browser/pref_names.h"
......
......@@ -396,44 +396,21 @@ fetchNonPasswordSuggestionsForFormWithName:(NSString*)formName
popupDelegate:
(const base::WeakPtr<autofill::AutofillPopupDelegate>&)
delegate {
NSMutableArray* formSuggestions = [[NSMutableArray alloc] init];
for (const auto& suggestion : suggestions) {
NSString* value = nil;
NSString* displayDescription = nil;
// frontend_id is greater than 0 for Autofill suggestions.
if (suggestion.frontend_id > 0) {
value = base::SysUTF16ToNSString(suggestion.value);
displayDescription = base::SysUTF16ToNSString(suggestion.label);
}
// Suggestions without values are typically special suggestions such as
// Autocomplete, clear form, or go to autofill settings. They are not
// supported by CWVAutofillController.
if (!value) {
continue;
}
NSString* icon = base::SysUTF16ToNSString(suggestion.icon);
NSInteger identifier = suggestion.frontend_id;
FormSuggestion* formSuggestion =
[FormSuggestion suggestionWithValue:value
displayDescription:displayDescription
icon:icon
identifier:identifier];
[formSuggestions addObject:formSuggestion];
}
[_autofillAgent onSuggestionsReady:formSuggestions popupDelegate:delegate];
if (delegate) {
delegate->OnPopupShown();
}
// frontend_id is > 0 for Autofill suggestions, == 0 for Autocomplete
// suggestions, and < 0 for special suggestions such as clear form, or go to
// autofill settings which are not supported by CWVAutofillController.
std::vector<autofill::Suggestion> filtered_suggestions;
std::copy_if(suggestions.begin(), suggestions.end(),
std::back_inserter(filtered_suggestions),
[](autofill::Suggestion suggestion) {
return suggestion.frontend_id > 0;
});
[_autofillAgent showAutofillPopup:filtered_suggestions
popupDelegate:delegate];
}
- (void)hideAutofillPopup {
[_autofillAgent
onSuggestionsReady:@[]
popupDelegate:base::WeakPtr<autofill::AutofillPopupDelegate>()];
[_autofillAgent hideAutofillPopup];
}
- (void)confirmSaveCreditCardLocally:(const autofill::CreditCard&)creditCard
......@@ -492,19 +469,14 @@ showUnmaskPromptForCard:(const autofill::CreditCard&)creditCard
#pragma mark - AutofillDriverIOSBridge
- (void)onFormDataFilled:(uint16_t)query_id
inFrame:(web::WebFrame*)frame
result:(const autofill::FormData&)result {
[_autofillAgent onFormDataFilled:result inFrame:frame];
autofill::AutofillManager* manager = [self autofillManagerForFrame:frame];
if (manager) {
manager->OnDidFillAutofillFormData(result, base::TimeTicks::Now());
}
- (void)fillFormData:(const autofill::FormData&)form
inFrame:(web::WebFrame*)frame {
[_autofillAgent fillFormData:form inFrame:frame];
}
- (void)sendAutofillTypePredictionsToRenderer:
- (void)fillFormDataPredictions:
(const std::vector<autofill::FormDataPredictions>&)forms
toFrame:(web::WebFrame*)frame {
inFrame:(web::WebFrame*)frame {
// Not supported.
}
......@@ -600,7 +572,6 @@ showUnmaskPromptForCard:(const autofill::CreditCard&)creditCard
- (void)webStateDestroyed:(web::WebState*)webState {
DCHECK_EQ(_webState, webState);
_formActivityObserverBridge.reset();
[_autofillAgent detachFromWebState];
_autofillClient.reset();
_webState->RemoveObserver(_webStateObserverBridge.get());
_webStateObserverBridge.reset();
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment