blob: 4e179c5d3b3b11aec79c118c16a157309d945b51 [file] [log] [blame]
// 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/ui/fullscreen_controller.h"
#import "ios/web/public/test/fakes/test_web_view_content_view.h"
#import "ios/web/public/web_state/ui/crw_web_view_content_view.h"
#import "ios/web/public/web_state/ui/crw_web_view_scroll_view_proxy.h"
#import "ios/web/web_state/ui/crw_web_controller.h"
#import "ios/web/web_state/ui/crw_web_view_proxy_impl.h"
#include "testing/platform_test.h"
#import "third_party/ocmock/OCMock/OCMock.h"
#include "third_party/ocmock/ocmock_extensions.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
#endif
namespace {
CGFloat kContentHeight = 5000.0;
CGFloat kHeaderHeight = 42.0;
}
@interface MockFullScreenControllerDelegate
: NSObject<FullScreenControllerDelegate>
@property(nonatomic, readonly) float currentPosition;
@property(nonatomic, assign) BOOL fakeIsTabWithIDCurrentFlag;
@end
@implementation MockFullScreenControllerDelegate
@synthesize currentPosition = currentPosition_;
@synthesize fakeIsTabWithIDCurrentFlag = fakeIsTabWithIDCurrentFlag_;
- (id)init {
if ((self = [super init])) {
currentPosition_ = 0.0;
fakeIsTabWithIDCurrentFlag_ = YES;
}
return self;
}
- (void)fullScreenController:(FullScreenController*)fullscreenController
drawHeaderViewFromOffset:(CGFloat)headerOffset
animate:(BOOL)animate {
currentPosition_ = headerOffset;
}
- (void)fullScreenController:(FullScreenController*)fullScreenController
drawHeaderViewFromOffset:(CGFloat)headerOffset
onWebViewProxy:(id<CRWWebViewProxy>)webViewProxy
changeTopContentPadding:(BOOL)changeTopContentPadding
scrollingToOffset:(CGFloat)contentOffset {
currentPosition_ = headerOffset;
webViewProxy.scrollViewProxy.contentOffset = CGPointMake(0.0f, contentOffset);
}
- (BOOL)isTabWithIDCurrent:(NSString*)sessionID {
return [self fakeIsTabWithIDCurrentFlag];
}
- (CGFloat)currentHeaderOffset {
return currentPosition_;
}
- (CGFloat)headerHeight {
return kHeaderHeight;
}
@end
namespace {
NSString* const kFakeSessionId = @"fake-session-id";
class FullscreenControllerTest : public PlatformTest {
protected:
void SetUp() override {
CGRect frame = CGRectMake(0.0, 0.0, 300.0, 900.0);
PlatformTest::SetUp();
scrollview_ = [[UIScrollView alloc] initWithFrame:frame];
scrollview_.contentInset = UIEdgeInsetsZero;
[GetWindow() addSubview:scrollview_];
CGRect contentSize = CGRectMake(0.0, 0.0, frame.size.width, kContentHeight);
scrollview_.contentSize = contentSize.size;
mockWebController_ =
[OCMockObject niceMockForClass:[CRWWebController class]];
mockDelegate_ = [[MockFullScreenControllerDelegate alloc] init];
mockWebView_ = [[UIView alloc] init];
mockContentView_ =
[[TestWebViewContentView alloc] initWithMockWebView:mockWebView_
scrollView:scrollview_];
webViewProxy_ =
[[CRWWebViewProxyImpl alloc] initWithWebController:mockWebController_];
[webViewProxy_ setContentView:mockContentView_];
webViewScrollViewProxy_ = [webViewProxy_ scrollViewProxy];
controller_ =
[[FullScreenController alloc] initWithDelegate:mockDelegate_
navigationManager:NULL
sessionID:kFakeSessionId];
DCHECK(controller_);
[webViewScrollViewProxy_ addObserver:controller_];
// Simulate a CRWWebControllerObserver callback.
[controller_ setWebViewProxy:webViewProxy_ controller:mockWebController_];
[controller_ moveHeaderToRestingPosition:YES];
UIView* awesome_view = [[UIView alloc] initWithFrame:contentSize];
[scrollview_ addSubview:awesome_view];
EXPECT_TRUE(IsHeaderVisible());
EXPECT_EQ(0.0f, webViewScrollViewProxy_.contentOffset.y);
}
void TearDown() override {
[webViewScrollViewProxy_ removeObserver:controller_];
[webViewScrollViewProxy_ setScrollView:nil];
[scrollview_ removeFromSuperview];
PlatformTest::TearDown();
}
void MoveMiddle() {
// Move somewhere in the middle.
CGFloat middle_point = kContentHeight / 2.0;
webViewScrollViewProxy_.contentOffset = CGPointMake(0.0, middle_point);
}
void MoveTop() {
webViewScrollViewProxy_.contentOffset = CGPointMake(0.0, -kHeaderHeight);
}
void MoveMiddleAndHide() {
MoveMiddle();
[controller_ moveHeaderToRestingPosition:NO];
EXPECT_TRUE(IsHeaderHidden());
}
UIWindow* GetWindow() {
UIWindow* window = [[UIApplication sharedApplication] keyWindow];
if (!window)
window = [[[UIApplication sharedApplication] windows] lastObject];
EXPECT_TRUE(window != nil);
return window;
}
bool IsHeaderVisible() { return [mockDelegate_ currentPosition] == 0.0; }
bool IsHeaderHidden() {
return [mockDelegate_ currentPosition] == kHeaderHeight;
}
// Adds |view| as a sub view to the underlying |scrollview_|.
void AddSubViewToScrollView(UIView* view) { [scrollview_ addSubview:view]; }
FullScreenController* controller_;
MockFullScreenControllerDelegate* mockDelegate_;
CRWWebViewScrollViewProxy* webViewScrollViewProxy_;
id mockWebView_;
id mockWebController_;
TestWebViewContentView* mockContentView_;
CRWWebViewProxyImpl* webViewProxy_;
private:
UIScrollView* scrollview_;
};
#pragma mark - Programmatic moves
TEST_F(FullscreenControllerTest, ForceHidden) {
[controller_ moveHeaderToRestingPosition:NO];
EXPECT_TRUE(IsHeaderHidden());
EXPECT_EQ(0.0, webViewScrollViewProxy_.contentOffset.y);
}
#pragma mark - Simulated user moves.
TEST_F(FullscreenControllerTest, LargeManualScrollUpHides) {
MoveMiddle();
[controller_ webViewScrollViewWillBeginDragging:webViewScrollViewProxy_];
CGFloat middle_point = webViewScrollViewProxy_.contentOffset.y;
// Move up a bit, multiple times
for (float i = 0.0; i < kHeaderHeight * 2.0; i++) {
webViewScrollViewProxy_.contentOffset = CGPointMake(0.0, middle_point + i);
}
[controller_ webViewScrollViewDidEndDragging:webViewScrollViewProxy_
willDecelerate:NO];
EXPECT_TRUE(IsHeaderHidden());
}
TEST_F(FullscreenControllerTest, PartialManualScrollUpHides) {
MoveMiddle();
[controller_ webViewScrollViewWillBeginDragging:webViewScrollViewProxy_];
CGFloat middle_point = webViewScrollViewProxy_.contentOffset.y;
// Move up a bit, multiple times
for (float i = 0.0; i < (kHeaderHeight * (2.0 / 3.0)); i++) {
webViewScrollViewProxy_.contentOffset = CGPointMake(0.0, middle_point + i);
}
[controller_ webViewScrollViewDidEndDragging:webViewScrollViewProxy_
willDecelerate:NO];
EXPECT_TRUE(IsHeaderHidden());
}
TEST_F(FullscreenControllerTest, SmallPartialManualScrollUpNoEffect) {
MoveMiddle();
[controller_ webViewScrollViewWillBeginDragging:webViewScrollViewProxy_];
CGFloat middle_point = webViewScrollViewProxy_.contentOffset.y;
// Move up a bit, multiple times
for (float i = 0.0; i < (kHeaderHeight / 3.0); i++) {
webViewScrollViewProxy_.contentOffset = CGPointMake(0.0, middle_point + i);
}
[controller_ webViewScrollViewDidEndDragging:webViewScrollViewProxy_
willDecelerate:NO];
EXPECT_TRUE(IsHeaderVisible());
}
TEST_F(FullscreenControllerTest, LargeManualScrollDownShows) {
MoveMiddleAndHide();
[controller_ webViewScrollViewWillBeginDragging:webViewScrollViewProxy_];
CGFloat middle_point = webViewScrollViewProxy_.contentOffset.y;
// Move down a bit, multiple times
for (float i = 0.0; i < kHeaderHeight * 2.0; i++) {
webViewScrollViewProxy_.contentOffset = CGPointMake(0.0, middle_point - i);
}
[controller_ webViewScrollViewDidEndDragging:webViewScrollViewProxy_
willDecelerate:NO];
EXPECT_TRUE(IsHeaderVisible());
}
TEST_F(FullscreenControllerTest, PartialManualScrollDownShows) {
MoveMiddleAndHide();
[controller_ webViewScrollViewWillBeginDragging:webViewScrollViewProxy_];
CGFloat middle_point = webViewScrollViewProxy_.contentOffset.y;
// Move down a bit, multiple times
for (float i = 0.0; i < (kHeaderHeight * (2.0 / 3.0)); i++) {
webViewScrollViewProxy_.contentOffset = CGPointMake(0.0, middle_point - i);
}
[controller_ webViewScrollViewDidEndDragging:webViewScrollViewProxy_
willDecelerate:NO];
EXPECT_TRUE(IsHeaderVisible());
}
TEST_F(FullscreenControllerTest, SmallPartialManualScrollDownNoEffect) {
MoveMiddleAndHide();
[controller_ webViewScrollViewWillBeginDragging:webViewScrollViewProxy_];
CGFloat middle_point = webViewScrollViewProxy_.contentOffset.y;
// Move up a bit, multiple times
for (float i = 0.0; i < (kHeaderHeight / 3.0); i++) {
webViewScrollViewProxy_.contentOffset = CGPointMake(0.0, middle_point - i);
}
[controller_ webViewScrollViewDidEndDragging:webViewScrollViewProxy_
willDecelerate:NO];
EXPECT_TRUE(IsHeaderHidden());
}
#pragma mark - Page load.
TEST_F(FullscreenControllerTest, NoHideOnEnable) {
[controller_ disableFullScreen];
webViewScrollViewProxy_.contentOffset = CGPointMake(0.0, 10.0);
EXPECT_TRUE(IsHeaderVisible());
[controller_ enableFullScreen];
EXPECT_TRUE(IsHeaderVisible());
}
TEST_F(FullscreenControllerTest, NoHideOnEnableDueToManualScroll) {
[controller_ disableFullScreen];
webViewScrollViewProxy_.contentOffset = CGPointMake(0.0, 1.0);
EXPECT_TRUE(IsHeaderVisible());
[controller_ webViewScrollViewWillBeginDragging:webViewScrollViewProxy_];
webViewScrollViewProxy_.contentOffset = CGPointMake(0.0, 10.0);
EXPECT_TRUE(IsHeaderVisible());
[controller_ webViewScrollViewDidEndDragging:webViewScrollViewProxy_
willDecelerate:NO];
[controller_ enableFullScreen];
EXPECT_TRUE(IsHeaderVisible());
}
#pragma mark - Keyboard.
TEST_F(FullscreenControllerTest, KeyboardAppearanceOnNonFullscreenPage) {
// Add a textfield.
UITextField* textField = [[UITextField alloc] init];
AddSubViewToScrollView(textField);
EXPECT_TRUE(IsHeaderVisible());
// Show the keyboard.
[textField becomeFirstResponder];
EXPECT_TRUE(IsHeaderVisible());
// Hide the keyboard.
[textField resignFirstResponder];
EXPECT_TRUE(IsHeaderVisible());
}
// TODO(lliabraa): Fails on Xcode 6 simulator (crbug.com/392433).
#if TARGET_IPHONE_SIMULATOR
#define MAYBE_KeyboardAppearanceOnFullscreenPage \
KeyboardAppearanceOnFullscreenPage
#else
#define MAYBE_KeyboardAppearanceOnFullscreenPage \
KeyboardAppearanceOnFullscreenPage
#endif
TEST_F(FullscreenControllerTest, MAYBE_KeyboardAppearanceOnFullscreenPage) {
// Scroll a bit to hide the toolbar.
MoveMiddleAndHide();
// Add a textfield.
UITextField* textField = [[UITextField alloc] init];
AddSubViewToScrollView(textField);
EXPECT_TRUE(IsHeaderHidden());
// Show the keyboard.
[textField becomeFirstResponder];
EXPECT_TRUE(IsHeaderVisible());
// Hide the keyboard.
[textField resignFirstResponder];
// Toolbars are never auto-hidden.
EXPECT_FALSE(IsHeaderHidden());
}
// TODO(lliabraa): Fails on Xcode 6 simulator (crbug.com/392433).
#if TARGET_IPHONE_SIMULATOR
#define MAYBE_KeyboardStayOnUserScrollOnNonFullscreenPage \
KeyboardStayOnUserScrollOnNonFullscreenPage
#else
#define MAYBE_KeyboardStayOnUserScrollOnNonFullscreenPage \
KeyboardStayOnUserScrollOnNonFullscreenPage
#endif
TEST_F(FullscreenControllerTest,
MAYBE_KeyboardStayOnUserScrollOnNonFullscreenPage) {
// Add a textfield.
UITextField* textField = [[UITextField alloc] init];
AddSubViewToScrollView(textField);
EXPECT_TRUE(IsHeaderVisible());
// Show the keyboard.
[textField becomeFirstResponder];
EXPECT_TRUE(IsHeaderVisible());
// Scroll.
[controller_ webViewScrollViewWillBeginDragging:webViewScrollViewProxy_];
webViewScrollViewProxy_.contentOffset = CGPointMake(0.0, 100.0);
[controller_ webViewScrollViewDidEndDragging:webViewScrollViewProxy_
willDecelerate:NO];
EXPECT_TRUE(IsHeaderVisible());
// Hide the keyboard.
[textField resignFirstResponder];
EXPECT_TRUE(IsHeaderVisible());
}
} // namespace