blob: e2eff93f465af037a351d1b39b43b9da86c77309 [file] [log] [blame]
// Copyright 2017 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/ui/fullscreen/fullscreen_controller_impl.h"
#include "base/memory/ptr_util.h"
#include "base/supports_user_data.h"
#include "ios/chrome/browser/browser_state/browser_state_otr_helper.h"
#include "ios/chrome/browser/browser_state/chrome_browser_state.h"
#import "ios/chrome/browser/main/browser.h"
#import "ios/chrome/browser/ui/broadcaster/chrome_broadcast_observer_bridge.h"
#import "ios/chrome/browser/ui/broadcaster/chrome_broadcaster.h"
#import "ios/chrome/browser/ui/fullscreen/fullscreen_features.h"
#import "ios/chrome/browser/ui/fullscreen/fullscreen_system_notification_observer.h"
#include "ios/public/provider/chrome/browser/chrome_browser_provider.h"
#import "ios/public/provider/chrome/browser/ui/fullscreen_provider.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
#endif
namespace {
// Key used to associate the stored FullscreenControllerContainer.
const char kFullscreenControllerContainerUserDataKey[] =
"fullscreen_controller_container";
// Container that manages storing the FullscreenControllerImpl to a UserData
// key.
//
// TODO(crbug.com/790886): Remove and subclass FullscreenController to
// BrowserUserData when the flag is turned on by default.
class FullscreenControllerContainer : public base::SupportsUserData::Data {
public:
FullscreenControllerContainer(Browser* browser)
: fullscreen_controller_(
std::make_unique<FullscreenControllerImpl>(browser)) {}
FullscreenControllerContainer()
: fullscreen_controller_(
std::make_unique<FullscreenControllerImpl>(nullptr)) {}
~FullscreenControllerContainer() override;
FullscreenControllerContainer(const FullscreenControllerContainer&) = delete;
FullscreenControllerContainer& operator=(
const FullscreenControllerContainer&) = delete;
FullscreenControllerContainer(FullscreenControllerContainer&&) = default;
FullscreenControllerContainer& operator=(FullscreenControllerContainer&&) =
default;
static FullscreenControllerContainer* GetForBrowserState(
ChromeBrowserState* browser_state);
static FullscreenControllerContainer* GetForBrowser(Browser* browser);
FullscreenController* GetFullscreenController();
private:
std::unique_ptr<FullscreenControllerImpl> fullscreen_controller_;
};
FullscreenControllerContainer::~FullscreenControllerContainer() {
fullscreen_controller_.reset();
}
FullscreenControllerContainer*
FullscreenControllerContainer::GetForBrowserState(
ChromeBrowserState* browser_state) {
ChromeBrowserState* original_browser_state = static_cast<ChromeBrowserState*>(
GetBrowserStateRedirectedInIncognito(browser_state));
FullscreenControllerContainer* fullscreen_controller_container =
static_cast<FullscreenControllerContainer*>(
original_browser_state->GetUserData(
kFullscreenControllerContainerUserDataKey));
if (!fullscreen_controller_container) {
fullscreen_controller_container = new FullscreenControllerContainer;
original_browser_state->SetUserData(
kFullscreenControllerContainerUserDataKey,
base::WrapUnique(fullscreen_controller_container));
}
return fullscreen_controller_container;
}
FullscreenControllerContainer* FullscreenControllerContainer::GetForBrowser(
Browser* browser) {
DCHECK(fullscreen::features::ShouldScopeFullscreenControllerToBrowser());
FullscreenControllerContainer* fullscreen_controller_container =
static_cast<FullscreenControllerContainer*>(
browser->GetUserData(kFullscreenControllerContainerUserDataKey));
if (!fullscreen_controller_container) {
fullscreen_controller_container =
new FullscreenControllerContainer(browser);
browser->SetUserData(kFullscreenControllerContainerUserDataKey,
base::WrapUnique(fullscreen_controller_container));
}
return fullscreen_controller_container;
}
FullscreenController* FullscreenControllerContainer::GetFullscreenController() {
return static_cast<FullscreenController*>(fullscreen_controller_.get());
}
} // namespace
// static
FullscreenController* FullscreenController::FromBrowser(Browser* browser) {
return FullscreenControllerContainer::GetForBrowser(browser)
->GetFullscreenController();
}
FullscreenController* FullscreenController::FromBrowserState(
ChromeBrowserState* browser_state) {
return FullscreenControllerContainer::GetForBrowserState(browser_state)
->GetFullscreenController();
}
FullscreenControllerImpl::FullscreenControllerImpl(Browser* browser)
: broadcaster_([[ChromeBroadcaster alloc] init]),
mediator_(this, &model_),
web_state_list_observer_(this, &model_, &mediator_),
fullscreen_browser_observer_(&web_state_list_observer_, browser),
bridge_([[ChromeBroadcastOberverBridge alloc] initWithObserver:&model_]),
notification_observer_([[FullscreenSystemNotificationObserver alloc]
initWithController:this
mediator:&mediator_]) {
DCHECK(broadcaster_);
[broadcaster_ addObserver:bridge_
forSelector:@selector(broadcastScrollViewSize:)];
[broadcaster_ addObserver:bridge_
forSelector:@selector(broadcastScrollViewContentSize:)];
[broadcaster_ addObserver:bridge_
forSelector:@selector(broadcastScrollViewContentInset:)];
[broadcaster_ addObserver:bridge_
forSelector:@selector(broadcastContentScrollOffset:)];
[broadcaster_ addObserver:bridge_
forSelector:@selector(broadcastScrollViewIsScrolling:)];
[broadcaster_ addObserver:bridge_
forSelector:@selector(broadcastScrollViewIsZooming:)];
[broadcaster_ addObserver:bridge_
forSelector:@selector(broadcastScrollViewIsDragging:)];
[broadcaster_ addObserver:bridge_
forSelector:@selector(broadcastCollapsedToolbarHeight:)];
[broadcaster_ addObserver:bridge_
forSelector:@selector(broadcastExpandedToolbarHeight:)];
[broadcaster_ addObserver:bridge_
forSelector:@selector(broadcastBottomToolbarHeight:)];
if (!fullscreen::features::ShouldScopeFullscreenControllerToBrowser()) {
ios::GetChromeBrowserProvider()
->GetFullscreenProvider()
->InitializeFullscreen(this);
}
}
FullscreenControllerImpl::~FullscreenControllerImpl() {
mediator_.Disconnect();
web_state_list_observer_.Disconnect();
[notification_observer_ disconnect];
[broadcaster_ removeObserver:bridge_
forSelector:@selector(broadcastScrollViewSize:)];
[broadcaster_ removeObserver:bridge_
forSelector:@selector(broadcastScrollViewContentSize:)];
[broadcaster_ removeObserver:bridge_
forSelector:@selector(broadcastScrollViewContentInset:)];
[broadcaster_ removeObserver:bridge_
forSelector:@selector(broadcastContentScrollOffset:)];
[broadcaster_ removeObserver:bridge_
forSelector:@selector(broadcastScrollViewIsScrolling:)];
[broadcaster_ removeObserver:bridge_
forSelector:@selector(broadcastScrollViewIsZooming:)];
[broadcaster_ removeObserver:bridge_
forSelector:@selector(broadcastScrollViewIsDragging:)];
[broadcaster_ removeObserver:bridge_
forSelector:@selector(broadcastCollapsedToolbarHeight:)];
[broadcaster_ removeObserver:bridge_
forSelector:@selector(broadcastExpandedToolbarHeight:)];
[broadcaster_ removeObserver:bridge_
forSelector:@selector(broadcastBottomToolbarHeight:)];
}
ChromeBroadcaster* FullscreenControllerImpl::broadcaster() {
return broadcaster_;
}
void FullscreenControllerImpl::SetWebStateList(WebStateList* web_state_list) {
web_state_list_observer_.SetWebStateList(web_state_list);
}
const WebStateList* FullscreenControllerImpl::GetWebStateList() const {
return web_state_list_observer_.GetWebStateList();
}
WebStateList* FullscreenControllerImpl::GetWebStateList() {
return web_state_list_observer_.GetWebStateList();
}
void FullscreenControllerImpl::AddObserver(
FullscreenControllerObserver* observer) {
mediator_.AddObserver(observer);
}
void FullscreenControllerImpl::RemoveObserver(
FullscreenControllerObserver* observer) {
mediator_.RemoveObserver(observer);
}
bool FullscreenControllerImpl::IsEnabled() const {
return model_.enabled();
}
void FullscreenControllerImpl::IncrementDisabledCounter() {
model_.IncrementDisabledCounter();
}
void FullscreenControllerImpl::DecrementDisabledCounter() {
model_.DecrementDisabledCounter();
}
bool FullscreenControllerImpl::ResizesScrollView() const {
return model_.ResizesScrollView();
}
void FullscreenControllerImpl::BrowserTraitCollectionChangedBegin() {
mediator_.SetIsBrowserTraitCollectionUpdating(true);
}
void FullscreenControllerImpl::BrowserTraitCollectionChangedEnd() {
mediator_.SetIsBrowserTraitCollectionUpdating(false);
}
CGFloat FullscreenControllerImpl::GetProgress() const {
return model_.progress();
}
UIEdgeInsets FullscreenControllerImpl::GetMinViewportInsets() const {
return model_.min_toolbar_insets();
}
UIEdgeInsets FullscreenControllerImpl::GetMaxViewportInsets() const {
return model_.max_toolbar_insets();
}
UIEdgeInsets FullscreenControllerImpl::GetCurrentViewportInsets() const {
return model_.current_toolbar_insets();
}
void FullscreenControllerImpl::EnterFullscreen() {
mediator_.EnterFullscreen();
}
void FullscreenControllerImpl::ExitFullscreen() {
mediator_.ExitFullscreen();
}
void FullscreenControllerImpl::ResizeHorizontalViewport() {
// TODO(crbug.com/1114054) this hack temporarily force change webview's
// width insets to trigger a width recomputation of its content. It will cause
// two relayouts.
mediator_.ResizeHorizontalInsets();
}