Commit ac5bc014 authored by edchin's avatar edchin Committed by Commit bot

[ios] Use web_state_list in web_contents_mediator

This CL enables the user to select a tab in the tab switcher
and the new tab is reflected immediately in the currently
open tab container.

BUG=none

Review-Url: https://codereview.chromium.org/2780423003
Cr-Commit-Position: refs/heads/master@{#462776}
parent 18bf204d
...@@ -15,6 +15,8 @@ source_set("web_contents") { ...@@ -15,6 +15,8 @@ source_set("web_contents") {
deps = [ deps = [
":web_contents_ui", ":web_contents_ui",
"//ios/clean/chrome/browser/ui/context_menu", "//ios/clean/chrome/browser/ui/context_menu",
"//ios/shared/chrome/browser/tabs",
"//ios/shared/chrome/browser/ui/browser_list",
"//ios/shared/chrome/browser/ui/coordinators", "//ios/shared/chrome/browser/ui/coordinators",
"//ios/web", "//ios/web",
"//ui/base", "//ui/base",
...@@ -46,6 +48,8 @@ source_set("unit_tests") { ...@@ -46,6 +48,8 @@ source_set("unit_tests") {
"//base", "//base",
"//base/test:test_support", "//base/test:test_support",
"//ios/chrome/test/base", "//ios/chrome/test/base",
"//ios/shared/chrome/browser/tabs",
"//ios/shared/chrome/browser/tabs:test_support",
"//ios/web:test_support", "//ios/web:test_support",
"//testing/gtest", "//testing/gtest",
] ]
......
...@@ -8,23 +8,24 @@ ...@@ -8,23 +8,24 @@
#import <Foundation/Foundation.h> #import <Foundation/Foundation.h>
@protocol WebContentsConsumer; @protocol WebContentsConsumer;
class WebStateList;
namespace web {
class WebState;
}
// A mediator object that provides the relevant properties of a web state // A mediator object that provides the relevant properties of a web state
// to a consumer. // to a consumer.
@interface WebContentsMediator : NSObject @interface WebContentsMediator : NSObject
// The WebState whose properties this object mediates. This can change during // Updates to this webStateList are mediated to the consumer. This can change
// the lifetime of this object and may be null. // during the lifetime of this object and may be nil.
@property(nonatomic, assign) web::WebState* webState; @property(nonatomic, assign) WebStateList* webStateList;
// The consumer for this object. This can change during the lifetime of this // The consumer for this object. This can change during the lifetime of this
// object and may be nil. // object and may be nil.
@property(nonatomic, weak) id<WebContentsConsumer> consumer; @property(nonatomic, weak) id<WebContentsConsumer> consumer;
// Stops observing all objects and sets the active webState's webUsageEnabled
// to false.
- (void)disconnect;
@end @end
#endif // IOS_CLEAN_CHROME_BROWSER_UI_WEB_CONTENTS_WEB_CONTENTS_MEDIATOR_H_ #endif // IOS_CLEAN_CHROME_BROWSER_UI_WEB_CONTENTS_WEB_CONTENTS_MEDIATOR_H_
...@@ -4,7 +4,10 @@ ...@@ -4,7 +4,10 @@
#import "ios/clean/chrome/browser/ui/web_contents/web_contents_mediator.h" #import "ios/clean/chrome/browser/ui/web_contents/web_contents_mediator.h"
#include "base/memory/ptr_util.h"
#import "ios/clean/chrome/browser/ui/web_contents/web_contents_consumer.h" #import "ios/clean/chrome/browser/ui/web_contents/web_contents_consumer.h"
#import "ios/shared/chrome/browser/tabs/web_state_list.h"
#import "ios/shared/chrome/browser/tabs/web_state_list_observer_bridge.h"
#import "ios/web/public/navigation_manager.h" #import "ios/web/public/navigation_manager.h"
#include "ios/web/public/web_state/web_state.h" #include "ios/web/public/web_state/web_state.h"
#include "ui/base/page_transition_types.h" #include "ui/base/page_transition_types.h"
...@@ -14,32 +17,96 @@ ...@@ -14,32 +17,96 @@
#error "This file requires ARC support." #error "This file requires ARC support."
#endif #endif
@implementation WebContentsMediator @interface WebContentsMediator ()<WebStateListObserving>
@synthesize webState = _webState; @end
@implementation WebContentsMediator {
std::unique_ptr<WebStateListObserverBridge> _webStateListObserver;
}
@synthesize webStateList = _webStateList;
@synthesize consumer = _consumer; @synthesize consumer = _consumer;
- (void)setWebState:(web::WebState*)webState { - (void)dealloc {
if (_webState) [self disconnect];
_webState->SetWebUsageEnabled(false); }
#pragma mark - Public
_webState = webState; - (void)disconnect {
if (!self.webState) if (!self.webStateList) {
return; return;
}
[self disableWebUsage:self.webStateList->GetActiveWebState()];
self.webStateList = nullptr;
}
self.webState->SetWebUsageEnabled(true); #pragma mark - Properties
if (!self.webState->GetNavigationManager()->GetItemCount()) {
web::NavigationManager::WebLoadParams params( - (void)setWebStateList:(WebStateList*)webStateList {
GURL("https://dev.chromium.org/")); if (_webStateList) {
params.transition_type = ui::PAGE_TRANSITION_TYPED; _webStateList->RemoveObserver(_webStateListObserver.get());
self.webState->GetNavigationManager()->LoadURLWithParams(params); _webStateListObserver.reset();
}
_webStateList = webStateList;
if (!_webStateList) {
return;
}
_webStateListObserver = base::MakeUnique<WebStateListObserverBridge>(self);
_webStateList->AddObserver(_webStateListObserver.get());
if (_webStateList->GetActiveWebState()) {
[self updateConsumerWithWebState:_webStateList->GetActiveWebState()];
} }
[self.consumer contentViewDidChange:self.webState->GetView()];
} }
- (void)setConsumer:(id<WebContentsConsumer>)consumer { - (void)setConsumer:(id<WebContentsConsumer>)consumer {
_consumer = consumer; _consumer = consumer;
if (self.webState) if (self.webStateList && self.webStateList->GetActiveWebState()) {
[self.consumer contentViewDidChange:self.webState->GetView()]; [self updateConsumerWithWebState:self.webStateList->GetActiveWebState()];
}
}
#pragma mark - WebStateListObserving
- (void)webStateList:(WebStateList*)webStateList
didChangeActiveWebState:(web::WebState*)newWebState
oldWebState:(web::WebState*)oldWebState
atIndex:(int)atIndex
userAction:(BOOL)userAction {
[self disableWebUsage:oldWebState];
[self updateConsumerWithWebState:newWebState];
}
#pragma mark - Private
- (void)disableWebUsage:(web::WebState*)webState {
if (webState) {
webState->SetWebUsageEnabled(false);
}
}
// Sets |webState| webUsageEnabled and updates the consumer's contentView.
- (void)updateConsumerWithWebState:(web::WebState*)webState {
UIView* updatedView = nil;
if (webState) {
webState->SetWebUsageEnabled(true);
updatedView = webState->GetView();
// PLACEHOLDER: This navigates the page since the omnibox is not yet
// hooked up.
[self navigateToDefaultPage:webState];
}
if (self.consumer) {
[self.consumer contentViewDidChange:updatedView];
}
}
// PLACEHOLDER: This navigates the page since the omnibox is not yet hooked up.
- (void)navigateToDefaultPage:(web::WebState*)webState {
if (!webState->GetNavigationManager()->GetItemCount()) {
web::NavigationManager::WebLoadParams params(
GURL("https://dev.chromium.org/"));
params.transition_type = ui::PAGE_TRANSITION_TYPED;
webState->GetNavigationManager()->LoadURLWithParams(params);
}
} }
@end @end
...@@ -6,6 +6,9 @@ ...@@ -6,6 +6,9 @@
#include "base/memory/ptr_util.h" #include "base/memory/ptr_util.h"
#import "ios/clean/chrome/browser/ui/web_contents/web_contents_consumer.h" #import "ios/clean/chrome/browser/ui/web_contents/web_contents_consumer.h"
#include "ios/shared/chrome/browser/tabs/fake_web_state_list_delegate.h"
#include "ios/shared/chrome/browser/tabs/web_state_list.h"
#import "ios/shared/chrome/browser/tabs/web_state_list_observer_bridge.h"
#import "ios/web/public/test/fakes/test_navigation_manager.h" #import "ios/web/public/test/fakes/test_navigation_manager.h"
#import "ios/web/public/test/fakes/test_web_state.h" #import "ios/web/public/test/fakes/test_web_state.h"
#include "testing/gtest/include/gtest/gtest.h" #include "testing/gtest/include/gtest/gtest.h"
...@@ -50,62 +53,103 @@ class StubNavigationManager : public web::TestNavigationManager { ...@@ -50,62 +53,103 @@ class StubNavigationManager : public web::TestNavigationManager {
class WebContentsMediatorTest : public PlatformTest { class WebContentsMediatorTest : public PlatformTest {
public: public:
WebContentsMediatorTest() { WebContentsMediatorTest() {
auto navigation_manager = base::MakeUnique<StubNavigationManager>(); mediator_ = [[WebContentsMediator alloc] init];
navigation_manager_ = navigation_manager.get(); SetUpWebStateList();
navigation_manager_->SetItemCount(0);
web_state_.SetNavigationManager(std::move(navigation_manager));
} }
~WebContentsMediatorTest() override { [mediator_ disconnect]; }
protected: protected:
StubNavigationManager* navigation_manager_; void SetUpWebStateList() {
web::TestWebState web_state_; web_state_list_ = base::MakeUnique<WebStateList>(&web_state_list_delegate_);
};
for (int i = 0; i < 2; i++) {
auto web_state = base::MakeUnique<web::TestWebState>();
auto navigation_manager = base::MakeUnique<StubNavigationManager>();
navigation_manager->SetItemCount(0);
web_state->SetView([[UIView alloc] init]);
web_state->SetNavigationManager(std::move(navigation_manager));
web_state_list_->InsertWebState(i, std::move(web_state));
}
web_state_list_->ActivateWebStateAt(0);
}
web::TestWebState* GetWebStateAt(int position) {
return static_cast<web::TestWebState*>(
web_state_list_->GetWebStateAt(position));
}
TEST_F(WebContentsMediatorTest, TestSetWebUsageEnabled) { StubNavigationManager* GetNavigationManagerAt(int position) {
WebContentsMediator* mediator = [[WebContentsMediator alloc] init]; return static_cast<StubNavigationManager*>(
GetWebStateAt(position)->GetNavigationManager());
}
mediator.webState = &web_state_; WebContentsMediator* mediator_;
// Setting the webState should set webUsageEnabled. std::unique_ptr<WebStateList> web_state_list_;
EXPECT_EQ(true, web_state_.IsWebUsageEnabled()); FakeWebStateListDelegate web_state_list_delegate_;
// Expect that with zero navigation items, a url will be loaded. };
EXPECT_EQ(true, navigation_manager_->GetHasLoadedUrl());
mediator.webState = nullptr; // Tests that webUsage is disabled when mediator is disconnected.
// The previous webState should now have web usage disabled. TEST_F(WebContentsMediatorTest, TestDisconnect) {
EXPECT_EQ(false, web_state_.IsWebUsageEnabled()); mediator_.webStateList = web_state_list_.get();
web::TestWebState* web_state = GetWebStateAt(0);
EXPECT_TRUE(web_state->IsWebUsageEnabled());
[mediator_ disconnect];
EXPECT_FALSE(web_state->IsWebUsageEnabled());
} }
TEST_F(WebContentsMediatorTest, TestNoLoadURL) { // Tests that both the old and new active web states have WebUsageEnabled
WebContentsMediator* mediator = [[WebContentsMediator alloc] init]; // updated.
TEST_F(WebContentsMediatorTest, TestWebUsageEnabled) {
mediator_.webStateList = web_state_list_.get();
web::TestWebState* first_web_state = GetWebStateAt(0);
web::TestWebState* second_web_state = GetWebStateAt(1);
first_web_state->SetWebUsageEnabled(true);
second_web_state->SetWebUsageEnabled(false);
web_state_list_->ActivateWebStateAt(1);
EXPECT_FALSE(first_web_state->IsWebUsageEnabled());
EXPECT_TRUE(second_web_state->IsWebUsageEnabled());
}
navigation_manager_->SetItemCount(2); // Tests that a URL is loaded if the new active web state has zero navigation
// items.
TEST_F(WebContentsMediatorTest, TestURLHasLoaded) {
mediator_.webStateList = web_state_list_.get();
StubNavigationManager* navigation_manager = GetNavigationManagerAt(1);
navigation_manager->SetItemCount(0);
web_state_list_->ActivateWebStateAt(1);
EXPECT_TRUE(navigation_manager->GetHasLoadedUrl());
}
mediator.webState = &web_state_; // Tests that a URL is not loaded if the new active web state has some
// Expect that with nonzero navigation items, no url will be loaded. // navigation items.
EXPECT_EQ(false, navigation_manager_->GetHasLoadedUrl()); TEST_F(WebContentsMediatorTest, TestNoLoadURL) {
mediator_.webStateList = web_state_list_.get();
StubNavigationManager* navigation_manager = GetNavigationManagerAt(1);
navigation_manager->SetItemCount(2);
web_state_list_->ActivateWebStateAt(1);
EXPECT_FALSE(navigation_manager->GetHasLoadedUrl());
} }
TEST_F(WebContentsMediatorTest, TestSetWebStateFirst) { // Tests that the consumer is updated immediately once both consumer and
WebContentsMediator* mediator = [[WebContentsMediator alloc] init]; // webStateList are set. This test sets webStateList first.
TEST_F(WebContentsMediatorTest, TestConsumerViewIsSetWebStateListFirst) {
StubContentsConsumer* consumer = [[StubContentsConsumer alloc] init]; StubContentsConsumer* consumer = [[StubContentsConsumer alloc] init];
mediator_.webStateList = web_state_list_.get();
mediator.webState = &web_state_; web::TestWebState* web_state = GetWebStateAt(0);
mediator.consumer = consumer; EXPECT_NE(web_state->GetView(), consumer.contentView);
mediator_.consumer = consumer;
// Setting the consumer after the web state should still have the consumer EXPECT_EQ(web_state->GetView(), consumer.contentView);
// called.
EXPECT_EQ(web_state_.GetView(), consumer.contentView);
} }
TEST_F(WebContentsMediatorTest, TestSetConsumerFirst) { // Tests that the consumer is updated immediately once both consumer and
WebContentsMediator* mediator = [[WebContentsMediator alloc] init]; // webStateList are set. This test sets consumer first.
TEST_F(WebContentsMediatorTest, TestConsumerViewIsSetConsumerFirst) {
StubContentsConsumer* consumer = [[StubContentsConsumer alloc] init]; StubContentsConsumer* consumer = [[StubContentsConsumer alloc] init];
mediator_.consumer = consumer;
mediator.consumer = consumer; web::TestWebState* web_state = GetWebStateAt(0);
mediator.webState = &web_state_; EXPECT_NE(web_state->GetView(), consumer.contentView);
mediator_.webStateList = web_state_list_.get();
// Setting the web_state after the consumer should trigger a call to the EXPECT_EQ(web_state->GetView(), consumer.contentView);
// consumer.
EXPECT_EQ(web_state_.GetView(), consumer.contentView);
}
} }
} // namespace
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#import "ios/clean/chrome/browser/ui/context_menu/web_context_menu_coordinator.h" #import "ios/clean/chrome/browser/ui/context_menu/web_context_menu_coordinator.h"
#import "ios/clean/chrome/browser/ui/web_contents/web_contents_mediator.h" #import "ios/clean/chrome/browser/ui/web_contents/web_contents_mediator.h"
#import "ios/clean/chrome/browser/ui/web_contents/web_contents_view_controller.h" #import "ios/clean/chrome/browser/ui/web_contents/web_contents_view_controller.h"
#import "ios/shared/chrome/browser/ui/browser_list/browser.h"
#import "ios/shared/chrome/browser/ui/coordinators/browser_coordinator+internal.h" #import "ios/shared/chrome/browser/ui/coordinators/browser_coordinator+internal.h"
#include "ios/web/public/web_state/web_state.h" #include "ios/web/public/web_state/web_state.h"
#import "ios/web/public/web_state/web_state_delegate_bridge.h" #import "ios/web/public/web_state/web_state_delegate_bridge.h"
...@@ -37,22 +38,22 @@ ...@@ -37,22 +38,22 @@
} }
- (void)setWebState:(web::WebState*)webState { - (void)setWebState:(web::WebState*)webState {
// PLACEHOLDER: The web state delegate will be set by another object, and
// this coordinator will not need to know the active web state.
_webState = webState; _webState = webState;
self.webState->SetDelegate(_webStateDelegate.get()); self.webState->SetDelegate(_webStateDelegate.get());
self.mediator.webState = self.webState;
} }
- (void)start { - (void)start {
self.viewController = [[WebContentsViewController alloc] init]; self.viewController = [[WebContentsViewController alloc] init];
self.mediator.consumer = self.viewController; self.mediator.consumer = self.viewController;
self.mediator.webStateList = &self.browser->web_state_list();
[super start]; [super start];
} }
- (void)stop { - (void)stop {
[super stop]; [super stop];
// PLACEHOLDER: This is how the webUsageEnabled is set to false. Find a [self.mediator disconnect];
// better way in the future.
self.mediator.webState = nullptr;
} }
- (void)childCoordinatorDidStart:(BrowserCoordinator*)childCoordinator { - (void)childCoordinatorDidStart:(BrowserCoordinator*)childCoordinator {
......
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