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

[iOS] Broadcast the toolbar UI state.

This CL adds a new ChromeBroadcastObserver method for the toolbar
height.  It also creates FullscreenUIState, an object that holds the
broadcast properties for toolbar UI.

Bug: 785625
Cq-Include-Trybots: master.tryserver.chromium.mac:ios-simulator-cronet;master.tryserver.chromium.mac:ios-simulator-full-configs
Change-Id: Ibebff64db6c33ec5e7e0ca6eb24a96973a533b36
Reviewed-on: https://chromium-review.googlesource.com/773443
Commit-Queue: Kurt Horimoto <kkhorimoto@chromium.org>
Reviewed-by: default avatarKurt Horimoto <kkhorimoto@chromium.org>
Reviewed-by: default avatarMark Cogan <marq@chromium.org>
Cr-Commit-Position: refs/heads/master@{#519526}
parent 42b2aa7c
...@@ -345,6 +345,7 @@ source_set("ui_internal") { ...@@ -345,6 +345,7 @@ source_set("ui_internal") {
"//ios/chrome/browser/ui/tab_switcher", "//ios/chrome/browser/ui/tab_switcher",
"//ios/chrome/browser/ui/tabs:coordinator", "//ios/chrome/browser/ui/tabs:coordinator",
"//ios/chrome/browser/ui/tabs/requirements", "//ios/chrome/browser/ui/tabs/requirements",
"//ios/chrome/browser/ui/toolbar:toolbar_ui",
"//ios/chrome/browser/ui/toolbar/public:toolbar_base_feature", "//ios/chrome/browser/ui/toolbar/public:toolbar_base_feature",
"//ios/chrome/browser/ui/tools_menu", "//ios/chrome/browser/ui/tools_menu",
"//ios/chrome/browser/ui/tools_menu:configuration", "//ios/chrome/browser/ui/tools_menu:configuration",
......
...@@ -31,6 +31,12 @@ ...@@ -31,6 +31,12 @@
// possible for |dragging| to be NO while |scrolling| is still YES. // possible for |dragging| to be NO while |scrolling| is still YES.
- (void)broadcastScrollViewIsDragging:(BOOL)dragging; - (void)broadcastScrollViewIsDragging:(BOOL)dragging;
#pragma mark - Toolbar UI
// Observer method for objects that care about the current height of the
// toolbar.
- (void)broadcastToolbarHeight:(CGFloat)height;
@end @end
#endif // IOS_CHROME_BROWSER_UI_BROADCASTER_CHROME_BROADCAST_OBSERVER_H_ #endif // IOS_CHROME_BROWSER_UI_BROADCASTER_CHROME_BROADCAST_OBSERVER_H_
...@@ -177,9 +177,11 @@ ...@@ -177,9 +177,11 @@
#import "ios/chrome/browser/ui/tabs/requirements/tab_strip_presentation.h" #import "ios/chrome/browser/ui/tabs/requirements/tab_strip_presentation.h"
#import "ios/chrome/browser/ui/tabs/tab_strip_legacy_coordinator.h" #import "ios/chrome/browser/ui/tabs/tab_strip_legacy_coordinator.h"
#include "ios/chrome/browser/ui/toolbar/legacy_toolbar_coordinator.h" #include "ios/chrome/browser/ui/toolbar/legacy_toolbar_coordinator.h"
#import "ios/chrome/browser/ui/toolbar/legacy_toolbar_ui_updater.h"
#include "ios/chrome/browser/ui/toolbar/toolbar_model_delegate_ios.h" #include "ios/chrome/browser/ui/toolbar/toolbar_model_delegate_ios.h"
#include "ios/chrome/browser/ui/toolbar/toolbar_model_ios.h" #include "ios/chrome/browser/ui/toolbar/toolbar_model_ios.h"
#import "ios/chrome/browser/ui/toolbar/toolbar_snapshot_providing.h" #import "ios/chrome/browser/ui/toolbar/toolbar_snapshot_providing.h"
#import "ios/chrome/browser/ui/toolbar/toolbar_ui.h"
#import "ios/chrome/browser/ui/toolbar/web_toolbar_controller.h" #import "ios/chrome/browser/ui/toolbar/web_toolbar_controller.h"
#import "ios/chrome/browser/ui/tools_menu/public/tools_menu_configuration_provider.h" #import "ios/chrome/browser/ui/tools_menu/public/tools_menu_configuration_provider.h"
#import "ios/chrome/browser/ui/tools_menu/public/tools_menu_presentation_provider.h" #import "ios/chrome/browser/ui/tools_menu/public/tools_menu_presentation_provider.h"
...@@ -566,6 +568,9 @@ NSString* const kBrowserViewControllerSnackbarCategory = ...@@ -566,6 +568,9 @@ NSString* const kBrowserViewControllerSnackbarCategory =
// Coordinator for the toolbar. // Coordinator for the toolbar.
LegacyToolbarCoordinator* _toolbarCoordinator; LegacyToolbarCoordinator* _toolbarCoordinator;
// The toolbar UI updater for the toolbar managed by |_toolbarCoordinator|.
LegacyToolbarUIUpdater* _toolbarUIUpdater;
// Coordinator for the External Search UI. // Coordinator for the External Search UI.
ExternalSearchCoordinator* _externalSearchCoordinator; ExternalSearchCoordinator* _externalSearchCoordinator;
...@@ -722,6 +727,9 @@ NSString* const kBrowserViewControllerSnackbarCategory = ...@@ -722,6 +727,9 @@ NSString* const kBrowserViewControllerSnackbarCategory =
- (UIImageView*)pageFullScreenOpenCloseAnimationView; - (UIImageView*)pageFullScreenOpenCloseAnimationView;
// Updates the toolbar display based on the current tab. // Updates the toolbar display based on the current tab.
- (void)updateToolbar; - (void)updateToolbar;
// Starts or stops broadcasting the toolbar UI depending on whether the BVC is
// visible and active.
- (void)updateToolbarBroadcastState;
// Updates |dialogPresenter|'s |active| property to account for the BVC's // Updates |dialogPresenter|'s |active| property to account for the BVC's
// |active|, |visible|, and |inNewTabAnimation| properties. // |active|, |visible|, and |inNewTabAnimation| properties.
- (void)updateDialogPresenterActiveState; - (void)updateDialogPresenterActiveState;
...@@ -1133,6 +1141,7 @@ applicationCommandEndpoint:(id<ApplicationCommands>)applicationCommandEndpoint { ...@@ -1133,6 +1141,7 @@ applicationCommandEndpoint:(id<ApplicationCommands>)applicationCommandEndpoint {
[_model setWebUsageEnabled:active]; [_model setWebUsageEnabled:active];
[self updateDialogPresenterActiveState]; [self updateDialogPresenterActiveState];
[self updateToolbarBroadcastState];
if (active) { if (active) {
// Make sure the tab (if any; it's possible to get here without a current // Make sure the tab (if any; it's possible to get here without a current
...@@ -1156,6 +1165,7 @@ applicationCommandEndpoint:(id<ApplicationCommands>)applicationCommandEndpoint { ...@@ -1156,6 +1165,7 @@ applicationCommandEndpoint:(id<ApplicationCommands>)applicationCommandEndpoint {
[_model setPrimary:primary]; [_model setPrimary:primary];
if (primary) { if (primary) {
[self updateDialogPresenterActiveState]; [self updateDialogPresenterActiveState];
[self updateToolbarBroadcastState];
} else { } else {
self.dialogPresenter.active = false; self.dialogPresenter.active = false;
} }
...@@ -1242,6 +1252,7 @@ applicationCommandEndpoint:(id<ApplicationCommands>)applicationCommandEndpoint { ...@@ -1242,6 +1252,7 @@ applicationCommandEndpoint:(id<ApplicationCommands>)applicationCommandEndpoint {
_viewVisible = viewVisible; _viewVisible = viewVisible;
self.visible = viewVisible; self.visible = viewVisible;
[self updateDialogPresenterActiveState]; [self updateDialogPresenterActiveState];
[self updateToolbarBroadcastState];
} }
- (BOOL)isToolbarOnScreen { - (BOOL)isToolbarOnScreen {
...@@ -1253,6 +1264,7 @@ applicationCommandEndpoint:(id<ApplicationCommands>)applicationCommandEndpoint { ...@@ -1253,6 +1264,7 @@ applicationCommandEndpoint:(id<ApplicationCommands>)applicationCommandEndpoint {
return; return;
_inNewTabAnimation = inNewTabAnimation; _inNewTabAnimation = inNewTabAnimation;
[self updateDialogPresenterActiveState]; [self updateDialogPresenterActiveState];
[self updateToolbarBroadcastState];
} }
- (BOOL)isInNewTabAnimation { - (BOOL)isInNewTabAnimation {
...@@ -1358,6 +1370,7 @@ applicationCommandEndpoint:(id<ApplicationCommands>)applicationCommandEndpoint { ...@@ -1358,6 +1370,7 @@ applicationCommandEndpoint:(id<ApplicationCommands>)applicationCommandEndpoint {
[super viewDidAppear:animated]; [super viewDidAppear:animated];
self.viewVisible = YES; self.viewVisible = YES;
[self updateDialogPresenterActiveState]; [self updateDialogPresenterActiveState];
[self updateToolbarBroadcastState];
// |viewDidAppear| can be called after |browserState| is destroyed. Since // |viewDidAppear| can be called after |browserState| is destroyed. Since
// |presentBubblesIfEligible| requires that |self.browserState| is not NULL, // |presentBubblesIfEligible| requires that |self.browserState| is not NULL,
...@@ -1391,6 +1404,7 @@ applicationCommandEndpoint:(id<ApplicationCommands>)applicationCommandEndpoint { ...@@ -1391,6 +1404,7 @@ applicationCommandEndpoint:(id<ApplicationCommands>)applicationCommandEndpoint {
- (void)viewWillDisappear:(BOOL)animated { - (void)viewWillDisappear:(BOOL)animated {
self.viewVisible = NO; self.viewVisible = NO;
[self updateDialogPresenterActiveState]; [self updateDialogPresenterActiveState];
[self updateToolbarBroadcastState];
[[_model currentTab] wasHidden]; [[_model currentTab] wasHidden];
[_bookmarkInteractionController dismissSnackbar]; [_bookmarkInteractionController dismissSnackbar];
if (IsIPadIdiom() && _infoBarContainer) { if (IsIPadIdiom() && _infoBarContainer) {
...@@ -1447,6 +1461,8 @@ applicationCommandEndpoint:(id<ApplicationCommands>)applicationCommandEndpoint { ...@@ -1447,6 +1461,8 @@ applicationCommandEndpoint:(id<ApplicationCommands>)applicationCommandEndpoint {
_readingListCoordinator = nil; _readingListCoordinator = nil;
self.recentTabsCoordinator = nil; self.recentTabsCoordinator = nil;
_toolbarCoordinator = nil; _toolbarCoordinator = nil;
[_toolbarUIUpdater stopUpdating];
_toolbarUIUpdater = nil;
_toolbarModelDelegate = nil; _toolbarModelDelegate = nil;
_toolbarModelIOS = nil; _toolbarModelIOS = nil;
[self.tabStripCoordinator stop]; [self.tabStripCoordinator stop];
...@@ -1930,6 +1946,7 @@ applicationCommandEndpoint:(id<ApplicationCommands>)applicationCommandEndpoint { ...@@ -1930,6 +1946,7 @@ applicationCommandEndpoint:(id<ApplicationCommands>)applicationCommandEndpoint {
[_dispatcher startDispatchingToTarget:_toolbarCoordinator [_dispatcher startDispatchingToTarget:_toolbarCoordinator
forProtocol:@protocol(OmniboxFocuser)]; forProtocol:@protocol(OmniboxFocuser)];
[_toolbarCoordinator setTabCount:[_model count]]; [_toolbarCoordinator setTabCount:[_model count]];
[self updateToolbarBroadcastState];
if (_voiceSearchController) if (_voiceSearchController)
_voiceSearchController->SetDelegate( _voiceSearchController->SetDelegate(
[_toolbarCoordinator voiceSearchDelegate]); [_toolbarCoordinator voiceSearchDelegate]);
...@@ -2186,6 +2203,24 @@ applicationCommandEndpoint:(id<ApplicationCommands>)applicationCommandEndpoint { ...@@ -2186,6 +2203,24 @@ applicationCommandEndpoint:(id<ApplicationCommands>)applicationCommandEndpoint {
} }
} }
- (void)updateToolbarBroadcastState {
BOOL shouldBroadcast =
self.active && self.viewVisible && !self.inNewTabAnimation;
BOOL broadcasting = _toolbarUIUpdater != nil;
if (shouldBroadcast == broadcasting)
return;
if (shouldBroadcast) {
_toolbarUIUpdater = [[LegacyToolbarUIUpdater alloc]
initWithToolbarUI:[[ToolbarUIState alloc] init]
toolbarOwner:self
webStateList:[_model webStateList]];
[_toolbarUIUpdater startUpdating];
} else {
[_toolbarUIUpdater stopUpdating];
_toolbarUIUpdater = nil;
}
}
- (void)updateDialogPresenterActiveState { - (void)updateDialogPresenterActiveState {
self.dialogPresenter.active = self.dialogPresenter.active =
self.active && self.viewVisible && !self.inNewTabAnimation; self.active && self.viewVisible && !self.inNewTabAnimation;
...@@ -4835,6 +4870,10 @@ bubblePresenterForFeature:(const base::Feature&)feature ...@@ -4835,6 +4870,10 @@ bubblePresenterForFeature:(const base::Feature&)feature
#pragma mark - ToolbarOwner #pragma mark - ToolbarOwner
- (CGFloat)toolbarHeight {
return [self headerHeight];
}
- (CGRect)toolbarFrame { - (CGRect)toolbarFrame {
return _toolbarCoordinator.toolbarViewController.view.frame; return _toolbarCoordinator.toolbarViewController.view.frame;
} }
......
...@@ -122,6 +122,36 @@ source_set("toolbar") { ...@@ -122,6 +122,36 @@ source_set("toolbar") {
] ]
} }
source_set("toolbar_ui") {
sources = [
"legacy_toolbar_ui_updater.h",
"legacy_toolbar_ui_updater.mm",
"toolbar_ui.h",
"toolbar_ui.mm",
]
deps = [
":toolbar",
"//base",
"//ios/chrome/browser/ui:ui_util",
"//ios/chrome/browser/web_state_list",
"//ios/web",
]
configs += [ "//build/config/compiler:enable_arc" ]
libs = [ "UIKit.framework" ]
}
source_set("toolbar_ui_broadcasting_util") {
sources = [
"toolbar_ui_broadcasting_util.h",
"toolbar_ui_broadcasting_util.mm",
]
deps = [
":toolbar_ui",
"//ios/chrome/browser/ui/broadcaster",
]
configs += [ "//build/config/compiler:enable_arc" ]
}
source_set("feature") { source_set("feature") {
sources = [ sources = [
"toolbar_private_base_feature.h", "toolbar_private_base_feature.h",
...@@ -164,13 +194,17 @@ source_set("unit_tests") { ...@@ -164,13 +194,17 @@ source_set("unit_tests") {
configs += [ "//build/config/compiler:enable_arc" ] configs += [ "//build/config/compiler:enable_arc" ]
testonly = true testonly = true
sources = [ sources = [
"legacy_toolbar_ui_updater_unittest.mm",
"toolbar_controller_unittest.mm", "toolbar_controller_unittest.mm",
"toolbar_model_impl_ios_unittest.mm", "toolbar_model_impl_ios_unittest.mm",
"toolbar_ui_broadcasting_util_unittest.mm",
"web_toolbar_controller_unittest.mm", "web_toolbar_controller_unittest.mm",
] ]
deps = [ deps = [
":test_support", ":test_support",
":toolbar", ":toolbar",
":toolbar_ui",
":toolbar_ui_broadcasting_util",
"//base", "//base",
"//components/bookmarks/browser", "//components/bookmarks/browser",
"//components/bookmarks/test", "//components/bookmarks/test",
...@@ -180,6 +214,7 @@ source_set("unit_tests") { ...@@ -180,6 +214,7 @@ source_set("unit_tests") {
"//ios/chrome/browser/browser_state:test_support", "//ios/chrome/browser/browser_state:test_support",
"//ios/chrome/browser/tabs", "//ios/chrome/browser/tabs",
"//ios/chrome/browser/ui", "//ios/chrome/browser/ui",
"//ios/chrome/browser/ui/broadcaster",
"//ios/chrome/browser/ui/toolbar/test", "//ios/chrome/browser/ui/toolbar/test",
"//ios/chrome/browser/web_state_list", "//ios/chrome/browser/web_state_list",
"//ios/chrome/browser/web_state_list:test_support", "//ios/chrome/browser/web_state_list:test_support",
......
// 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.
#ifndef IOS_CHROME_BROWSER_UI_TOOLBAR_LEGACY_TOOLBAR_UI_UPDATER_H_
#define IOS_CHROME_BROWSER_UI_TOOLBAR_LEGACY_TOOLBAR_UI_UPDATER_H_
#import <Foundation/Foundation.h>
@protocol ToolbarOwner;
@class ToolbarUIState;
class WebStateList;
// Helper object that uses navigation events to update a ToolbarUIState.
@interface LegacyToolbarUIUpdater : NSObject
// The toolbar UI being updated by this object.
@property(nonatomic, strong, readonly, nonnull) ToolbarUIState* toolbarUI;
// Designated initializer that uses navigation events from |webStateList| and
// the height provided by |toolbarOwner| to update |state|'s broadcast value.
- (nullable instancetype)initWithToolbarUI:(nonnull ToolbarUIState*)toolbarUI
toolbarOwner:(nonnull id<ToolbarOwner>)owner
webStateList:(nonnull WebStateList*)webStateList
NS_DESIGNATED_INITIALIZER;
- (nullable instancetype)init NS_UNAVAILABLE;
// Starts updating |state|.
- (void)startUpdating;
// Stops updating |state|.
- (void)stopUpdating;
@end
#endif // IOS_CHROME_BROWSER_UI_TOOLBAR_LEGACY_TOOLBAR_UI_UPDATER_H_
// 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/toolbar/legacy_toolbar_ui_updater.h"
#include "base/logging.h"
#include "base/memory/ptr_util.h"
#import "ios/chrome/browser/ui/toolbar/toolbar_owner.h"
#import "ios/chrome/browser/ui/toolbar/toolbar_ui.h"
#import "ios/chrome/browser/web_state_list/web_state_list.h"
#import "ios/chrome/browser/web_state_list/web_state_list_observer_bridge.h"
#import "ios/web/public/web_state/navigation_context.h"
#import "ios/web/public/web_state/web_state.h"
#import "ios/web/public/web_state/web_state_observer_bridge.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
#endif
@interface LegacyToolbarUIUpdater ()<CRWWebStateObserver,
WebStateListObserving> {
// The bridge for WebStateList observation.
std::unique_ptr<WebStateListObserverBridge> _webStateListObserver;
// The bridge for WebState observation.
std::unique_ptr<web::WebStateObserverBridge> _webStateObserver;
}
// The ToolbarOwner passed on initialization.
@property(nonatomic, readonly, strong) id<ToolbarOwner> owner;
// The WebStateList whose navigations are driving this updater.
@property(nonatomic, readonly) WebStateList* webStateList;
// The active WebState in |webStateList|.
@property(nonatomic, assign) web::WebState* webState;
// Updates |state| using |toolbarOwner|.
- (void)updateState;
@end
@implementation LegacyToolbarUIUpdater
@synthesize toolbarUI = _toolbarUI;
@synthesize owner = _owner;
@synthesize webStateList = _webStateList;
@synthesize webState = _webState;
- (nullable instancetype)initWithToolbarUI:(nonnull ToolbarUIState*)toolbarUI
toolbarOwner:(nonnull id<ToolbarOwner>)owner
webStateList:(nonnull WebStateList*)webStateList {
if (self = [super init]) {
_toolbarUI = toolbarUI;
DCHECK(_toolbarUI);
_owner = owner;
DCHECK(_owner);
_webStateList = webStateList;
DCHECK(_webStateList);
}
return self;
}
#pragma mark Accessors
- (void)setWebState:(web::WebState*)webState {
if (_webState == webState)
return;
if (_webState) {
DCHECK(_webStateObserver);
_webState->RemoveObserver(_webStateObserver.get());
_webStateObserver = nullptr;
}
_webState = webState;
if (_webState) {
_webStateObserver = base::MakeUnique<web::WebStateObserverBridge>(self);
_webState->AddObserver(_webStateObserver.get());
[self updateState];
}
}
#pragma mark Public
- (void)startUpdating {
DCHECK(!_webStateListObserver);
DCHECK(!_webStateObserver);
_webStateListObserver = base::MakeUnique<WebStateListObserverBridge>(self);
self.webStateList->AddObserver(_webStateListObserver.get());
self.webState = self.webStateList->GetActiveWebState();
[self updateState];
}
- (void)stopUpdating {
DCHECK(_webStateListObserver);
DCHECK(!self.webState || _webStateObserver);
self.webStateList->RemoveObserver(_webStateListObserver.get());
self.webState = nullptr;
}
#pragma mark CRWWebStateObserver
- (void)webState:(web::WebState*)webState
didStartNavigation:(web::NavigationContext*)navigation {
// For user-initiated loads, the toolbar is updated when the navigation is
// started.
if (!navigation->IsRendererInitiated())
[self updateState];
}
- (void)webState:(web::WebState*)webState
didFinishNavigation:(web::NavigationContext*)navigation {
[self updateState];
}
- (void)webStateDestroyed:(web::WebState*)webState {
self.webState = nullptr;
}
#pragma mark WebStateListObserving
- (void)webStateList:(WebStateList*)webStateList
didChangeActiveWebState:(web::WebState*)newWebState
oldWebState:(web::WebState*)oldWebState
atIndex:(int)atIndex
userAction:(BOOL)userAction {
DCHECK_EQ(self.webStateList, webStateList);
self.webState = newWebState;
}
#pragma mark Private
- (void)updateState {
self.toolbarUI.toolbarHeight = [self.owner toolbarHeight];
}
@end
// 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/toolbar/legacy_toolbar_ui_updater.h"
#include "base/memory/ptr_util.h"
#import "ios/chrome/browser/ui/toolbar/toolbar_owner.h"
#import "ios/chrome/browser/ui/toolbar/toolbar_ui.h"
#include "ios/chrome/browser/ui/ui_util.h"
#import "ios/chrome/browser/web_state_list/fake_web_state_list_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/fake_navigation_context.h"
#import "ios/web/public/test/fakes/test_web_state.h"
#include "testing/platform_test.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
#endif
@interface TestToolbarOwner : NSObject<ToolbarOwner>
// Define writable property with same name as |-toolbarHeight| getter defined in
// ToolbarOwner.
@property(nonatomic, assign) CGFloat toolbarHeight;
@end
@implementation TestToolbarOwner
@synthesize toolbarHeight = _toolbarHeight;
@synthesize toolbarSnapshotProvider = _toolbarSnapshotProvider;
- (CGRect)toolbarFrame {
return CGRectZero;
}
@end
class LegacyToolbarUIUpdaterTest : public PlatformTest {
public:
LegacyToolbarUIUpdaterTest()
: PlatformTest(),
web_state_list_(&web_state_list_delegate_),
toolbar_owner_([[TestToolbarOwner alloc] init]),
toolbar_ui_([[ToolbarUIState alloc] init]),
updater_([[LegacyToolbarUIUpdater alloc]
initWithToolbarUI:toolbar_ui_
toolbarOwner:toolbar_owner_
webStateList:&web_state_list_]) {}
~LegacyToolbarUIUpdaterTest() override { StopUpdating(); }
// Getters.
WebStateList* web_state_list() { return &web_state_list_; }
TestToolbarOwner* toolbar_owner() { return toolbar_owner_; }
CGFloat toolbar_height() { return toolbar_ui_.toolbarHeight; }
// Start or stop updating the state.
void StartUpdating() {
if (updating_)
return;
[updater_ startUpdating];
updating_ = true;
}
void StopUpdating() {
if (!updating_)
return;
[updater_ stopUpdating];
updating_ = false;
}
// Inserts and activates a new WebState at the end of the list, and returns a
// pointer to the inserted WebState.
web::TestWebState* InsertActiveWebState() {
std::unique_ptr<web::TestWebState> web_state =
base::MakeUnique<web::TestWebState>();
web::TestWebState* inserted_web_state = web_state.get();
web_state_list_.InsertWebState(0, std::move(web_state),
WebStateList::INSERT_ACTIVATE,
WebStateOpener(nullptr));
return inserted_web_state;
}
private:
FakeWebStateListDelegate web_state_list_delegate_;
WebStateList web_state_list_;
__strong TestToolbarOwner* toolbar_owner_ = nil;
__strong ToolbarUIState* toolbar_ui_ = nil;
__strong LegacyToolbarUIUpdater* updater_ = nil;
bool updating_ = false;
};
// Tests that |-startUpdating| resets the state's height when starting.
TEST_F(LegacyToolbarUIUpdaterTest, StartUpdating) {
EXPECT_EQ(toolbar_height(), 0.0);
const CGFloat kHeight = 150.0;
toolbar_owner().toolbarHeight = kHeight;
StartUpdating();
EXPECT_EQ(toolbar_height(), kHeight);
}
// Tests that the state is not updated after calling |-stopUpdating|.
TEST_F(LegacyToolbarUIUpdaterTest, StopUpdating) {
web::TestWebState* web_state = InsertActiveWebState();
StartUpdating();
const CGFloat kHeight = 150.0;
toolbar_owner().toolbarHeight = kHeight;
web::FakeNavigationContext context;
web_state->OnNavigationFinished(&context);
EXPECT_EQ(toolbar_height(), kHeight);
const CGFloat kNonUpdatedHeight = 500.0;
StopUpdating();
toolbar_owner().toolbarHeight = kNonUpdatedHeight;
web_state->OnNavigationFinished(&context);
EXPECT_EQ(toolbar_height(), kHeight);
}
// Tests that the updater polls for the new height when the active WebState
// changes.
TEST_F(LegacyToolbarUIUpdaterTest, UpdateActiveWebState) {
StartUpdating();
const CGFloat kHeight = 150.0;
toolbar_owner().toolbarHeight = kHeight;
EXPECT_EQ(toolbar_height(), 0.0);
InsertActiveWebState();
EXPECT_EQ(toolbar_height(), kHeight);
}
// Tests that the updater polls for the new height when the active WebState
// starts a user-initiated navigation.
TEST_F(LegacyToolbarUIUpdaterTest, UserInitiatedNavigation) {
web::TestWebState* web_state = InsertActiveWebState();
StartUpdating();
const CGFloat kHeight = 150.0;
toolbar_owner().toolbarHeight = kHeight;
EXPECT_EQ(toolbar_height(), 0.0);
web::FakeNavigationContext context;
context.SetIsRendererInitiated(false);
web_state->OnNavigationStarted(&context);
EXPECT_EQ(toolbar_height(), kHeight);
}
// Tests that the updater waits until a render-initiated navigation is committed
// before updating the ui state.
TEST_F(LegacyToolbarUIUpdaterTest, RendererInitiatedNavigation) {
web::TestWebState* web_state = InsertActiveWebState();
StartUpdating();
const CGFloat kHeight = 150.0;
toolbar_owner().toolbarHeight = kHeight;
EXPECT_EQ(toolbar_height(), 0.0);
web::FakeNavigationContext context;
context.SetIsRendererInitiated(true);
web_state->OnNavigationStarted(&context);
EXPECT_EQ(toolbar_height(), 0.0);
web_state->OnNavigationFinished(&context);
EXPECT_EQ(toolbar_height(), kHeight);
}
...@@ -7,6 +7,10 @@ source_set("test") { ...@@ -7,6 +7,10 @@ source_set("test") {
testonly = true testonly = true
sources = [ sources = [
"test_toolbar_ui_observer.h",
"test_toolbar_ui_observer.mm",
"toolbar_broadcast_test_util.h",
"toolbar_broadcast_test_util.mm",
"toolbar_test_navigation_manager.h", "toolbar_test_navigation_manager.h",
"toolbar_test_navigation_manager.mm", "toolbar_test_navigation_manager.mm",
"toolbar_test_web_state.h", "toolbar_test_web_state.h",
...@@ -14,6 +18,11 @@ source_set("test") { ...@@ -14,6 +18,11 @@ source_set("test") {
] ]
deps = [ deps = [
"//ios/chrome/browser/ui:ui_util",
"//ios/chrome/browser/ui/broadcaster",
"//ios/chrome/browser/ui/toolbar",
"//ios/chrome/browser/ui/toolbar:toolbar_ui",
"//ios/web/public/test/fakes", "//ios/web/public/test/fakes",
"//testing/gtest",
] ]
} }
// 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.
#ifndef IOS_CHROME_BROWSER_UI_TOOLBAR_TEST_TEST_TOOLBAR_UI_OBSERVER_H_
#define IOS_CHROME_BROWSER_UI_TOOLBAR_TEST_TEST_TOOLBAR_UI_OBSERVER_H_
#import <Foundation/Foundation.h>
#import "ios/chrome/browser/ui/broadcaster/chrome_broadcaster.h"
// An object that observes the toolbar's UI state.
@interface TestToolbarUIObserver : NSObject<ChromeBroadcastObserver>
// The broadcaster. Setting will start observing broadcast values from the
// broadcaster.
@property(nonatomic, strong) ChromeBroadcaster* broadcaster;
// The broadcasted UI state observed by this object.
@property(nonatomic, readonly) CGFloat toolbarHeight;
@end
#endif // IOS_CHROME_BROWSER_UI_TOOLBAR_TEST_TEST_TOOLBAR_UI_OBSERVER_H_
// 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/toolbar/test/test_toolbar_ui_observer.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
#endif
@implementation TestToolbarUIObserver
@synthesize broadcaster = _broadcaster;
@synthesize toolbarHeight = _toolbarHeight;
- (void)setBroadcaster:(ChromeBroadcaster*)broadcaster {
[_broadcaster removeObserver:self
forSelector:@selector(broadcastToolbarHeight:)];
_broadcaster = broadcaster;
[_broadcaster addObserver:self
forSelector:@selector(broadcastToolbarHeight:)];
}
- (void)broadcastToolbarHeight:(CGFloat)toolbarHeight {
_toolbarHeight = toolbarHeight;
}
@end
// 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.
#ifndef IOS_CHROME_BROWSER_UI_TOOLBAR_TEST_TOOLBAR_BROADCAST_TEST_UTIL_H_
#define IOS_CHROME_BROWSER_UI_TOOLBAR_TEST_TOOLBAR_BROADCAST_TEST_UTIL_H_
@class ChromeBroadcaster;
@class ToolbarUIState;
// Checks whether |ui_state|'s broadcast properties are being broadcast through
// |broadcaster|. Verifies broadcast setup according to |should_broadcast|.
void VerifyToolbarUIBroadcast(ToolbarUIState* toolbar_ui,
ChromeBroadcaster* broadcaster,
bool should_broadcast);
#endif // IOS_CHROME_BROWSER_UI_TOOLBAR_TEST_TOOLBAR_BROADCAST_TEST_UTIL_H_
// 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/toolbar/test/toolbar_broadcast_test_util.h"
#import "ios/chrome/browser/ui/toolbar/test/test_toolbar_ui_observer.h"
#import "ios/chrome/browser/ui/toolbar/toolbar_ui.h"
#include "ios/chrome/browser/ui/ui_util.h"
#include "testing/gtest/include/gtest/gtest.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
#endif
namespace {
// The delta by which the toolbar height is adjusted to verify broadcasting.
const CGFloat kHeightDelta = 100.0;
// Helper class that modifies a TestMainContentUIState, then reverts those
// changes upon destruction.
class TestToolbarUIStateModifier {
public:
TestToolbarUIStateModifier(ToolbarUIState* toolbar_ui)
: toolbar_ui_(toolbar_ui), original_height_(toolbar_ui_.toolbarHeight) {
toolbar_ui_.toolbarHeight += kHeightDelta;
}
~TestToolbarUIStateModifier() {
toolbar_ui_.toolbarHeight = original_height_;
}
// The original values of the UI state.
CGFloat original_height() { return original_height_; }
private:
__strong ToolbarUIState* toolbar_ui_ = nil;
CGFloat original_height_ = 0.0;
};
} // namespace
void VerifyToolbarUIBroadcast(ToolbarUIState* toolbar_ui,
ChromeBroadcaster* broadcaster,
bool should_broadcast) {
ASSERT_TRUE(toolbar_ui);
ASSERT_TRUE(broadcaster);
// Create an observer and modifier for |ui_state|.
TestToolbarUIObserver* observer = [[TestToolbarUIObserver alloc] init];
observer.broadcaster = broadcaster;
TestToolbarUIStateModifier modifier(toolbar_ui);
// Verify whether the changed or original UI elements are observed.
if (should_broadcast) {
EXPECT_TRUE(
AreCGFloatsEqual(observer.toolbarHeight, toolbar_ui.toolbarHeight));
} else {
EXPECT_TRUE(
AreCGFloatsEqual(observer.toolbarHeight, modifier.original_height()));
}
// Stop observing |broadcaster|.
observer.broadcaster = nil;
}
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
#ifndef IOS_CHROME_BROWSER_UI_TOOLBAR_TOOLBAR_OWNER_H_ #ifndef IOS_CHROME_BROWSER_UI_TOOLBAR_TOOLBAR_OWNER_H_
#define IOS_CHROME_BROWSER_UI_TOOLBAR_TOOLBAR_OWNER_H_ #define IOS_CHROME_BROWSER_UI_TOOLBAR_TOOLBAR_OWNER_H_
#import <Foundation/Foundation.h> #import <UIKit/UIKit.h>
@class ToolbarController; @class ToolbarController;
@protocol ToolbarSnapshotProviding; @protocol ToolbarSnapshotProviding;
......
// 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.
#ifndef IOS_CHROME_BROWSER_UI_TOOLBAR_TOOLBAR_UI_H_
#define IOS_CHROME_BROWSER_UI_TOOLBAR_TOOLBAR_UI_H_
#import <UIKit/UIKit.h>
// Protocol for the UI displaying the toolbar.
@protocol ToolbarUI<NSObject>
// The height of the toolbar, not including the safe area inset.
// This should be broadcast using |-broadcastToolbarHeight:|.
@property(nonatomic, readonly) CGFloat toolbarHeight;
@end
// Simple implementation of ToolbarUI that allows readwrite access to broadcast
// properties.
@interface ToolbarUIState : NSObject<ToolbarUI>
// Redefine properties as readwrite.
@property(nonatomic, assign) CGFloat toolbarHeight;
@end
#endif // IOS_CHROME_BROWSER_UI_TOOLBAR_TOOLBAR_UI_H_
// 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/toolbar/toolbar_ui.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
#endif
@implementation ToolbarUIState
@synthesize toolbarHeight = _toolbarHeight;
@end
// 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.
#ifndef IOS_CHROME_BROWSER_UI_TOOLBAR_TOOLBAR_UI_BROADCASTING_UTIL_H_
#define IOS_CHROME_BROWSER_UI_TOOLBAR_TOOLBAR_UI_BROADCASTING_UTIL_H_
@class ChromeBroadcaster;
@protocol ToolbarUI;
// Starts broadcasting |toolbar|'s UI state using |broadcaster|.
void StartBroadcastingToolbarUI(id<ToolbarUI> toolbar,
ChromeBroadcaster* broadcaster);
// Stops broadcasting MainContentUI properties using |broadcaster|.
void StopBroadcastingToolbarUI(ChromeBroadcaster* broadcaster);
#endif // IOS_CHROME_BROWSER_UI_TOOLBAR_TOOLBAR_UI_BROADCASTING_UTIL_H_
// 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/toolbar/toolbar_ui_broadcasting_util.h"
#import "ios/chrome/browser/ui/broadcaster/chrome_broadcaster.h"
#import "ios/chrome/browser/ui/toolbar/toolbar_ui.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
#endif
void StartBroadcastingToolbarUI(id<ToolbarUI> toolbar,
ChromeBroadcaster* broadcaster) {
[broadcaster broadcastValue:@"toolbarHeight"
ofObject:toolbar
selector:@selector(broadcastToolbarHeight:)];
}
void StopBroadcastingToolbarUI(ChromeBroadcaster* broadcaster) {
[broadcaster stopBroadcastingForSelector:@selector(broadcastToolbarHeight:)];
}
// 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/toolbar/toolbar_ui_broadcasting_util.h"
#import "ios/chrome/browser/ui/broadcaster/chrome_broadcaster.h"
#import "ios/chrome/browser/ui/toolbar/test/toolbar_broadcast_test_util.h"
#import "ios/chrome/browser/ui/toolbar/toolbar_ui.h"
#include "testing/gtest/include/gtest/gtest.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
#endif
// Tests that the ToolbarUIBroadcastingUtil functions successfully start
// and stop broadcasting toolbar properties.
TEST(ToolbarUIBroadcastingUtilTest, StartStop) {
ToolbarUIState* toolbar_ui = [[ToolbarUIState alloc] init];
ChromeBroadcaster* broadcaster = [[ChromeBroadcaster alloc] init];
VerifyToolbarUIBroadcast(toolbar_ui, broadcaster, false);
StartBroadcastingToolbarUI(toolbar_ui, broadcaster);
VerifyToolbarUIBroadcast(toolbar_ui, broadcaster, true);
StopBroadcastingToolbarUI(broadcaster);
VerifyToolbarUIBroadcast(toolbar_ui, broadcaster, false);
}
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