browser_window_controller_browsertest.mm revision a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7
1// Copyright (c) 2012 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#import "chrome/browser/ui/cocoa/browser_window_controller.h" 6 7#import "base/mac/mac_util.h" 8#include "base/run_loop.h" 9#include "base/strings/utf_string_conversions.h" 10#include "chrome/browser/browser_process.h" 11#include "chrome/browser/infobars/infobar_service.h" 12#include "chrome/browser/infobars/simple_alert_infobar_delegate.h" 13#include "chrome/browser/profiles/profile.h" 14#include "chrome/browser/profiles/profile_manager.h" 15#include "chrome/browser/ui/bookmarks/bookmark_utils.h" 16#include "chrome/browser/ui/browser.h" 17#include "chrome/browser/ui/browser_commands.h" 18#include "chrome/browser/ui/browser_list.h" 19#include "chrome/browser/ui/browser_window.h" 20#import "chrome/browser/ui/cocoa/browser/avatar_button_controller.h" 21#include "chrome/browser/ui/cocoa/browser_window_cocoa.h" 22#import "chrome/browser/ui/cocoa/browser_window_controller_private.h" 23#import "chrome/browser/ui/cocoa/fast_resize_view.h" 24#import "chrome/browser/ui/cocoa/history_overlay_controller.h" 25#import "chrome/browser/ui/cocoa/infobars/infobar_cocoa.h" 26#import "chrome/browser/ui/cocoa/infobars/infobar_container_controller.h" 27#import "chrome/browser/ui/cocoa/nsview_additions.h" 28#import "chrome/browser/ui/cocoa/tab_contents/overlayable_contents_controller.h" 29#include "chrome/browser/ui/extensions/application_launch.h" 30#include "chrome/browser/ui/find_bar/find_bar_controller.h" 31#include "chrome/browser/ui/find_bar/find_bar.h" 32#include "chrome/browser/ui/tabs/tab_strip_model.h" 33#include "chrome/test/base/in_process_browser_test.h" 34#include "chrome/test/base/testing_profile.h" 35#include "content/public/browser/web_contents.h" 36#include "content/public/browser/web_contents_view.h" 37#import "testing/gtest_mac.h" 38 39namespace { 40 41#if !defined(MAC_OS_X_VERSION_10_7) || \ 42 MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_7 43enum { 44 NSWindowDocumentVersionsButton = 6, 45 NSWindowFullScreenButton 46}; 47#endif // MAC_OS_X_VERSION_10_7 48 49void CreateProfileCallback(const base::Closure& quit_closure, 50 Profile* profile, 51 Profile::CreateStatus status) { 52 EXPECT_TRUE(profile); 53 EXPECT_NE(Profile::CREATE_STATUS_LOCAL_FAIL, status); 54 EXPECT_NE(Profile::CREATE_STATUS_REMOTE_FAIL, status); 55 // This will be called multiple times. Wait until the profile is initialized 56 // fully to quit the loop. 57 if (status == Profile::CREATE_STATUS_INITIALIZED) 58 quit_closure.Run(); 59} 60 61enum ViewID { 62 VIEW_ID_TOOLBAR, 63 VIEW_ID_BOOKMARK_BAR, 64 VIEW_ID_INFO_BAR, 65 VIEW_ID_FIND_BAR, 66 VIEW_ID_DOWNLOAD_SHELF, 67 VIEW_ID_TAB_CONTENT_AREA, 68 VIEW_ID_FULLSCREEN_FLOATING_BAR, 69 VIEW_ID_COUNT, 70}; 71 72} // namespace 73 74class BrowserWindowControllerTest : public InProcessBrowserTest { 75 public: 76 BrowserWindowControllerTest() : InProcessBrowserTest() { 77 } 78 79 virtual void SetUpOnMainThread() OVERRIDE { 80 [[controller() bookmarkBarController] setStateAnimationsEnabled:NO]; 81 [[controller() bookmarkBarController] setInnerContentAnimationsEnabled:NO]; 82 } 83 84 BrowserWindowController* controller() const { 85 return [BrowserWindowController browserWindowControllerForWindow: 86 browser()->window()->GetNativeWindow()]; 87 } 88 89 static void ShowInfoBar(Browser* browser) { 90 SimpleAlertInfoBarDelegate::Create( 91 InfoBarService::FromWebContents( 92 browser->tab_strip_model()->GetActiveWebContents()), 93 0, base::string16(), false); 94 } 95 96 NSView* GetViewWithID(ViewID view_id) const { 97 switch (view_id) { 98 case VIEW_ID_FULLSCREEN_FLOATING_BAR: 99 return [controller() floatingBarBackingView]; 100 case VIEW_ID_TOOLBAR: 101 return [[controller() toolbarController] view]; 102 case VIEW_ID_BOOKMARK_BAR: 103 return [[controller() bookmarkBarController] view]; 104 case VIEW_ID_INFO_BAR: 105 return [[controller() infoBarContainerController] view]; 106 case VIEW_ID_FIND_BAR: 107 return [[controller() findBarCocoaController] view]; 108 case VIEW_ID_DOWNLOAD_SHELF: 109 return [[controller() downloadShelf] view]; 110 case VIEW_ID_TAB_CONTENT_AREA: 111 return [controller() tabContentArea]; 112 default: 113 NOTREACHED(); 114 return nil; 115 } 116 } 117 118 void VerifyZOrder(const std::vector<ViewID>& view_list) const { 119 for (size_t i = 0; i < view_list.size() - 1; ++i) { 120 NSView* bottom_view = GetViewWithID(view_list[i]); 121 NSView* top_view = GetViewWithID(view_list[i + 1]); 122 EXPECT_NSEQ([bottom_view superview], [top_view superview]); 123 EXPECT_TRUE([bottom_view cr_isBelowView:top_view]); 124 } 125 126 // Views not in |view_list| must either be nil or not parented. 127 for (size_t i = 0; i < VIEW_ID_COUNT; ++i) { 128 if (std::find(view_list.begin(), view_list.end(), i) == view_list.end()) { 129 NSView* view = GetViewWithID(static_cast<ViewID>(i)); 130 EXPECT_TRUE(!view || ![view superview]); 131 } 132 } 133 } 134 135 CGFloat GetViewHeight(ViewID viewID) const { 136 CGFloat height = NSHeight([GetViewWithID(viewID) frame]); 137 if (viewID == VIEW_ID_INFO_BAR) { 138 height -= [[controller() infoBarContainerController] 139 overlappingTipHeight]; 140 } 141 return height; 142 } 143 144 private: 145 DISALLOW_COPY_AND_ASSIGN(BrowserWindowControllerTest); 146}; 147 148// Tests that adding the first profile moves the Lion fullscreen button over 149// correctly. 150// DISABLED_ because it regularly times out: http://crbug.com/159002. 151IN_PROC_BROWSER_TEST_F(BrowserWindowControllerTest, 152 DISABLED_ProfileAvatarFullscreenButton) { 153 if (base::mac::IsOSSnowLeopard()) 154 return; 155 156 // Initialize the locals. 157 ProfileManager* profile_manager = g_browser_process->profile_manager(); 158 ASSERT_TRUE(profile_manager); 159 160 NSWindow* window = browser()->window()->GetNativeWindow(); 161 ASSERT_TRUE(window); 162 163 // With only one profile, the fullscreen button should be visible, but the 164 // avatar button should not. 165 EXPECT_EQ(1u, profile_manager->GetNumberOfProfiles()); 166 167 NSButton* fullscreen_button = 168 [window standardWindowButton:NSWindowFullScreenButton]; 169 EXPECT_TRUE(fullscreen_button); 170 EXPECT_FALSE([fullscreen_button isHidden]); 171 172 AvatarButtonController* avatar_controller = 173 [controller() avatarButtonController]; 174 NSView* avatar = [avatar_controller view]; 175 EXPECT_TRUE(avatar); 176 EXPECT_TRUE([avatar isHidden]); 177 178 // Create a profile asynchronously and run the loop until its creation 179 // is complete. 180 base::RunLoop run_loop; 181 182 ProfileManager::CreateCallback create_callback = 183 base::Bind(&CreateProfileCallback, run_loop.QuitClosure()); 184 profile_manager->CreateProfileAsync( 185 profile_manager->user_data_dir().Append("test"), 186 create_callback, 187 ASCIIToUTF16("avatar_test"), 188 base::string16(), 189 std::string()); 190 191 run_loop.Run(); 192 193 // There should now be two profiles, and the avatar button and fullscreen 194 // button are both visible. 195 EXPECT_EQ(2u, profile_manager->GetNumberOfProfiles()); 196 EXPECT_FALSE([avatar isHidden]); 197 EXPECT_FALSE([fullscreen_button isHidden]); 198 EXPECT_EQ([avatar window], [fullscreen_button window]); 199 200 // Make sure the visual order of the buttons is correct and that they don't 201 // overlap. 202 NSRect avatar_frame = [avatar frame]; 203 NSRect fullscreen_frame = [fullscreen_button frame]; 204 205 EXPECT_LT(NSMinX(fullscreen_frame), NSMinX(avatar_frame)); 206 EXPECT_LT(NSMaxX(fullscreen_frame), NSMinX(avatar_frame)); 207} 208 209// Verify that in non-Instant normal mode that the find bar and download shelf 210// are above the content area. Everything else should be below it. 211IN_PROC_BROWSER_TEST_F(BrowserWindowControllerTest, ZOrderNormal) { 212 browser()->GetFindBarController(); // add find bar 213 214 std::vector<ViewID> view_list; 215 view_list.push_back(VIEW_ID_BOOKMARK_BAR); 216 view_list.push_back(VIEW_ID_TOOLBAR); 217 view_list.push_back(VIEW_ID_INFO_BAR); 218 view_list.push_back(VIEW_ID_TAB_CONTENT_AREA); 219 view_list.push_back(VIEW_ID_FIND_BAR); 220 view_list.push_back(VIEW_ID_DOWNLOAD_SHELF); 221 VerifyZOrder(view_list); 222} 223 224// Verify that in non-Instant presentation mode that the info bar is below the 225// content are and everything else is above it. 226// DISABLED due to flaky failures on trybots. http://crbug.com/178778 227IN_PROC_BROWSER_TEST_F(BrowserWindowControllerTest, 228 DISABLED_ZOrderPresentationMode) { 229 chrome::ToggleFullscreenMode(browser()); 230 browser()->GetFindBarController(); // add find bar 231 232 std::vector<ViewID> view_list; 233 view_list.push_back(VIEW_ID_INFO_BAR); 234 view_list.push_back(VIEW_ID_TAB_CONTENT_AREA); 235 view_list.push_back(VIEW_ID_FULLSCREEN_FLOATING_BAR); 236 view_list.push_back(VIEW_ID_BOOKMARK_BAR); 237 view_list.push_back(VIEW_ID_TOOLBAR); 238 view_list.push_back(VIEW_ID_FIND_BAR); 239 view_list.push_back(VIEW_ID_DOWNLOAD_SHELF); 240 VerifyZOrder(view_list); 241} 242 243// Verify that if the fullscreen floating bar view is below the tab content area 244// then calling |updateSubviewZOrder:| will correctly move back above. 245IN_PROC_BROWSER_TEST_F(BrowserWindowControllerTest, 246 DISABLED_FloatingBarBelowContentView) { 247 // TODO(kbr): re-enable: http://crbug.com/222296 248 if (base::mac::IsOSMountainLionOrLater()) 249 return; 250 251 chrome::ToggleFullscreenMode(browser()); 252 253 NSView* fullscreen_floating_bar = 254 GetViewWithID(VIEW_ID_FULLSCREEN_FLOATING_BAR); 255 [fullscreen_floating_bar removeFromSuperview]; 256 [[[controller() window] contentView] addSubview:fullscreen_floating_bar 257 positioned:NSWindowBelow 258 relativeTo:nil]; 259 [controller() updateSubviewZOrder:[controller() inPresentationMode]]; 260 261 std::vector<ViewID> view_list; 262 view_list.push_back(VIEW_ID_INFO_BAR); 263 view_list.push_back(VIEW_ID_TAB_CONTENT_AREA); 264 view_list.push_back(VIEW_ID_FULLSCREEN_FLOATING_BAR); 265 view_list.push_back(VIEW_ID_BOOKMARK_BAR); 266 view_list.push_back(VIEW_ID_TOOLBAR); 267 view_list.push_back(VIEW_ID_DOWNLOAD_SHELF); 268 VerifyZOrder(view_list); 269} 270 271IN_PROC_BROWSER_TEST_F(BrowserWindowControllerTest, SheetPosition) { 272 ASSERT_TRUE([controller() isKindOfClass:[BrowserWindowController class]]); 273 EXPECT_TRUE([controller() isTabbedWindow]); 274 EXPECT_TRUE([controller() hasTabStrip]); 275 EXPECT_FALSE([controller() hasTitleBar]); 276 EXPECT_TRUE([controller() hasToolbar]); 277 EXPECT_FALSE([controller() isBookmarkBarVisible]); 278 279 NSRect defaultAlertFrame = NSMakeRect(0, 0, 300, 200); 280 NSWindow* window = browser()->window()->GetNativeWindow(); 281 NSRect alertFrame = [controller() window:window 282 willPositionSheet:nil 283 usingRect:defaultAlertFrame]; 284 NSRect toolbarFrame = [[[controller() toolbarController] view] frame]; 285 EXPECT_EQ(NSMinY(alertFrame), NSMinY(toolbarFrame)); 286 287 // Open sheet with normal browser window, persistent bookmark bar. 288 chrome::ToggleBookmarkBarWhenVisible(browser()->profile()); 289 EXPECT_TRUE([controller() isBookmarkBarVisible]); 290 alertFrame = [controller() window:window 291 willPositionSheet:nil 292 usingRect:defaultAlertFrame]; 293 NSRect bookmarkBarFrame = [[[controller() bookmarkBarController] view] frame]; 294 EXPECT_EQ(NSMinY(alertFrame), NSMinY(bookmarkBarFrame)); 295 296 // Make sure the profile does not have the bookmark visible so that 297 // we'll create the shortcut window without the bookmark bar. 298 chrome::ToggleBookmarkBarWhenVisible(browser()->profile()); 299 // Open application mode window. 300 gfx::Rect initial_bounds(0, 0, 400, 400); 301 OpenAppShortcutWindow(browser()->profile(), GURL("about:blank"), 302 initial_bounds); 303 Browser* popup_browser = BrowserList::GetInstance( 304 chrome::GetActiveDesktop())->GetLastActive(); 305 NSWindow* popupWindow = popup_browser->window()->GetNativeWindow(); 306 BrowserWindowController* popupController = 307 [BrowserWindowController browserWindowControllerForWindow:popupWindow]; 308 ASSERT_TRUE([popupController isKindOfClass:[BrowserWindowController class]]); 309 EXPECT_FALSE([popupController isTabbedWindow]); 310 EXPECT_FALSE([popupController hasTabStrip]); 311 EXPECT_TRUE([popupController hasTitleBar]); 312 EXPECT_FALSE([popupController isBookmarkBarVisible]); 313 EXPECT_FALSE([popupController hasToolbar]); 314 315 // Open sheet in an application window. 316 [popupController showWindow:nil]; 317 alertFrame = [popupController window:popupWindow 318 willPositionSheet:nil 319 usingRect:defaultAlertFrame]; 320 EXPECT_EQ(NSMinY(alertFrame), 321 NSHeight([[popupWindow contentView] frame]) - 322 defaultAlertFrame.size.height); 323 324 // Close the application window. 325 popup_browser->tab_strip_model()->CloseSelectedTabs(); 326 [popupController close]; 327} 328 329// Verify that the info bar tip is hidden when the toolbar is not visible. 330IN_PROC_BROWSER_TEST_F(BrowserWindowControllerTest, 331 InfoBarTipHiddenForWindowWithoutToolbar) { 332 ShowInfoBar(browser()); 333 EXPECT_FALSE( 334 [[controller() infoBarContainerController] shouldSuppressTopInfoBarTip]); 335 336 gfx::Rect initial_bounds(0, 0, 400, 400); 337 OpenAppShortcutWindow(browser()->profile(), GURL("about:blank"), 338 initial_bounds); 339 Browser* popup_browser = BrowserList::GetInstance( 340 chrome::HOST_DESKTOP_TYPE_NATIVE)->GetLastActive(); 341 NSWindow* popupWindow = popup_browser->window()->GetNativeWindow(); 342 BrowserWindowController* popupController = 343 [BrowserWindowController browserWindowControllerForWindow:popupWindow]; 344 EXPECT_FALSE([popupController hasToolbar]); 345 346 // Show infobar for controller. 347 ShowInfoBar(popup_browser); 348 EXPECT_TRUE( 349 [[popupController infoBarContainerController] 350 shouldSuppressTopInfoBarTip]); 351} 352 353// Verify that AllowOverlappingViews is set while the history overlay is 354// visible. 355IN_PROC_BROWSER_TEST_F(BrowserWindowControllerTest, 356 AllowOverlappingViewsHistoryOverlay) { 357 content::WebContentsView* web_contents_view = 358 browser()->tab_strip_model()->GetActiveWebContents()->GetView(); 359 EXPECT_TRUE(web_contents_view->GetAllowOverlappingViews()); 360 361 base::scoped_nsobject<HistoryOverlayController> overlay( 362 [[HistoryOverlayController alloc] initForMode:kHistoryOverlayModeBack]); 363 [overlay showPanelForView:web_contents_view->GetNativeView()]; 364 EXPECT_TRUE(web_contents_view->GetAllowOverlappingViews()); 365 366 overlay.reset(); 367 EXPECT_TRUE(web_contents_view->GetAllowOverlappingViews()); 368} 369