Commit d798e544 authored by Kurt Horimoto's avatar Kurt Horimoto Committed by Commit Bot

[iOS] Support showing the passwords settings for infobar modals.

This CL updates PasswordInfobarModalInteractionHandler to take Browser
upon construction so that it can use the command dispatcher to open the
passwords settings when selected in the password infobar modal view.

Additionally, this CL adds default behavior to the show settings command
for use when there is not a base view controller to send with the
command.  OverlayRequestCoordinators' base view controllers are their
corresponding OverlayContainerViewController, which only should be used
to present things from within that OverlayPresenter's modality.  The
default behavior is to instead use the current BVC as the base controller
if one is not provided.

Bug: 1030357
Change-Id: I9a3d18cad6425aed47c005ce52ec7119b4a9059c
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2001727
Commit-Queue: Kurt Horimoto <kkhorimoto@chromium.org>
Reviewed-by: default avatarSergio Collazos <sczs@chromium.org>
Reviewed-by: default avatarMark Cogan <marq@chromium.org>
Cr-Commit-Position: refs/heads/master@{#733784}
parent 7d62b9fc
...@@ -20,7 +20,7 @@ void AttachInfobarOverlayBrowserAgent(Browser* browser) { ...@@ -20,7 +20,7 @@ void AttachInfobarOverlayBrowserAgent(Browser* browser) {
InfobarOverlayBrowserAgent* browser_agent = InfobarOverlayBrowserAgent* browser_agent =
InfobarOverlayBrowserAgent::FromBrowser(browser); InfobarOverlayBrowserAgent::FromBrowser(browser);
browser_agent->AddInfobarInteractionHandler( browser_agent->AddInfobarInteractionHandler(
std::make_unique<PasswordInfobarInteractionHandler>()); std::make_unique<PasswordInfobarInteractionHandler>(browser));
// TODO(crbug.com/1030357): Add InfobarInteractionHandlers for each // TODO(crbug.com/1030357): Add InfobarInteractionHandlers for each
// InfobarType when implemented. // InfobarType when implemented.
} }
...@@ -21,10 +21,12 @@ source_set("passwords") { ...@@ -21,10 +21,12 @@ source_set("passwords") {
"//ios/chrome/browser/infobars/overlays:util", "//ios/chrome/browser/infobars/overlays:util",
"//ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers", "//ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers",
"//ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/common", "//ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/common",
"//ios/chrome/browser/main:public",
"//ios/chrome/browser/overlays", "//ios/chrome/browser/overlays",
"//ios/chrome/browser/overlays/public/infobar_banner", "//ios/chrome/browser/overlays/public/infobar_banner",
"//ios/chrome/browser/overlays/public/infobar_modal", "//ios/chrome/browser/overlays/public/infobar_modal",
"//ios/chrome/browser/passwords:infobar_delegates", "//ios/chrome/browser/passwords:infobar_delegates",
"//ios/chrome/browser/ui/commands",
] ]
} }
...@@ -46,15 +48,21 @@ source_set("unit_tests") { ...@@ -46,15 +48,21 @@ source_set("unit_tests") {
"//ios/chrome/browser/infobars:public", "//ios/chrome/browser/infobars:public",
"//ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/passwords/test", "//ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/passwords/test",
"//ios/chrome/browser/infobars/test", "//ios/chrome/browser/infobars/test",
"//ios/chrome/browser/main:test_support",
"//ios/chrome/browser/overlays", "//ios/chrome/browser/overlays",
"//ios/chrome/browser/overlays/public/common/infobars", "//ios/chrome/browser/overlays/public/common/infobars",
"//ios/chrome/browser/overlays/public/infobar_modal", "//ios/chrome/browser/overlays/public/infobar_modal",
"//ios/chrome/browser/overlays/test", "//ios/chrome/browser/overlays/test",
"//ios/chrome/browser/passwords:infobar_delegates", "//ios/chrome/browser/passwords:infobar_delegates",
"//ios/chrome/browser/passwords/test", "//ios/chrome/browser/passwords/test",
"//ios/chrome/browser/ui/commands",
"//ios/chrome/browser/ui/infobars/test", "//ios/chrome/browser/ui/infobars/test",
"//ios/chrome/browser/web_state_list",
"//ios/chrome/browser/web_state_list:test_support",
"//ios/chrome/test:test_support", "//ios/chrome/test:test_support",
"//ios/web/public/test",
"//ios/web/public/test/fakes", "//ios/web/public/test/fakes",
"//testing/gtest", "//testing/gtest",
"//third_party/ocmock",
] ]
} }
...@@ -9,11 +9,13 @@ ...@@ -9,11 +9,13 @@
#import "ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/infobar_interaction_handler.h" #import "ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/infobar_interaction_handler.h"
class Browser;
// An InfobarInteractionHandler that updates the model layer for interaction // An InfobarInteractionHandler that updates the model layer for interaction
// events with the UI for password infobars. // events with the UI for password infobars.
class PasswordInfobarInteractionHandler : public InfobarInteractionHandler { class PasswordInfobarInteractionHandler : public InfobarInteractionHandler {
public: public:
PasswordInfobarInteractionHandler(); PasswordInfobarInteractionHandler(Browser* browser);
~PasswordInfobarInteractionHandler() override; ~PasswordInfobarInteractionHandler() override;
}; };
......
...@@ -13,12 +13,13 @@ ...@@ -13,12 +13,13 @@
#error "This file requires ARC support." #error "This file requires ARC support."
#endif #endif
PasswordInfobarInteractionHandler::PasswordInfobarInteractionHandler() PasswordInfobarInteractionHandler::PasswordInfobarInteractionHandler(
Browser* browser)
: InfobarInteractionHandler( : InfobarInteractionHandler(
InfobarType::kInfobarTypePasswordSave, InfobarType::kInfobarTypePasswordSave,
std::make_unique<PasswordInfobarBannerInteractionHandler>(), std::make_unique<PasswordInfobarBannerInteractionHandler>(),
/*sheet_handler=*/nullptr, /*sheet_handler=*/nullptr,
std::make_unique<PasswordInfobarModalInteractionHandler>()) {} std::make_unique<PasswordInfobarModalInteractionHandler>(browser)) {}
PasswordInfobarInteractionHandler::~PasswordInfobarInteractionHandler() = PasswordInfobarInteractionHandler::~PasswordInfobarInteractionHandler() =
default; default;
...@@ -7,12 +7,14 @@ ...@@ -7,12 +7,14 @@
#import "ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/common/infobar_modal_interaction_handler.h" #import "ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/common/infobar_modal_interaction_handler.h"
@protocol ApplicationSettingsCommands;
class Browser;
class IOSChromeSavePasswordInfoBarDelegate; class IOSChromeSavePasswordInfoBarDelegate;
class PasswordInfobarModalInteractionHandler class PasswordInfobarModalInteractionHandler
: public InfobarModalInteractionHandler { : public InfobarModalInteractionHandler {
public: public:
PasswordInfobarModalInteractionHandler(); PasswordInfobarModalInteractionHandler(Browser* browser);
~PasswordInfobarModalInteractionHandler() override; ~PasswordInfobarModalInteractionHandler() override;
// Instructs the handler to update the credentials with |username| and // Instructs the handler to update the credentials with |username| and
...@@ -43,6 +45,12 @@ class PasswordInfobarModalInteractionHandler ...@@ -43,6 +45,12 @@ class PasswordInfobarModalInteractionHandler
// InfobarInteractionHandler::Handler: // InfobarInteractionHandler::Handler:
void InfobarVisibilityChanged(InfoBarIOS* infobar, bool visible) override; void InfobarVisibilityChanged(InfoBarIOS* infobar, bool visible) override;
protected:
// TODO(crbug.com/1040653): This class is only subclassed as a mock for use in
// tests. This constructor can be removed once the password infobar delegate
// is refactored for testing and this class no longer needs to be mocked.
PasswordInfobarModalInteractionHandler();
private: private:
// InfobarModalInteractionHandler: // InfobarModalInteractionHandler:
std::unique_ptr<InfobarModalOverlayRequestCallbackInstaller> std::unique_ptr<InfobarModalOverlayRequestCallbackInstaller>
...@@ -50,6 +58,9 @@ class PasswordInfobarModalInteractionHandler ...@@ -50,6 +58,9 @@ class PasswordInfobarModalInteractionHandler
// Returns the password delegate from |infobar|. // Returns the password delegate from |infobar|.
IOSChromeSavePasswordInfoBarDelegate* GetDelegate(InfoBarIOS* infobar); IOSChromeSavePasswordInfoBarDelegate* GetDelegate(InfoBarIOS* infobar);
// Dispatcher used to open the password settings.
id<ApplicationSettingsCommands> settings_command_handler_ = nil;
}; };
#endif // IOS_CHROME_BROWSER_INFOBARS_OVERLAYS_BROWSER_AGENT_INTERACTION_HANDLERS_PASSWORDS_PASSWORD_INFOBAR_MODAL_INTERACTION_HANDLER_H_ #endif // IOS_CHROME_BROWSER_INFOBARS_OVERLAYS_BROWSER_AGENT_INTERACTION_HANDLERS_PASSWORDS_PASSWORD_INFOBAR_MODAL_INTERACTION_HANDLER_H_
...@@ -6,7 +6,10 @@ ...@@ -6,7 +6,10 @@
#include "ios/chrome/browser/infobars/infobar_ios.h" #include "ios/chrome/browser/infobars/infobar_ios.h"
#import "ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/passwords/password_infobar_modal_overlay_request_callback_installer.h" #import "ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/passwords/password_infobar_modal_overlay_request_callback_installer.h"
#include "ios/chrome/browser/main/browser.h"
#import "ios/chrome/browser/passwords/ios_chrome_save_password_infobar_delegate.h" #import "ios/chrome/browser/passwords/ios_chrome_save_password_infobar_delegate.h"
#include "ios/chrome/browser/ui/commands/application_commands.h"
#import "ios/chrome/browser/ui/commands/command_dispatcher.h"
#if !defined(__has_feature) || !__has_feature(objc_arc) #if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support." #error "This file requires ARC support."
...@@ -15,6 +18,14 @@ ...@@ -15,6 +18,14 @@
PasswordInfobarModalInteractionHandler:: PasswordInfobarModalInteractionHandler::
PasswordInfobarModalInteractionHandler() = default; PasswordInfobarModalInteractionHandler() = default;
PasswordInfobarModalInteractionHandler::PasswordInfobarModalInteractionHandler(
Browser* browser)
: settings_command_handler_(
HandlerForProtocol(browser->GetCommandDispatcher(),
ApplicationSettingsCommands)) {
DCHECK(settings_command_handler_);
}
PasswordInfobarModalInteractionHandler:: PasswordInfobarModalInteractionHandler::
~PasswordInfobarModalInteractionHandler() = default; ~PasswordInfobarModalInteractionHandler() = default;
...@@ -34,7 +45,7 @@ void PasswordInfobarModalInteractionHandler::NeverSaveCredentials( ...@@ -34,7 +45,7 @@ void PasswordInfobarModalInteractionHandler::NeverSaveCredentials(
void PasswordInfobarModalInteractionHandler::PresentPasswordsSettings( void PasswordInfobarModalInteractionHandler::PresentPasswordsSettings(
InfoBarIOS* infobar) { InfoBarIOS* infobar) {
// TODO(crbug.com/1033154): Show the passwords settings. [settings_command_handler_ showSavedPasswordsSettingsFromViewController:nil];
} }
void PasswordInfobarModalInteractionHandler::PerformMainAction( void PasswordInfobarModalInteractionHandler::PerformMainAction(
......
...@@ -7,10 +7,19 @@ ...@@ -7,10 +7,19 @@
#include "base/test/scoped_feature_list.h" #include "base/test/scoped_feature_list.h"
#include "components/infobars/core/infobar_feature.h" #include "components/infobars/core/infobar_feature.h"
#import "ios/chrome/browser/infobars/test/fake_infobar_ios.h" #import "ios/chrome/browser/infobars/test/fake_infobar_ios.h"
#import "ios/chrome/browser/main/test_browser.h"
#import "ios/chrome/browser/overlays/public/overlay_request_queue.h" #import "ios/chrome/browser/overlays/public/overlay_request_queue.h"
#import "ios/chrome/browser/passwords/test/mock_ios_chrome_save_passwords_infobar_delegate.h" #import "ios/chrome/browser/passwords/test/mock_ios_chrome_save_passwords_infobar_delegate.h"
#import "ios/chrome/browser/ui/commands/application_commands.h"
#import "ios/chrome/browser/ui/commands/command_dispatcher.h"
#import "ios/chrome/browser/ui/infobars/test/fake_infobar_ui_delegate.h" #import "ios/chrome/browser/ui/infobars/test/fake_infobar_ui_delegate.h"
#import "ios/chrome/browser/web_state_list/web_state_list.h"
#import "ios/chrome/browser/web_state_list/web_state_opener.h"
#import "ios/web/public/test/fakes/test_web_state.h"
#include "ios/web/public/test/web_task_environment.h"
#include "testing/platform_test.h" #include "testing/platform_test.h"
#import "third_party/ocmock/OCMock/OCMock.h"
#import "third_party/ocmock/gtest_support.h"
#if !defined(__has_feature) || !__has_feature(objc_arc) #if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support." #error "This file requires ARC support."
...@@ -20,11 +29,23 @@ ...@@ -20,11 +29,23 @@
class PasswordInfobarModalInteractionHandlerTest : public PlatformTest { class PasswordInfobarModalInteractionHandlerTest : public PlatformTest {
public: public:
PasswordInfobarModalInteractionHandlerTest() PasswordInfobarModalInteractionHandlerTest()
: infobar_( : mock_command_receiver_(
OCMStrictProtocolMock(@protocol(ApplicationSettingsCommands))),
infobar_(
[[FakeInfobarUIDelegate alloc] init], [[FakeInfobarUIDelegate alloc] init],
MockIOSChromeSavePasswordInfoBarDelegate::Create(@"username", MockIOSChromeSavePasswordInfoBarDelegate::Create(@"username",
@"password")) { @"password")) {
scoped_feature_list_.InitWithFeatures({kIOSInfobarUIReboot}, {}); scoped_feature_list_.InitWithFeatures({kIOSInfobarUIReboot}, {});
[browser_.GetCommandDispatcher()
startDispatchingToTarget:mock_command_receiver_
forProtocol:@protocol(ApplicationSettingsCommands)];
handler_ =
std::make_unique<PasswordInfobarModalInteractionHandler>(&browser_);
}
~PasswordInfobarModalInteractionHandlerTest() override {
[browser_.GetCommandDispatcher()
stopDispatchingToTarget:mock_command_receiver_];
EXPECT_OCMOCK_VERIFY(mock_command_receiver_);
} }
MockIOSChromeSavePasswordInfoBarDelegate& mock_delegate() { MockIOSChromeSavePasswordInfoBarDelegate& mock_delegate() {
...@@ -34,8 +55,11 @@ class PasswordInfobarModalInteractionHandlerTest : public PlatformTest { ...@@ -34,8 +55,11 @@ class PasswordInfobarModalInteractionHandlerTest : public PlatformTest {
protected: protected:
base::test::ScopedFeatureList scoped_feature_list_; base::test::ScopedFeatureList scoped_feature_list_;
web::WebTaskEnvironment task_environment_;
TestBrowser browser_;
id mock_command_receiver_ = nil;
InfoBarIOS infobar_; InfoBarIOS infobar_;
PasswordInfobarModalInteractionHandler handler_; std::unique_ptr<PasswordInfobarModalInteractionHandler> handler_;
}; };
// Tests that UpdateCredentials() forwards the call to the mock delegate. // Tests that UpdateCredentials() forwards the call to the mock delegate.
...@@ -43,13 +67,20 @@ TEST_F(PasswordInfobarModalInteractionHandlerTest, UpdateCredentials) { ...@@ -43,13 +67,20 @@ TEST_F(PasswordInfobarModalInteractionHandlerTest, UpdateCredentials) {
NSString* username = @"username"; NSString* username = @"username";
NSString* password = @"password"; NSString* password = @"password";
EXPECT_CALL(mock_delegate(), UpdateCredentials(username, password)); EXPECT_CALL(mock_delegate(), UpdateCredentials(username, password));
handler_.UpdateCredentials(&infobar_, username, password); handler_->UpdateCredentials(&infobar_, username, password);
} }
// Tests that NeverSaveCredentials() forwards the call to the mock delegate. // Tests that NeverSaveCredentials() forwards the call to the mock delegate.
TEST_F(PasswordInfobarModalInteractionHandlerTest, NeverSaveCredentials) { TEST_F(PasswordInfobarModalInteractionHandlerTest, NeverSaveCredentials) {
EXPECT_CALL(mock_delegate(), Cancel()); EXPECT_CALL(mock_delegate(), Cancel());
handler_.NeverSaveCredentials(&infobar_); handler_->NeverSaveCredentials(&infobar_);
}
// Tests that PresentPasswordsSettings() forwards the call to the mock delegate.
TEST_F(PasswordInfobarModalInteractionHandlerTest, PresentPasswordsSettings) {
OCMExpect([mock_command_receiver_
showSavedPasswordsSettingsFromViewController:nil]);
handler_->PresentPasswordsSettings(&infobar_);
} }
// Tests PerformMainAction() calls Accept() on the mock delegate and resets // Tests PerformMainAction() calls Accept() on the mock delegate and resets
...@@ -57,7 +88,7 @@ TEST_F(PasswordInfobarModalInteractionHandlerTest, NeverSaveCredentials) { ...@@ -57,7 +88,7 @@ TEST_F(PasswordInfobarModalInteractionHandlerTest, NeverSaveCredentials) {
TEST_F(PasswordInfobarModalInteractionHandlerTest, MainAction) { TEST_F(PasswordInfobarModalInteractionHandlerTest, MainAction) {
ASSERT_FALSE(infobar_.accepted()); ASSERT_FALSE(infobar_.accepted());
EXPECT_CALL(mock_delegate(), Accept()).WillOnce(testing::Return(true)); EXPECT_CALL(mock_delegate(), Accept()).WillOnce(testing::Return(true));
handler_.PerformMainAction(&infobar_); handler_->PerformMainAction(&infobar_);
EXPECT_TRUE(infobar_.accepted()); EXPECT_TRUE(infobar_.accepted());
} }
...@@ -65,7 +96,7 @@ TEST_F(PasswordInfobarModalInteractionHandlerTest, MainAction) { ...@@ -65,7 +96,7 @@ TEST_F(PasswordInfobarModalInteractionHandlerTest, MainAction) {
// InfobarDismissed() on the mock delegate. // InfobarDismissed() on the mock delegate.
TEST_F(PasswordInfobarModalInteractionHandlerTest, InfobarVisibilityChanged) { TEST_F(PasswordInfobarModalInteractionHandlerTest, InfobarVisibilityChanged) {
EXPECT_CALL(mock_delegate(), InfobarPresenting(/*automatic=*/false)); EXPECT_CALL(mock_delegate(), InfobarPresenting(/*automatic=*/false));
handler_.InfobarVisibilityChanged(&infobar_, true); handler_->InfobarVisibilityChanged(&infobar_, true);
EXPECT_CALL(mock_delegate(), InfobarDismissed()); EXPECT_CALL(mock_delegate(), InfobarDismissed());
handler_.InfobarVisibilityChanged(&infobar_, false); handler_->InfobarVisibilityChanged(&infobar_, false);
} }
...@@ -482,6 +482,11 @@ enum class EnterTabSwitcherSnapshotResult { ...@@ -482,6 +482,11 @@ enum class EnterTabSwitcherSnapshotResult {
// TODO(crbug.com/779791) : Remove show settings commands from MainController. // TODO(crbug.com/779791) : Remove show settings commands from MainController.
- (void)showSavedPasswordsSettingsFromViewController: - (void)showSavedPasswordsSettingsFromViewController:
(UIViewController*)baseViewController { (UIViewController*)baseViewController {
if (!baseViewController) {
// TODO(crbug.com/779791): Don't pass base view controller through
// dispatched command.
baseViewController = [self.mainController currentBVC];
}
DCHECK(!self.signinInteractionCoordinator.isSettingsViewPresented); DCHECK(!self.signinInteractionCoordinator.isSettingsViewPresented);
if (self.settingsNavigationController) { if (self.settingsNavigationController) {
[self.settingsNavigationController [self.settingsNavigationController
......
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