Commit 559fe24a authored by sczs's avatar sczs Committed by Commit Bot

[ios] Stores presented InfobarsCoordinators in a Dictionary.

- Adds infobarManagerWillChange consumer method to clean up
this dictionary when the manager/webstate has changed.
- Changes childCoordinatorStopped so it sends the InfobarType.
- Updates unittests.

Bug: 961343
Change-Id: I275ba5a5f3091202b7eff3d40777ac782c438946
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1731141Reviewed-by: default avatarPeter Lee <pkl@chromium.org>
Commit-Queue: Sergio Collazos <sczs@chromium.org>
Cr-Commit-Position: refs/heads/master@{#684238}
parent d73a1f67
......@@ -86,7 +86,8 @@
self.bannerIsPresenting = YES;
[self.infobarCoordinator presentInfobarBannerAnimated:NO completion:nil];
}
- (void)infobarManagerWillChange {
}
- (void)setUserInteractionEnabled:(BOOL)enabled {
}
- (void)updateLayoutAnimated:(BOOL)animated {
......
......@@ -21,6 +21,13 @@ class InfoBarContainerIOS : public infobars::InfoBarContainer {
id<InfobarContainerConsumer> legacyConsumer);
~InfoBarContainerIOS() override;
// Changes the InfoBarManager for which this container is showing infobars.
// This will hide all current infobars, remove them from the container, add
// the infobars from |infobar_manager|, and show them all. If
// |infobar_manager| is nullptr, it will hide all current Infobars but won't
// be able to present new ones.
void ChangeInfoBarManager(infobars::InfoBarManager* infobar_manager);
protected:
void PlatformSpecificAddInfoBar(infobars::InfoBar* infobar,
size_t position) override;
......
......@@ -24,6 +24,12 @@ InfoBarContainerIOS::~InfoBarContainerIOS() {
RemoveAllInfoBarsForDestruction();
}
void InfoBarContainerIOS::ChangeInfoBarManager(
infobars::InfoBarManager* infobar_manager) {
[consumer_ infobarManagerWillChange];
InfoBarContainer::ChangeInfoBarManager(infobar_manager);
}
void InfoBarContainerIOS::PlatformSpecificAddInfoBar(infobars::InfoBar* infobar,
size_t position) {
InfoBarIOS* infobar_ios = static_cast<InfoBarIOS*>(infobar);
......
......@@ -18,6 +18,7 @@ source_set("infobars") {
"//ios/chrome/browser",
"//ios/chrome/browser/infobars",
"//ios/chrome/browser/infobars:badge",
"//ios/chrome/browser/infobars:public",
"//ios/chrome/browser/ui/commands",
"//ios/chrome/browser/ui/coordinators:chrome_coordinators",
"//ios/chrome/browser/ui/fullscreen",
......
......@@ -68,7 +68,7 @@
// from memory.
self.delegate->RemoveInfoBar();
_confirmInfobarDelegate = nil;
[self.infobarContainer childCoordinatorStopped];
[self.infobarContainer childCoordinatorStopped:self.infobarType];
}
}
......
......@@ -97,7 +97,7 @@
// from memory.
self.delegate->RemoveInfoBar();
_passwordInfoBarDelegate = nil;
[self.infobarContainer childCoordinatorStopped];
[self.infobarContainer childCoordinatorStopped:self.infobarType];
}
}
......
......@@ -7,15 +7,15 @@
#import <Foundation/Foundation.h>
enum class InfobarType;
// Protocol for the InfobarCoordinators to communicate with the InfobarContainer
// Coordinator.
@protocol InfobarContainer
// Informs the InfobarContainer Coordinator that its child coordinator has
// stopped.
// TODO(crbug.com/961343): Add support to indicate which Coordinator has
// stopped.
- (void)childCoordinatorStopped;
// Informs the InfobarContainer Coordinator that its child coordinator of type
// |infobarType| has stopped.
- (void)childCoordinatorStopped:(InfobarType)infobarType;
@end
......
......@@ -15,6 +15,11 @@
// Adds |infoBarDelegate|'s Infobar to the InfobarContainer.
- (void)addInfoBarWithDelegate:(id<InfobarUIDelegate>)infoBarDelegate;
// Informs InfobarContainerConsumer that the backing infobarManager will change.
// This most likely means that the WebState is changing and a new set of
// Infobars will/may be presented.
- (void)infobarManagerWillChange;
// Sets the Infobar container user interaction to |enabled|.
- (void)setUserInteractionEnabled:(BOOL)enabled;
......
......@@ -8,6 +8,7 @@
#import "base/mac/foundation_util.h"
#include "ios/chrome/browser/infobars/infobar_manager_impl.h"
#import "ios/chrome/browser/infobars/infobar_type.h"
#import "ios/chrome/browser/ui/commands/application_commands.h"
#import "ios/chrome/browser/ui/commands/command_dispatcher.h"
#import "ios/chrome/browser/ui/fullscreen/fullscreen_controller_factory.h"
......@@ -43,6 +44,10 @@
// TODO(crbug.com/927064): Remove this once the legacy container is no longer
// needed.
@property(nonatomic, assign) BOOL legacyContainerFullscrenSupportDisabled;
// infobarCoordinators holds all InfobarCoordinators this ContainerCoordinator
// can display.
@property(nonatomic, strong)
NSMutableDictionary<NSNumber*, InfobarCoordinator*>* infobarCoordinators;
@end
......@@ -56,6 +61,7 @@
browserState:browserState];
if (self) {
_webStateList = webStateList;
_infobarCoordinators = [NSMutableDictionary dictionary];
}
return self;
}
......@@ -134,10 +140,27 @@
- (void)dismissInfobarBannerAnimated:(BOOL)animated
completion:(void (^)())completion {
DCHECK(IsInfobarUIRebootEnabled());
InfobarCoordinator* infobarCoordinator =
static_cast<InfobarCoordinator*>(self.activeChildCoordinator);
[infobarCoordinator dismissInfobarBannerAnimated:animated
completion:completion];
for (InfobarCoordinator* infobarCoordinator in
[self.infobarCoordinators allValues]) {
if (infobarCoordinator.infobarBannerState !=
InfobarBannerPresentationState::NotPresented) {
// Since only one Banner can be presented at any time, dismiss it.
[infobarCoordinator dismissInfobarBannerAnimated:animated
completion:completion];
return;
}
}
// If no banner was presented make sure the completion block still runs.
if (completion)
completion();
}
#pragma mark - ChromeCoordinator
- (MutableCoordinatorArray*)childCoordinators {
return static_cast<MutableCoordinatorArray*>(
[self.infobarCoordinators allValues]);
}
#pragma mark - Accessors
......@@ -159,9 +182,15 @@
- (InfobarBannerPresentationState)infobarBannerState {
DCHECK(IsInfobarUIRebootEnabled());
InfobarCoordinator* infobarCoordinator =
static_cast<InfobarCoordinator*>(self.activeChildCoordinator);
return infobarCoordinator.infobarBannerState;
for (InfobarCoordinator* infobarCoordinator in
[self.infobarCoordinators allValues]) {
if (infobarCoordinator.infobarBannerState !=
InfobarBannerPresentationState::NotPresented) {
// Since only one Banner can be presented at any time, early return.
return infobarCoordinator.infobarBannerState;
}
}
return InfobarBannerPresentationState::NotPresented;
}
#pragma mark - InfobarConsumer
......@@ -171,6 +200,10 @@
InfobarCoordinator* infobarCoordinator =
static_cast<InfobarCoordinator*>(infoBarDelegate);
NSNumber* infobarKey =
[NSNumber numberWithInt:static_cast<int>(infoBarDelegate.infobarType)];
self.infobarCoordinators[infobarKey] = infobarCoordinator;
// Present the InfobarBanner, and set the Coordinator and View hierarchies.
[infobarCoordinator start];
infobarCoordinator.badgeDelegate = self.mediator;
......@@ -181,7 +214,6 @@
if (!infobarCoordinator.bannerWasPresented)
[infobarCoordinator presentInfobarBannerAnimated:YES completion:nil];
self.infobarViewController = infobarCoordinator.bannerViewController;
[self.childCoordinators addObject:infobarCoordinator];
// Dismisses the presented InfobarCoordinator banner after
// kInfobarBannerPresentationDurationInSeconds seconds.
......@@ -195,6 +227,10 @@
}
}
- (void)infobarManagerWillChange {
self.infobarCoordinators = [NSMutableDictionary dictionary];
}
- (void)setUserInteractionEnabled:(BOOL)enabled {
[self.infobarViewController.view setUserInteractionEnabled:enabled];
}
......@@ -207,18 +243,17 @@
#pragma mark InfobarContainer
- (void)childCoordinatorStopped {
- (void)childCoordinatorStopped:(InfobarType)infobarType {
DCHECK(IsInfobarUIRebootEnabled());
// TODO(crbug.com/961343): When more than one InfobarCoordinator can exist
// concurrently, delete only the one that stopped.
[self.childCoordinators removeAllObjects];
NSNumber* infobarKey = [NSNumber numberWithInt:static_cast<int>(infobarType)];
[self.infobarCoordinators removeObjectForKey:infobarKey];
}
#pragma mark - InfobarCommands
- (void)displayModalInfobar {
InfobarCoordinator* infobarCoordinator =
static_cast<InfobarCoordinator*>(self.activeChildCoordinator);
NSArray* allCoordinators = [self.infobarCoordinators allValues];
InfobarCoordinator* infobarCoordinator = [allCoordinators lastObject];
[infobarCoordinator presentInfobarModal];
}
......
......@@ -134,6 +134,22 @@ class InfobarContainerCoordinatorTest : public PlatformTest {
coordinator_, std::move(infobar_delegate_)));
}
// Adds an Infobar to the InfobarManager, triggering an InfobarBanner
// presentation.
void AddSecondInfobar() {
// Setup the InfobarCoordinator and InfobarDelegate.
TestInfoBarDelegate* test_infobar_delegate =
new TestInfoBarDelegate(@"Title 2");
InfobarConfirmCoordinator* coordinator = [[InfobarConfirmCoordinator alloc]
initWithInfoBarDelegate:test_infobar_delegate
type:InfobarType::kInfobarTypePasswordSave];
std::unique_ptr<ConfirmInfoBarDelegate> infobar_delegate =
std::unique_ptr<ConfirmInfoBarDelegate>(test_infobar_delegate);
GetInfobarManager()->AddInfoBar(
std::make_unique<InfoBarIOS>(coordinator, std::move(infobar_delegate)));
}
void AddSecondWebstate() {
std::unique_ptr<web::TestWebState> second_web_state =
std::make_unique<web::TestWebState>();
......@@ -455,10 +471,9 @@ TEST_F(InfobarContainerCoordinatorTest,
InfobarBannerPresentationState::NotPresented);
}
// Tests that the ChildCoordinator is deleted once it stops.
// TODO(crbug.com/961343): Update test when more than one Child Coordinator is
// supported.
TEST_F(InfobarContainerCoordinatorTest, TestInfobarChildCoordinatorCount) {
// Tests that the ChildCoordinators are deleted once the Webstate is closed.
TEST_F(InfobarContainerCoordinatorTest,
TestInfobarChildCoordinatorCountWebstate) {
AddInfobar();
EXPECT_TRUE(base::test::ios::WaitUntilConditionOrTimeout(
......@@ -482,6 +497,25 @@ TEST_F(InfobarContainerCoordinatorTest, TestInfobarChildCoordinatorCount) {
InfobarBannerPresentationState::NotPresented;
}));
AddSecondInfobar();
EXPECT_TRUE(base::test::ios::WaitUntilConditionOrTimeout(
base::test::ios::kWaitForUIElementTimeout, ^bool {
return infobar_container_coordinator_.infobarBannerState ==
InfobarBannerPresentationState::Presented;
}));
ASSERT_EQ(infobar_container_coordinator_.infobarBannerState,
InfobarBannerPresentationState::Presented);
ASSERT_EQ(NSUInteger(2),
infobar_container_coordinator_.childCoordinators.count);
[infobar_container_coordinator_ dismissInfobarBannerAnimated:NO
completion:nil];
ASSERT_TRUE(base::test::ios::WaitUntilConditionOrTimeout(
base::test::ios::kWaitForUIElementTimeout, ^bool {
return infobar_container_coordinator_.infobarBannerState ==
InfobarBannerPresentationState::NotPresented;
}));
web_state_list_->CloseWebStateAt(0, 0);
ASSERT_TRUE(base::test::ios::WaitUntilConditionOrTimeout(
......@@ -494,3 +528,53 @@ TEST_F(InfobarContainerCoordinatorTest, TestInfobarChildCoordinatorCount) {
ASSERT_EQ(NSUInteger(0),
infobar_container_coordinator_.childCoordinators.count);
}
// Tests that the ChildCoordinators are deleted once they stop.
TEST_F(InfobarContainerCoordinatorTest, TestInfobarChildCoordinatorCountStop) {
AddInfobar();
EXPECT_TRUE(base::test::ios::WaitUntilConditionOrTimeout(
base::test::ios::kWaitForUIElementTimeout, ^bool {
return infobar_container_coordinator_.infobarBannerState ==
InfobarBannerPresentationState::Presented;
}));
ASSERT_EQ(infobar_container_coordinator_.infobarBannerState,
InfobarBannerPresentationState::Presented);
ASSERT_EQ(NSUInteger(1),
infobar_container_coordinator_.childCoordinators.count);
ASSERT_EQ(infobar_container_coordinator_.infobarBannerState,
InfobarBannerPresentationState::Presented);
[infobar_container_coordinator_ dismissInfobarBannerAnimated:NO
completion:nil];
ASSERT_TRUE(base::test::ios::WaitUntilConditionOrTimeout(
base::test::ios::kWaitForUIElementTimeout, ^bool {
return infobar_container_coordinator_.infobarBannerState ==
InfobarBannerPresentationState::NotPresented;
}));
AddSecondInfobar();
EXPECT_TRUE(base::test::ios::WaitUntilConditionOrTimeout(
base::test::ios::kWaitForUIElementTimeout, ^bool {
return infobar_container_coordinator_.infobarBannerState ==
InfobarBannerPresentationState::Presented;
}));
ASSERT_EQ(infobar_container_coordinator_.infobarBannerState,
InfobarBannerPresentationState::Presented);
ASSERT_EQ(NSUInteger(2),
infobar_container_coordinator_.childCoordinators.count);
[infobar_container_coordinator_ dismissInfobarBannerAnimated:NO
completion:nil];
ASSERT_TRUE(base::test::ios::WaitUntilConditionOrTimeout(
base::test::ios::kWaitForUIElementTimeout, ^bool {
return infobar_container_coordinator_.infobarBannerState ==
InfobarBannerPresentationState::NotPresented;
}));
// Stop the first Coordinator.
[coordinator_ stop];
ASSERT_EQ(NSUInteger(1),
infobar_container_coordinator_.childCoordinators.count);
}
......@@ -92,6 +92,11 @@ const CGFloat kAlphaChangeAnimationDuration = 0.35;
]];
}
- (void)infobarManagerWillChange {
// NO-OP. This legacy container doesn't need to clean up any state after the
// InfobarManager has changed.
}
- (void)setUserInteractionEnabled:(BOOL)enabled {
[self.view setUserInteractionEnabled:enabled];
}
......
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