// Copyright (c) 2012 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. #include "ash/shelf/shelf_layout_manager.h" #include "ash/accelerators/accelerator_controller.h" #include "ash/accelerators/accelerator_table.h" #include "ash/ash_switches.h" #include "ash/display/display_manager.h" #include "ash/display/window_tree_host_manager.h" #include "ash/focus_cycler.h" #include "ash/root_window_controller.h" #include "ash/session/session_state_delegate.h" #include "ash/shelf/shelf.h" #include "ash/shelf/shelf_layout_manager_observer.h" #include "ash/shelf/shelf_view.h" #include "ash/shelf/shelf_widget.h" #include "ash/shell.h" #include "ash/shell_window_ids.h" #include "ash/system/status_area_widget.h" #include "ash/system/tray/system_tray.h" #include "ash/system/tray/system_tray_item.h" #include "ash/test/ash_test_base.h" #include "ash/test/display_manager_test_api.h" #include "ash/test/shelf_test_api.h" #include "ash/wm/window_state.h" #include "ash/wm/window_util.h" #include "base/command_line.h" #include "base/strings/utf_string_conversions.h" #include "ui/aura/client/aura_constants.h" #include "ui/aura/client/window_tree_client.h" #include "ui/aura/window.h" #include "ui/aura/window_event_dispatcher.h" #include "ui/compositor/layer.h" #include "ui/compositor/layer_animator.h" #include "ui/compositor/scoped_animation_duration_scale_mode.h" #include "ui/events/gesture_detection/gesture_configuration.h" #include "ui/events/test/event_generator.h" #include "ui/gfx/display.h" #include "ui/gfx/screen.h" #include "ui/views/controls/label.h" #include "ui/views/layout/fill_layout.h" #include "ui/views/view.h" #include "ui/views/widget/widget.h" #if defined(OS_WIN) #include "base/win/windows_version.h" #endif namespace ash { namespace { void StepWidgetLayerAnimatorToEnd(views::Widget* widget) { widget->GetNativeView()->layer()->GetAnimator()->Step( base::TimeTicks::Now() + base::TimeDelta::FromSeconds(1)); } ShelfWidget* GetShelfWidget() { return Shell::GetPrimaryRootWindowController()->shelf(); } ShelfLayoutManager* GetShelfLayoutManager() { return Shell::GetPrimaryRootWindowController()->GetShelfLayoutManager(); } SystemTray* GetSystemTray() { return Shell::GetPrimaryRootWindowController()->GetSystemTray(); } // Class which waits till the shelf finishes animating to the target size and // counts the number of animation steps. class ShelfAnimationWaiter : views::WidgetObserver { public: explicit ShelfAnimationWaiter(const gfx::Rect& target_bounds) : target_bounds_(target_bounds), animation_steps_(0), done_waiting_(false) { GetShelfWidget()->AddObserver(this); } ~ShelfAnimationWaiter() override { GetShelfWidget()->RemoveObserver(this); } // Wait till the shelf finishes animating to its expected bounds. void WaitTillDoneAnimating() { if (IsDoneAnimating()) done_waiting_ = true; else base::MessageLoop::current()->Run(); } // Returns true if the animation has completed and it was valid. bool WasValidAnimation() const { return done_waiting_ && animation_steps_ > 0; } private: // Returns true if shelf has finished animating to the target size. bool IsDoneAnimating() const { ShelfLayoutManager* layout_manager = GetShelfLayoutManager(); gfx::Rect current_bounds = GetShelfWidget()->GetWindowBoundsInScreen(); int size = layout_manager->PrimaryAxisValue(current_bounds.height(), current_bounds.width()); int desired_size = layout_manager->PrimaryAxisValue(target_bounds_.height(), target_bounds_.width()); return (size == desired_size); } // views::WidgetObserver override. void OnWidgetBoundsChanged(views::Widget* widget, const gfx::Rect& new_bounds) override { if (done_waiting_) return; ++animation_steps_; if (IsDoneAnimating()) { done_waiting_ = true; base::MessageLoop::current()->QuitWhenIdle(); } } gfx::Rect target_bounds_; int animation_steps_; bool done_waiting_; DISALLOW_COPY_AND_ASSIGN(ShelfAnimationWaiter); }; class ShelfDragCallback { public: ShelfDragCallback(const gfx::Rect& not_visible, const gfx::Rect& visible) : not_visible_bounds_(not_visible), visible_bounds_(visible), was_visible_on_drag_start_(false) { EXPECT_EQ(not_visible_bounds_.bottom(), visible_bounds_.bottom()); } virtual ~ShelfDragCallback() { } void ProcessScroll(ui::EventType type, const gfx::Vector2dF& delta) { if (GetShelfLayoutManager()->visibility_state() == ash::SHELF_HIDDEN) return; if (type == ui::ET_GESTURE_SCROLL_BEGIN) { scroll_ = gfx::Vector2dF(); was_visible_on_drag_start_ = GetShelfLayoutManager()->IsVisible(); return; } // The state of the shelf at the end of the gesture is tested separately. if (type == ui::ET_GESTURE_SCROLL_END) return; if (type == ui::ET_GESTURE_SCROLL_UPDATE) scroll_.Add(delta); gfx::Rect shelf_bounds = GetShelfWidget()->GetWindowBoundsInScreen(); if (GetShelfLayoutManager()->IsHorizontalAlignment()) { EXPECT_EQ(not_visible_bounds_.bottom(), shelf_bounds.bottom()); EXPECT_EQ(visible_bounds_.bottom(), shelf_bounds.bottom()); } else if (SHELF_ALIGNMENT_RIGHT == GetShelfLayoutManager()->GetAlignment()){ EXPECT_EQ(not_visible_bounds_.right(), shelf_bounds.right()); EXPECT_EQ(visible_bounds_.right(), shelf_bounds.right()); } else if (SHELF_ALIGNMENT_LEFT == GetShelfLayoutManager()->GetAlignment()) { EXPECT_EQ(not_visible_bounds_.x(), shelf_bounds.x()); EXPECT_EQ(visible_bounds_.x(), shelf_bounds.x()); } // if the shelf is being dimmed test dimmer bounds as well. if (GetShelfWidget()->GetDimsShelf()) EXPECT_EQ(GetShelfWidget()->GetWindowBoundsInScreen(), GetShelfWidget()->GetDimmerBoundsForTest()); // The shelf should never be smaller than the hidden state. EXPECT_GE(shelf_bounds.height(), not_visible_bounds_.height()); float scroll_delta = GetShelfLayoutManager()->PrimaryAxisValue( scroll_.y(), scroll_.x()); bool increasing_drag = GetShelfWidget()->shelf()->SelectValueForShelfAlignment( scroll_delta < 0, scroll_delta > 0, scroll_delta < 0, scroll_delta > 0); int shelf_size = GetShelfLayoutManager()->PrimaryAxisValue( shelf_bounds.height(), shelf_bounds.width()); int visible_bounds_size = GetShelfLayoutManager()->PrimaryAxisValue( visible_bounds_.height(), visible_bounds_.width()); int not_visible_bounds_size = GetShelfLayoutManager()->PrimaryAxisValue( not_visible_bounds_.height(), not_visible_bounds_.width()); if (was_visible_on_drag_start_) { if (increasing_drag) { // If dragging inwards from the visible state, then the shelf should // increase in size, but not more than the scroll delta. EXPECT_LE(visible_bounds_size, shelf_size); EXPECT_LE(std::abs(shelf_size - visible_bounds_size), std::abs(scroll_delta)); } else { if (shelf_size > not_visible_bounds_size) { // If dragging outwards from the visible state, then the shelf // should decrease in size, until it reaches the minimum size. EXPECT_EQ(shelf_size, visible_bounds_size - std::abs(scroll_delta)); } } } else { if (std::abs(scroll_delta) < visible_bounds_size - not_visible_bounds_size) { // Tests that the shelf sticks with the touch point during the drag // until the shelf is completely visible. EXPECT_EQ(shelf_size, not_visible_bounds_size + std::abs(scroll_delta)); } else { // Tests that after the shelf is completely visible, the shelf starts // resisting the drag. EXPECT_LT(shelf_size, not_visible_bounds_size + std::abs(scroll_delta)); } } } private: const gfx::Rect not_visible_bounds_; const gfx::Rect visible_bounds_; gfx::Vector2dF scroll_; bool was_visible_on_drag_start_; DISALLOW_COPY_AND_ASSIGN(ShelfDragCallback); }; class ShelfLayoutObserverTest : public ShelfLayoutManagerObserver { public: ShelfLayoutObserverTest() : changed_auto_hide_state_(false) { } ~ShelfLayoutObserverTest() override {} bool changed_auto_hide_state() const { return changed_auto_hide_state_; } private: void OnAutoHideStateChanged(ShelfAutoHideState new_state) override { changed_auto_hide_state_ = true; } bool changed_auto_hide_state_; DISALLOW_COPY_AND_ASSIGN(ShelfLayoutObserverTest); }; // Trivial item implementation that tracks its views for testing. class TestItem : public SystemTrayItem { public: TestItem() : SystemTrayItem(GetSystemTray()), tray_view_(nullptr), default_view_(nullptr), detailed_view_(nullptr), notification_view_(nullptr) {} views::View* CreateTrayView(user::LoginStatus status) override { tray_view_ = new views::View; // Add a label so it has non-zero width. tray_view_->SetLayoutManager(new views::FillLayout); tray_view_->AddChildView(new views::Label(base::UTF8ToUTF16("Tray"))); return tray_view_; } views::View* CreateDefaultView(user::LoginStatus status) override { default_view_ = new views::View; default_view_->SetLayoutManager(new views::FillLayout); default_view_->AddChildView(new views::Label(base::UTF8ToUTF16("Default"))); return default_view_; } views::View* CreateDetailedView(user::LoginStatus status) override { detailed_view_ = new views::View; detailed_view_->SetLayoutManager(new views::FillLayout); detailed_view_->AddChildView( new views::Label(base::UTF8ToUTF16("Detailed"))); return detailed_view_; } views::View* CreateNotificationView(user::LoginStatus status) override { notification_view_ = new views::View; return notification_view_; } void DestroyTrayView() override { tray_view_ = nullptr; } void DestroyDefaultView() override { default_view_ = nullptr; } void DestroyDetailedView() override { detailed_view_ = nullptr; } void DestroyNotificationView() override { notification_view_ = nullptr; } void UpdateAfterLoginStatusChange(user::LoginStatus status) override {} views::View* tray_view() const { return tray_view_; } views::View* default_view() const { return default_view_; } views::View* detailed_view() const { return detailed_view_; } views::View* notification_view() const { return notification_view_; } private: views::View* tray_view_; views::View* default_view_; views::View* detailed_view_; views::View* notification_view_; DISALLOW_COPY_AND_ASSIGN(TestItem); }; } // namespace class ShelfLayoutManagerTest : public ash::test::AshTestBase { public: ShelfLayoutManagerTest() {} void SetState(ShelfLayoutManager* shelf, ShelfVisibilityState state) { shelf->SetState(state); } void UpdateAutoHideStateNow() { GetShelfLayoutManager()->UpdateAutoHideStateNow(); } aura::Window* CreateTestWindow() { aura::Window* window = new aura::Window(nullptr); window->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_NORMAL); window->SetType(ui::wm::WINDOW_TYPE_NORMAL); window->Init(ui::LAYER_TEXTURED); ParentWindowInPrimaryRootWindow(window); return window; } aura::Window* CreateTestWindowInParent(aura::Window* root_window) { aura::Window* window = new aura::Window(nullptr); window->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_NORMAL); window->SetType(ui::wm::WINDOW_TYPE_NORMAL); window->Init(ui::LAYER_TEXTURED); aura::client::ParentWindowWithContext(window, root_window, gfx::Rect()); return window; } views::Widget* CreateTestWidgetWithParams( const views::Widget::InitParams& params) { views::Widget* out = new views::Widget; out->Init(params); out->Show(); return out; } // Create a simple widget attached to the current context (will // delete on TearDown). views::Widget* CreateTestWidget() { views::Widget::InitParams params(views::Widget::InitParams::TYPE_WINDOW); params.bounds = gfx::Rect(0, 0, 200, 200); params.context = CurrentContext(); return CreateTestWidgetWithParams(params); } void RunGestureDragTests(gfx::Vector2d); // Turn on the lock screen. void LockScreen() { Shell::GetInstance()->session_state_delegate()->LockScreen(); // The test session state delegate does not fire the lock state change. Shell::GetInstance()->OnLockStateChanged(true); } // Turn off the lock screen. void UnlockScreen() { Shell::GetInstance()->session_state_delegate()->UnlockScreen(); // The test session state delegate does not fire the lock state change. Shell::GetInstance()->OnLockStateChanged(false); } // Open the add user screen if |show| is true, otherwise end it. void ShowAddUserScreen(bool show) { SetUserAddingScreenRunning(show); ShelfLayoutManager* manager = GetShelfWidget()->shelf_layout_manager(); manager->SessionStateChanged( show ? SessionStateDelegate::SESSION_STATE_LOGIN_SECONDARY : SessionStateDelegate::SESSION_STATE_ACTIVE); } private: DISALLOW_COPY_AND_ASSIGN(ShelfLayoutManagerTest); }; void ShelfLayoutManagerTest::RunGestureDragTests(gfx::Vector2d delta) { ShelfLayoutManager* shelf = GetShelfLayoutManager(); shelf->SetAutoHideBehavior(SHELF_AUTO_HIDE_BEHAVIOR_NEVER); views::Widget* widget = new views::Widget; views::Widget::InitParams params(views::Widget::InitParams::TYPE_WINDOW); params.bounds = gfx::Rect(0, 0, 200, 200); params.context = CurrentContext(); widget->Init(params); widget->Show(); widget->Maximize(); // The time delta should be large enough to prevent accidental fling creation. const base::TimeDelta kTimeDelta = base::TimeDelta::FromMilliseconds(100); aura::Window* window = widget->GetNativeWindow(); shelf->LayoutShelf(); gfx::Rect shelf_shown = GetShelfWidget()->GetWindowBoundsInScreen(); gfx::Rect bounds_shelf = window->bounds(); EXPECT_EQ(SHELF_VISIBLE, shelf->visibility_state()); shelf->SetAutoHideBehavior(SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS); shelf->LayoutShelf(); EXPECT_EQ(SHELF_AUTO_HIDE_HIDDEN, shelf->auto_hide_state()); gfx::Rect bounds_noshelf = window->bounds(); gfx::Rect shelf_hidden = GetShelfWidget()->GetWindowBoundsInScreen(); shelf->SetAutoHideBehavior(SHELF_AUTO_HIDE_BEHAVIOR_NEVER); shelf->LayoutShelf(); ui::test::EventGenerator generator(Shell::GetPrimaryRootWindow()); const int kNumScrollSteps = 4; ShelfDragCallback handler(shelf_hidden, shelf_shown); // Swipe up on the shelf. This should not change any state. gfx::Point start = GetShelfWidget()->GetWindowBoundsInScreen().CenterPoint(); gfx::Point end = start + delta; // Swipe down on the shelf to hide it. generator.GestureScrollSequenceWithCallback( start, end, kTimeDelta, kNumScrollSteps, base::Bind(&ShelfDragCallback::ProcessScroll, base::Unretained(&handler))); EXPECT_EQ(SHELF_AUTO_HIDE, shelf->visibility_state()); EXPECT_EQ(SHELF_AUTO_HIDE_HIDDEN, shelf->auto_hide_state()); EXPECT_EQ(SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS, shelf->auto_hide_behavior()); EXPECT_NE(bounds_shelf.ToString(), window->bounds().ToString()); EXPECT_NE(shelf_shown.ToString(), GetShelfWidget()->GetWindowBoundsInScreen().ToString()); // Swipe up to show the shelf. generator.GestureScrollSequenceWithCallback( end, start, kTimeDelta, kNumScrollSteps, base::Bind(&ShelfDragCallback::ProcessScroll, base::Unretained(&handler))); EXPECT_EQ(SHELF_VISIBLE, shelf->visibility_state()); EXPECT_EQ(SHELF_AUTO_HIDE_BEHAVIOR_NEVER, shelf->auto_hide_behavior()); EXPECT_EQ(bounds_shelf.ToString(), window->bounds().ToString()); EXPECT_EQ(GetShelfWidget()->GetDimmerBoundsForTest(), GetShelfWidget()->GetWindowBoundsInScreen()); EXPECT_EQ(shelf_shown.ToString(), GetShelfWidget()->GetWindowBoundsInScreen().ToString()); // Swipe up again. The shelf should hide. end = start - delta; generator.GestureScrollSequenceWithCallback( start, end, kTimeDelta, kNumScrollSteps, base::Bind(&ShelfDragCallback::ProcessScroll, base::Unretained(&handler))); EXPECT_EQ(SHELF_AUTO_HIDE, shelf->visibility_state()); EXPECT_EQ(SHELF_AUTO_HIDE_HIDDEN, shelf->auto_hide_state()); EXPECT_EQ(SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS, shelf->auto_hide_behavior()); EXPECT_EQ(shelf_hidden.ToString(), GetShelfWidget()->GetWindowBoundsInScreen().ToString()); // Swipe up yet again to show it. end = start + delta; generator.GestureScrollSequenceWithCallback( end, start, kTimeDelta, kNumScrollSteps, base::Bind(&ShelfDragCallback::ProcessScroll, base::Unretained(&handler))); // Swipe down very little. It shouldn't change any state. if (GetShelfLayoutManager()->IsHorizontalAlignment()) end.set_y(start.y() + shelf_shown.height() * 3 / 10); else if (SHELF_ALIGNMENT_LEFT == GetShelfLayoutManager()->GetAlignment()) end.set_x(start.x() - shelf_shown.width() * 3 / 10); else if (SHELF_ALIGNMENT_RIGHT == GetShelfLayoutManager()->GetAlignment()) end.set_x(start.x() + shelf_shown.width() * 3 / 10); generator.GestureScrollSequence(start, end, kTimeDelta, 5); EXPECT_EQ(SHELF_VISIBLE, shelf->visibility_state()); EXPECT_EQ(SHELF_AUTO_HIDE_BEHAVIOR_NEVER, shelf->auto_hide_behavior()); EXPECT_EQ(bounds_shelf.ToString(), window->bounds().ToString()); EXPECT_EQ(shelf_shown.ToString(), GetShelfWidget()->GetWindowBoundsInScreen().ToString()); // Swipe down again to hide. end = start + delta; generator.GestureScrollSequenceWithCallback( start, end, kTimeDelta, kNumScrollSteps, base::Bind(&ShelfDragCallback::ProcessScroll, base::Unretained(&handler))); EXPECT_EQ(SHELF_AUTO_HIDE, shelf->visibility_state()); EXPECT_EQ(SHELF_AUTO_HIDE_HIDDEN, shelf->auto_hide_state()); EXPECT_EQ(SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS, shelf->auto_hide_behavior()); EXPECT_EQ(GetShelfWidget()->GetDimmerBoundsForTest(), gfx::Rect()); EXPECT_EQ(bounds_noshelf.ToString(), window->bounds().ToString()); EXPECT_EQ(shelf_hidden.ToString(), GetShelfWidget()->GetWindowBoundsInScreen().ToString()); // Swipe up in extended hit region to show it. gfx::Point extended_start = start; if (GetShelfLayoutManager()->IsHorizontalAlignment()) extended_start.set_y(GetShelfWidget()->GetWindowBoundsInScreen().y() -1); else if (SHELF_ALIGNMENT_LEFT == GetShelfLayoutManager()->GetAlignment()) extended_start.set_x( GetShelfWidget()->GetWindowBoundsInScreen().right() + 1); else if (SHELF_ALIGNMENT_RIGHT == GetShelfLayoutManager()->GetAlignment()) extended_start.set_x(GetShelfWidget()->GetWindowBoundsInScreen().x() - 1); end = extended_start - delta; generator.GestureScrollSequenceWithCallback( extended_start, end, kTimeDelta, kNumScrollSteps, base::Bind(&ShelfDragCallback::ProcessScroll, base::Unretained(&handler))); EXPECT_EQ(SHELF_VISIBLE, shelf->visibility_state()); EXPECT_EQ(SHELF_AUTO_HIDE_BEHAVIOR_NEVER, shelf->auto_hide_behavior()); EXPECT_EQ(bounds_shelf.ToString(), window->bounds().ToString()); EXPECT_EQ(GetShelfWidget()->GetDimmerBoundsForTest(), GetShelfWidget()->GetWindowBoundsInScreen()); EXPECT_EQ(shelf_shown.ToString(), GetShelfWidget()->GetWindowBoundsInScreen().ToString()); // Swipe down again to hide. end = start + delta; generator.GestureScrollSequenceWithCallback( start, end, kTimeDelta, kNumScrollSteps, base::Bind(&ShelfDragCallback::ProcessScroll, base::Unretained(&handler))); EXPECT_EQ(SHELF_AUTO_HIDE, shelf->visibility_state()); EXPECT_EQ(SHELF_AUTO_HIDE_HIDDEN, shelf->auto_hide_state()); EXPECT_EQ(SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS, shelf->auto_hide_behavior()); EXPECT_EQ(GetShelfWidget()->GetDimmerBoundsForTest(), gfx::Rect()); EXPECT_EQ(bounds_noshelf.ToString(), window->bounds().ToString()); EXPECT_EQ(shelf_hidden.ToString(), GetShelfWidget()->GetWindowBoundsInScreen().ToString()); // Swipe up outside the hit area. This should not change anything. gfx::Point outside_start = gfx::Point( (GetShelfWidget()->GetWindowBoundsInScreen().x() + GetShelfWidget()->GetWindowBoundsInScreen().right())/2, GetShelfWidget()->GetWindowBoundsInScreen().y() - 50); end = outside_start + delta; generator.GestureScrollSequence( outside_start, end, kTimeDelta, kNumScrollSteps); EXPECT_EQ(SHELF_AUTO_HIDE, shelf->visibility_state()); EXPECT_EQ(SHELF_AUTO_HIDE_HIDDEN, shelf->auto_hide_state()); EXPECT_EQ(SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS, shelf->auto_hide_behavior()); EXPECT_EQ(shelf_hidden.ToString(), GetShelfWidget()->GetWindowBoundsInScreen().ToString()); // Swipe up from below the shelf where a bezel would be, this should show the // shelf. gfx::Point below_start = start; if (GetShelfLayoutManager()->IsHorizontalAlignment()) below_start.set_y(GetShelfWidget()->GetWindowBoundsInScreen().bottom() + 1); else if (SHELF_ALIGNMENT_LEFT == GetShelfLayoutManager()->GetAlignment()) below_start.set_x( GetShelfWidget()->GetWindowBoundsInScreen().x() - 1); else if (SHELF_ALIGNMENT_RIGHT == GetShelfLayoutManager()->GetAlignment()) below_start.set_x(GetShelfWidget()->GetWindowBoundsInScreen().right() + 1); end = below_start - delta; generator.GestureScrollSequence( below_start, end, kTimeDelta, kNumScrollSteps); EXPECT_EQ(SHELF_VISIBLE, shelf->visibility_state()); EXPECT_EQ(SHELF_AUTO_HIDE_BEHAVIOR_NEVER, shelf->auto_hide_behavior()); EXPECT_EQ(bounds_shelf.ToString(), window->bounds().ToString()); EXPECT_EQ(GetShelfWidget()->GetDimmerBoundsForTest(), GetShelfWidget()->GetWindowBoundsInScreen()); EXPECT_EQ(shelf_shown.ToString(), GetShelfWidget()->GetWindowBoundsInScreen().ToString()); // Swipe down again to hide. end = start + delta; generator.GestureScrollSequenceWithCallback( start, end, kTimeDelta, kNumScrollSteps, base::Bind(&ShelfDragCallback::ProcessScroll, base::Unretained(&handler))); EXPECT_EQ(SHELF_AUTO_HIDE, shelf->visibility_state()); EXPECT_EQ(SHELF_AUTO_HIDE_HIDDEN, shelf->auto_hide_state()); EXPECT_EQ(SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS, shelf->auto_hide_behavior()); EXPECT_EQ(GetShelfWidget()->GetDimmerBoundsForTest(), gfx::Rect()); EXPECT_EQ(bounds_noshelf.ToString(), window->bounds().ToString()); EXPECT_EQ(shelf_hidden.ToString(), GetShelfWidget()->GetWindowBoundsInScreen().ToString()); // Put |widget| into fullscreen. Set the shelf to be auto hidden when |widget| // is fullscreen. (eg browser immersive fullscreen). widget->SetFullscreen(true); wm::GetWindowState(window)->set_hide_shelf_when_fullscreen(false); shelf->UpdateVisibilityState(); gfx::Rect bounds_fullscreen = window->bounds(); EXPECT_TRUE(widget->IsFullscreen()); EXPECT_NE(bounds_noshelf.ToString(), bounds_fullscreen.ToString()); // Swipe up. This should show the shelf. end = below_start - delta; generator.GestureScrollSequenceWithCallback( below_start, end, kTimeDelta, kNumScrollSteps, base::Bind(&ShelfDragCallback::ProcessScroll, base::Unretained(&handler))); EXPECT_EQ(SHELF_AUTO_HIDE, shelf->visibility_state()); EXPECT_EQ(SHELF_AUTO_HIDE_SHOWN, shelf->auto_hide_state()); EXPECT_EQ(SHELF_AUTO_HIDE_BEHAVIOR_NEVER, shelf->auto_hide_behavior()); EXPECT_EQ(shelf_shown.ToString(), GetShelfWidget()->GetWindowBoundsInScreen().ToString()); EXPECT_EQ(bounds_fullscreen.ToString(), window->bounds().ToString()); // Swipe up again. This should hide the shelf. generator.GestureScrollSequenceWithCallback( below_start, end, kTimeDelta, kNumScrollSteps, base::Bind(&ShelfDragCallback::ProcessScroll, base::Unretained(&handler))); EXPECT_EQ(SHELF_AUTO_HIDE, shelf->visibility_state()); EXPECT_EQ(SHELF_AUTO_HIDE_HIDDEN, shelf->auto_hide_state()); EXPECT_EQ(SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS, shelf->auto_hide_behavior()); EXPECT_EQ(shelf_hidden.ToString(), GetShelfWidget()->GetWindowBoundsInScreen().ToString()); EXPECT_EQ(bounds_fullscreen.ToString(), window->bounds().ToString()); // Set the shelf to be hidden when |widget| is fullscreen. (eg tab fullscreen // with or without immersive browser fullscreen). wm::GetWindowState(window)->set_hide_shelf_when_fullscreen(true); shelf->UpdateVisibilityState(); EXPECT_EQ(SHELF_HIDDEN, shelf->visibility_state()); EXPECT_EQ(SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS, shelf->auto_hide_behavior()); // Swipe-up. This should not change anything. end = start - delta; generator.GestureScrollSequenceWithCallback( below_start, end, kTimeDelta, kNumScrollSteps, base::Bind(&ShelfDragCallback::ProcessScroll, base::Unretained(&handler))); EXPECT_EQ(SHELF_HIDDEN, shelf->visibility_state()); EXPECT_EQ(SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS, shelf->auto_hide_behavior()); EXPECT_EQ(bounds_fullscreen.ToString(), window->bounds().ToString()); // Close actually, otherwise further event may be affected since widget // is fullscreen status. widget->Close(); RunAllPendingInMessageLoop(); // The shelf should be shown because there are no more visible windows. EXPECT_EQ(SHELF_AUTO_HIDE, shelf->visibility_state()); EXPECT_EQ(SHELF_AUTO_HIDE_SHOWN, shelf->auto_hide_state()); EXPECT_EQ(SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS, shelf->auto_hide_behavior()); // Swipe-up to hide. This should have no effect because there are no visible // windows. end = below_start - delta; generator.GestureScrollSequenceWithCallback( below_start, end, kTimeDelta, kNumScrollSteps, base::Bind(&ShelfDragCallback::ProcessScroll, base::Unretained(&handler))); EXPECT_EQ(SHELF_AUTO_HIDE, shelf->visibility_state()); EXPECT_EQ(SHELF_AUTO_HIDE_SHOWN, shelf->auto_hide_state()); EXPECT_EQ(SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS, shelf->auto_hide_behavior()); } // Need to be implemented. http://crbug.com/111279. #if defined(OS_WIN) #define MAYBE_SetVisible DISABLED_SetVisible #else #define MAYBE_SetVisible SetVisible #endif // Makes sure SetVisible updates work area and widget appropriately. TEST_F(ShelfLayoutManagerTest, MAYBE_SetVisible) { ShelfWidget* shelf = GetShelfWidget(); ShelfLayoutManager* manager = shelf->shelf_layout_manager(); // Force an initial layout. manager->LayoutShelf(); EXPECT_EQ(SHELF_VISIBLE, manager->visibility_state()); gfx::Rect status_bounds( shelf->status_area_widget()->GetWindowBoundsInScreen()); gfx::Rect shelf_bounds( shelf->GetWindowBoundsInScreen()); int shelf_height = manager->GetIdealBounds().height(); gfx::Screen* screen = gfx::Screen::GetScreen(); gfx::Display display = screen->GetDisplayNearestWindow( Shell::GetPrimaryRootWindow()); ASSERT_NE(-1, display.id()); // Bottom inset should be the max of widget heights. EXPECT_EQ(shelf_height, display.GetWorkAreaInsets().bottom()); // Hide the shelf. SetState(manager, SHELF_HIDDEN); // Run the animation to completion. StepWidgetLayerAnimatorToEnd(shelf); StepWidgetLayerAnimatorToEnd(shelf->status_area_widget()); EXPECT_EQ(SHELF_HIDDEN, manager->visibility_state()); display = screen->GetDisplayNearestWindow( Shell::GetPrimaryRootWindow()); EXPECT_EQ(0, display.GetWorkAreaInsets().bottom()); // Make sure the bounds of the two widgets changed. EXPECT_GE(shelf->GetNativeView()->bounds().y(), screen->GetPrimaryDisplay().bounds().bottom()); EXPECT_GE(shelf->status_area_widget()->GetNativeView()->bounds().y(), screen->GetPrimaryDisplay().bounds().bottom()); // And show it again. SetState(manager, SHELF_VISIBLE); // Run the animation to completion. StepWidgetLayerAnimatorToEnd(shelf); StepWidgetLayerAnimatorToEnd(shelf->status_area_widget()); EXPECT_EQ(SHELF_VISIBLE, manager->visibility_state()); display = screen->GetDisplayNearestWindow( Shell::GetPrimaryRootWindow()); EXPECT_EQ(shelf_height, display.GetWorkAreaInsets().bottom()); // Make sure the bounds of the two widgets changed. shelf_bounds = shelf->GetNativeView()->bounds(); EXPECT_LT(shelf_bounds.y(), screen->GetPrimaryDisplay().bounds().bottom()); status_bounds = shelf->status_area_widget()->GetNativeView()->bounds(); EXPECT_LT(status_bounds.y(), screen->GetPrimaryDisplay().bounds().bottom()); } // Makes sure shelf alignment is correct for lock screen. TEST_F(ShelfLayoutManagerTest, SideAlignmentInteractionWithLockScreen) { ShelfLayoutManager* manager = GetShelfWidget()->shelf_layout_manager(); manager->SetAlignment(SHELF_ALIGNMENT_LEFT); EXPECT_EQ(SHELF_ALIGNMENT_LEFT, manager->GetAlignment()); LockScreen(); EXPECT_EQ(SHELF_ALIGNMENT_BOTTOM, manager->GetAlignment()); UnlockScreen(); EXPECT_EQ(SHELF_ALIGNMENT_LEFT, manager->GetAlignment()); } // Makes sure shelf alignment is correct for add user screen. TEST_F(ShelfLayoutManagerTest, SideAlignmentInteractionWithAddUserScreen) { ShelfLayoutManager* manager = GetShelfWidget()->shelf_layout_manager(); manager->SetAlignment(SHELF_ALIGNMENT_LEFT); EXPECT_EQ(SHELF_ALIGNMENT_LEFT, manager->GetAlignment()); ShowAddUserScreen(true); EXPECT_EQ(SHELF_ALIGNMENT_BOTTOM, manager->GetAlignment()); ShowAddUserScreen(false); EXPECT_EQ(SHELF_ALIGNMENT_LEFT, manager->GetAlignment()); } // Makes sure shelf alignment is correct for login screen. TEST_F(ShelfLayoutManagerTest, SideAlignmentInteractionWithLoginScreen) { ShelfLayoutManager* manager = GetShelfWidget()->shelf_layout_manager(); ASSERT_EQ(SHELF_ALIGNMENT_BOTTOM, manager->GetAlignment()); SetUserLoggedIn(false); SetSessionStarted(false); // The test session state delegate does not fire state changes. SetSessionStarting(); manager->SessionStateChanged( Shell::GetInstance()->session_state_delegate()->GetSessionState()); // Login sets alignment preferences before the session completes startup. manager->SetAlignment(SHELF_ALIGNMENT_LEFT); SetUserLoggedIn(true); SetSessionStarted(true); EXPECT_EQ(SHELF_ALIGNMENT_LEFT, manager->GetAlignment()); // Ensure that the shelf has been notified. EXPECT_EQ(SHELF_ALIGNMENT_LEFT, GetShelfWidget()->shelf()->alignment()); } // Makes sure LayoutShelf invoked while animating cleans things up. TEST_F(ShelfLayoutManagerTest, LayoutShelfWhileAnimating) { ShelfWidget* shelf = GetShelfWidget(); // Force an initial layout. shelf->shelf_layout_manager()->LayoutShelf(); EXPECT_EQ(SHELF_VISIBLE, shelf->shelf_layout_manager()->visibility_state()); // Hide the shelf. SetState(shelf->shelf_layout_manager(), SHELF_HIDDEN); shelf->shelf_layout_manager()->LayoutShelf(); EXPECT_EQ(SHELF_HIDDEN, shelf->shelf_layout_manager()->visibility_state()); gfx::Display display = gfx::Screen::GetScreen()->GetDisplayNearestWindow( Shell::GetPrimaryRootWindow()); EXPECT_EQ(0, display.GetWorkAreaInsets().bottom()); // Make sure the bounds of the two widgets changed. EXPECT_GE(shelf->GetNativeView()->bounds().y(), gfx::Screen::GetScreen()->GetPrimaryDisplay().bounds().bottom()); EXPECT_GE(shelf->status_area_widget()->GetNativeView()->bounds().y(), gfx::Screen::GetScreen()->GetPrimaryDisplay().bounds().bottom()); } // Test that switching to a different visibility state does not restart the // shelf show / hide animation if it is already running. (crbug.com/250918) TEST_F(ShelfLayoutManagerTest, SetStateWhileAnimating) { ShelfWidget* shelf = GetShelfWidget(); SetState(shelf->shelf_layout_manager(), SHELF_VISIBLE); gfx::Rect initial_shelf_bounds = shelf->GetWindowBoundsInScreen(); gfx::Rect initial_status_bounds = shelf->status_area_widget()->GetWindowBoundsInScreen(); ui::ScopedAnimationDurationScaleMode normal_animation_duration( ui::ScopedAnimationDurationScaleMode::SLOW_DURATION); SetState(shelf->shelf_layout_manager(), SHELF_HIDDEN); SetState(shelf->shelf_layout_manager(), SHELF_VISIBLE); gfx::Rect current_shelf_bounds = shelf->GetWindowBoundsInScreen(); gfx::Rect current_status_bounds = shelf->status_area_widget()->GetWindowBoundsInScreen(); const int small_change = initial_shelf_bounds.height() / 2; EXPECT_LE( std::abs(initial_shelf_bounds.height() - current_shelf_bounds.height()), small_change); EXPECT_LE( std::abs(initial_status_bounds.height() - current_status_bounds.height()), small_change); } // Makes sure the shelf is sized when the status area changes size. TEST_F(ShelfLayoutManagerTest, ShelfUpdatedWhenStatusAreaChangesSize) { Shelf* shelf = Shelf::ForPrimaryDisplay(); ASSERT_TRUE(shelf); ShelfWidget* shelf_widget = GetShelfWidget(); ASSERT_TRUE(shelf_widget); ASSERT_TRUE(shelf_widget->status_area_widget()); shelf_widget->status_area_widget()->SetBounds( gfx::Rect(0, 0, 200, 200)); EXPECT_EQ(200, shelf_widget->GetContentsView()->width() - test::ShelfTestAPI(shelf).shelf_view()->width()); } #if defined(OS_WIN) // RootWindow and Display can't resize on Windows Ash. http://crbug.com/165962 #define MAYBE_AutoHide DISABLED_AutoHide #else #define MAYBE_AutoHide AutoHide #endif // Various assertions around auto-hide. TEST_F(ShelfLayoutManagerTest, MAYBE_AutoHide) { aura::Window* root = Shell::GetPrimaryRootWindow(); ui::test::EventGenerator generator(root, root); generator.MoveMouseTo(0, 0); ShelfLayoutManager* shelf = GetShelfLayoutManager(); shelf->SetAutoHideBehavior(ash::SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS); views::Widget* widget = new views::Widget; views::Widget::InitParams params(views::Widget::InitParams::TYPE_WINDOW); params.bounds = gfx::Rect(0, 0, 200, 200); params.context = CurrentContext(); // Widget is now owned by the parent window. widget->Init(params); widget->Maximize(); widget->Show(); EXPECT_EQ(SHELF_AUTO_HIDE, shelf->visibility_state()); EXPECT_EQ(SHELF_AUTO_HIDE_HIDDEN, shelf->auto_hide_state()); // LayoutShelf() forces the animation to completion, at which point the // shelf should go off the screen. shelf->LayoutShelf(); EXPECT_EQ(root->bounds().bottom() - ShelfLayoutManager::kAutoHideSize, GetShelfWidget()->GetWindowBoundsInScreen().y()); EXPECT_EQ(root->bounds().bottom() - ShelfLayoutManager::kAutoHideSize, gfx::Screen::GetScreen() ->GetDisplayNearestWindow(root) .work_area() .bottom()); // Move the mouse to the bottom of the screen. generator.MoveMouseTo(0, root->bounds().bottom() - 1); // Shelf should be shown again (but it shouldn't have changed the work area). SetState(shelf, SHELF_AUTO_HIDE); EXPECT_EQ(SHELF_AUTO_HIDE_SHOWN, shelf->auto_hide_state()); shelf->LayoutShelf(); EXPECT_EQ(root->bounds().bottom() - shelf->GetIdealBounds().height(), GetShelfWidget()->GetWindowBoundsInScreen().y()); EXPECT_EQ(root->bounds().bottom() - ShelfLayoutManager::kAutoHideSize, gfx::Screen::GetScreen() ->GetDisplayNearestWindow(root) .work_area() .bottom()); // Move mouse back up. generator.MoveMouseTo(0, 0); SetState(shelf, SHELF_AUTO_HIDE); EXPECT_EQ(SHELF_AUTO_HIDE_HIDDEN, shelf->auto_hide_state()); shelf->LayoutShelf(); EXPECT_EQ(root->bounds().bottom() - ShelfLayoutManager::kAutoHideSize, GetShelfWidget()->GetWindowBoundsInScreen().y()); // Drag mouse to bottom of screen. generator.PressLeftButton(); generator.MoveMouseTo(0, root->bounds().bottom() - 1); UpdateAutoHideStateNow(); EXPECT_EQ(SHELF_AUTO_HIDE_HIDDEN, shelf->auto_hide_state()); generator.ReleaseLeftButton(); generator.MoveMouseTo(1, root->bounds().bottom() - 1); UpdateAutoHideStateNow(); EXPECT_EQ(SHELF_AUTO_HIDE_SHOWN, shelf->auto_hide_state()); generator.PressLeftButton(); generator.MoveMouseTo(1, root->bounds().bottom() - 1); UpdateAutoHideStateNow(); EXPECT_EQ(SHELF_AUTO_HIDE_SHOWN, shelf->auto_hide_state()); } // Test the behavior of the shelf when it is auto hidden and it is on the // boundary between the primary and the secondary display. TEST_F(ShelfLayoutManagerTest, AutoHideShelfOnScreenBoundary) { if (!SupportsMultipleDisplays()) return; UpdateDisplay("800x600,800x600"); Shell::GetInstance()->display_manager()->SetLayoutForCurrentDisplays( test::CreateDisplayLayout(DisplayPlacement::RIGHT, 0)); // Put the primary monitor's shelf on the display boundary. ShelfLayoutManager* shelf = GetShelfLayoutManager(); shelf->SetAlignment(SHELF_ALIGNMENT_RIGHT); // Create a window because the shelf is always shown when no windows are // visible. CreateTestWidget(); aura::Window::Windows root_windows = Shell::GetAllRootWindows(); ASSERT_EQ(root_windows[0], GetShelfWidget()->GetNativeWindow()->GetRootWindow()); shelf->SetAutoHideBehavior(ash::SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS); EXPECT_EQ(SHELF_AUTO_HIDE, shelf->visibility_state()); int right_edge = root_windows[0]->GetBoundsInScreen().right() - 1; int y = root_windows[0]->GetBoundsInScreen().y(); // Start off the mouse nowhere near the shelf; the shelf should be hidden. ui::test::EventGenerator& generator(GetEventGenerator()); generator.MoveMouseTo(right_edge - 50, y); UpdateAutoHideStateNow(); EXPECT_EQ(SHELF_AUTO_HIDE_HIDDEN, shelf->auto_hide_state()); // Moving the mouse over the light bar (but not to the edge of the screen) // should show the shelf. generator.MoveMouseTo(right_edge - 1, y); UpdateAutoHideStateNow(); EXPECT_EQ(SHELF_AUTO_HIDE_SHOWN, shelf->auto_hide_state()); EXPECT_EQ(right_edge - 1, gfx::Screen::GetScreen()->GetCursorScreenPoint().x()); // Moving the mouse off the light bar should hide the shelf. generator.MoveMouseTo(right_edge - 50, y); UpdateAutoHideStateNow(); EXPECT_EQ(SHELF_AUTO_HIDE_HIDDEN, shelf->auto_hide_state()); // Moving the mouse to the right edge of the screen crossing the light bar // should show the shelf despite the mouse cursor getting warped to the // secondary display. generator.MoveMouseTo(right_edge - 1, y); generator.MoveMouseTo(right_edge, y); UpdateAutoHideStateNow(); EXPECT_NE(right_edge - 1, gfx::Screen::GetScreen()->GetCursorScreenPoint().x()); EXPECT_EQ(SHELF_AUTO_HIDE_SHOWN, shelf->auto_hide_state()); // Hide the shelf. generator.MoveMouseTo(right_edge - 50, y); UpdateAutoHideStateNow(); EXPECT_EQ(SHELF_AUTO_HIDE_HIDDEN, shelf->auto_hide_state()); // Moving the mouse to the right edge of the screen crossing the light bar and // overshooting by a lot should keep the shelf hidden. generator.MoveMouseTo(right_edge - 1, y); generator.MoveMouseTo(right_edge + 50, y); UpdateAutoHideStateNow(); EXPECT_EQ(SHELF_AUTO_HIDE_HIDDEN, shelf->auto_hide_state()); // Moving the mouse to the right edge of the screen crossing the light bar and // overshooting a bit should show the shelf. generator.MoveMouseTo(right_edge - 1, y); generator.MoveMouseTo(right_edge + 2, y); UpdateAutoHideStateNow(); EXPECT_EQ(SHELF_AUTO_HIDE_SHOWN, shelf->auto_hide_state()); // Keeping the mouse close to the left edge of the secondary display after the // shelf is shown should keep the shelf shown. generator.MoveMouseTo(right_edge + 2, y + 1); UpdateAutoHideStateNow(); EXPECT_EQ(SHELF_AUTO_HIDE_SHOWN, shelf->auto_hide_state()); // Moving the mouse far from the left edge of the secondary display should // hide the shelf. generator.MoveMouseTo(right_edge + 50, y); UpdateAutoHideStateNow(); EXPECT_EQ(SHELF_AUTO_HIDE_HIDDEN, shelf->auto_hide_state()); // Moving to the left edge of the secondary display without first crossing // the primary display's right aligned shelf first should not show the shelf. generator.MoveMouseTo(right_edge + 2, y); UpdateAutoHideStateNow(); EXPECT_EQ(SHELF_AUTO_HIDE_HIDDEN, shelf->auto_hide_state()); } // Assertions around the lock screen showing. TEST_F(ShelfLayoutManagerTest, VisibleWhenLockScreenShowing) { if (!SupportsHostWindowResize()) return; // Since ShelfLayoutManager queries for mouse location, move the mouse so // it isn't over the shelf. ui::test::EventGenerator generator(Shell::GetPrimaryRootWindow(), gfx::Point()); generator.MoveMouseTo(0, 0); ShelfLayoutManager* shelf = GetShelfLayoutManager(); shelf->SetAutoHideBehavior(ash::SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS); views::Widget* widget = new views::Widget; views::Widget::InitParams params(views::Widget::InitParams::TYPE_WINDOW); params.bounds = gfx::Rect(0, 0, 200, 200); params.context = CurrentContext(); // Widget is now owned by the parent window. widget->Init(params); widget->Maximize(); widget->Show(); EXPECT_EQ(SHELF_AUTO_HIDE, shelf->visibility_state()); EXPECT_EQ(SHELF_AUTO_HIDE_HIDDEN, shelf->auto_hide_state()); aura::Window* root = Shell::GetPrimaryRootWindow(); // LayoutShelf() forces the animation to completion, at which point the // shelf should go off the screen. shelf->LayoutShelf(); EXPECT_EQ(root->bounds().bottom() - ShelfLayoutManager::kAutoHideSize, GetShelfWidget()->GetWindowBoundsInScreen().y()); aura::Window* lock_container = Shell::GetContainer( Shell::GetPrimaryRootWindow(), kShellWindowId_LockScreenContainer); views::Widget* lock_widget = new views::Widget; views::Widget::InitParams lock_params( views::Widget::InitParams::TYPE_WINDOW); lock_params.bounds = gfx::Rect(0, 0, 200, 200); params.context = CurrentContext(); lock_params.parent = lock_container; // Widget is now owned by the parent window. lock_widget->Init(lock_params); lock_widget->Maximize(); lock_widget->Show(); // Lock the screen. LockScreen(); // Showing a widget in the lock screen should force the shelf to be visibile. EXPECT_EQ(SHELF_VISIBLE, shelf->visibility_state()); UnlockScreen(); EXPECT_EQ(SHELF_AUTO_HIDE, shelf->visibility_state()); } // Assertions around SetAutoHideBehavior. TEST_F(ShelfLayoutManagerTest, SetAutoHideBehavior) { // Since ShelfLayoutManager queries for mouse location, move the mouse so // it isn't over the shelf. ui::test::EventGenerator generator(Shell::GetPrimaryRootWindow(), gfx::Point()); generator.MoveMouseTo(0, 0); ShelfLayoutManager* shelf = GetShelfLayoutManager(); views::Widget* widget = new views::Widget; views::Widget::InitParams params(views::Widget::InitParams::TYPE_WINDOW); params.bounds = gfx::Rect(0, 0, 200, 200); params.context = CurrentContext(); // Widget is now owned by the parent window. widget->Init(params); widget->Show(); aura::Window* window = widget->GetNativeWindow(); gfx::Rect display_bounds( gfx::Screen::GetScreen()->GetDisplayNearestWindow(window).bounds()); shelf->SetAutoHideBehavior(SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS); EXPECT_EQ(SHELF_AUTO_HIDE, shelf->visibility_state()); shelf->SetAutoHideBehavior(SHELF_AUTO_HIDE_BEHAVIOR_NEVER); EXPECT_EQ(SHELF_VISIBLE, shelf->visibility_state()); widget->Maximize(); EXPECT_EQ(SHELF_VISIBLE, shelf->visibility_state()); EXPECT_EQ(gfx::Screen::GetScreen() ->GetDisplayNearestWindow(window) .work_area() .bottom(), widget->GetWorkAreaBoundsInScreen().bottom()); shelf->SetAutoHideBehavior(SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS); EXPECT_EQ(SHELF_AUTO_HIDE, shelf->visibility_state()); EXPECT_EQ(gfx::Screen::GetScreen() ->GetDisplayNearestWindow(window) .work_area() .bottom(), widget->GetWorkAreaBoundsInScreen().bottom()); ui::ScopedAnimationDurationScaleMode animation_duration( ui::ScopedAnimationDurationScaleMode::SLOW_DURATION); shelf->SetAutoHideBehavior(SHELF_AUTO_HIDE_BEHAVIOR_NEVER); ShelfWidget* shelf_widget = GetShelfWidget(); EXPECT_TRUE(shelf_widget->status_area_widget()->IsVisible()); StepWidgetLayerAnimatorToEnd(shelf_widget); StepWidgetLayerAnimatorToEnd(shelf_widget->status_area_widget()); EXPECT_EQ(SHELF_VISIBLE, shelf->visibility_state()); EXPECT_EQ(gfx::Screen::GetScreen() ->GetDisplayNearestWindow(window) .work_area() .bottom(), widget->GetWorkAreaBoundsInScreen().bottom()); } // Basic assertions around the dimming of the shelf. TEST_F(ShelfLayoutManagerTest, DimmingBehavior) { // Since ShelfLayoutManager queries for mouse location, move the mouse so // it isn't over the shelf. ui::test::EventGenerator generator(Shell::GetPrimaryRootWindow(), gfx::Point()); generator.MoveMouseTo(0, 0); ShelfLayoutManager* shelf = GetShelfLayoutManager(); shelf->shelf_widget()->DisableDimmingAnimationsForTest(); views::Widget* widget = new views::Widget; views::Widget::InitParams params(views::Widget::InitParams::TYPE_WINDOW); params.bounds = gfx::Rect(0, 0, 200, 200); params.context = CurrentContext(); // Widget is now owned by the parent window. widget->Init(params); widget->Show(); aura::Window* window = widget->GetNativeWindow(); gfx::Rect display_bounds( gfx::Screen::GetScreen()->GetDisplayNearestWindow(window).bounds()); gfx::Point off_shelf = display_bounds.CenterPoint(); gfx::Point on_shelf = shelf->shelf_widget()->GetWindowBoundsInScreen().CenterPoint(); // Test there is no dimming object active at this point. generator.MoveMouseTo(on_shelf.x(), on_shelf.y()); EXPECT_EQ(-1, shelf->shelf_widget()->GetDimmingAlphaForTest()); generator.MoveMouseTo(off_shelf.x(), off_shelf.y()); EXPECT_EQ(-1, shelf->shelf_widget()->GetDimmingAlphaForTest()); // After maximization, the shelf should be visible and the dimmer created. widget->Maximize(); on_shelf = shelf->shelf_widget()->GetWindowBoundsInScreen().CenterPoint(); EXPECT_LT(0, shelf->shelf_widget()->GetDimmingAlphaForTest()); // Moving the mouse off the shelf should dim the bar. generator.MoveMouseTo(off_shelf.x(), off_shelf.y()); EXPECT_LT(0, shelf->shelf_widget()->GetDimmingAlphaForTest()); // Adding touch events outside the shelf should still keep the shelf in // dimmed state. generator.PressTouch(); generator.MoveTouch(off_shelf); EXPECT_LT(0, shelf->shelf_widget()->GetDimmingAlphaForTest()); // Move the touch into the shelf area should undim. generator.MoveTouch(on_shelf); EXPECT_EQ(0, shelf->shelf_widget()->GetDimmingAlphaForTest()); generator.ReleaseTouch(); // And a release dims again. EXPECT_LT(0, shelf->shelf_widget()->GetDimmingAlphaForTest()); // Moving the mouse on the shelf should undim the bar. generator.MoveMouseTo(on_shelf); EXPECT_EQ(0, shelf->shelf_widget()->GetDimmingAlphaForTest()); // No matter what the touch events do, the shelf should stay undimmed. generator.PressTouch(); generator.MoveTouch(off_shelf); EXPECT_EQ(0, shelf->shelf_widget()->GetDimmingAlphaForTest()); generator.MoveTouch(on_shelf); EXPECT_EQ(0, shelf->shelf_widget()->GetDimmingAlphaForTest()); generator.MoveTouch(off_shelf); EXPECT_EQ(0, shelf->shelf_widget()->GetDimmingAlphaForTest()); generator.MoveTouch(on_shelf); generator.ReleaseTouch(); // After restore, the dimming object should be deleted again. widget->Restore(); EXPECT_EQ(-1, shelf->shelf_widget()->GetDimmingAlphaForTest()); } // Test that dimming works correctly with multiple displays. TEST_F(ShelfLayoutManagerTest, DimmingBehaviorDualDisplay) { if (!SupportsMultipleDisplays()) return; // Create two displays. Shell* shell = Shell::GetInstance(); UpdateDisplay("0+0-200x200,+200+0-100x100"); EXPECT_EQ(2U, shell->display_manager()->GetNumDisplays()); WindowTreeHostManager* window_tree_host_manager = shell->window_tree_host_manager(); aura::Window::Windows root_windows = window_tree_host_manager->GetAllRootWindows(); EXPECT_EQ(root_windows.size(), 2U); std::vector shelf_widgets; for (auto& root_window : root_windows) { ShelfLayoutManager* shelf = GetRootWindowController(root_window)->GetShelfLayoutManager(); shelf_widgets.push_back(shelf->shelf_widget()); // For disabling the dimming animation to work, the animation must be // disabled prior to creating the dimmer. shelf_widgets.back()->DisableDimmingAnimationsForTest(); // Create a maximized window to create the dimmer. views::Widget* widget = new views::Widget; views::Widget::InitParams params(views::Widget::InitParams::TYPE_WINDOW); params.context = root_window; params.bounds = root_window->GetBoundsInScreen(); params.show_state = ui::SHOW_STATE_MAXIMIZED; widget->Init(params); widget->Show(); } ui::test::EventGenerator& generator(GetEventGenerator()); generator.MoveMouseTo(root_windows[0]->GetBoundsInScreen().CenterPoint()); EXPECT_LT(0, shelf_widgets[0]->GetDimmingAlphaForTest()); EXPECT_LT(0, shelf_widgets[1]->GetDimmingAlphaForTest()); generator.MoveMouseTo( shelf_widgets[0]->GetWindowBoundsInScreen().CenterPoint()); EXPECT_EQ(0, shelf_widgets[0]->GetDimmingAlphaForTest()); EXPECT_LT(0, shelf_widgets[1]->GetDimmingAlphaForTest()); generator.MoveMouseTo( shelf_widgets[1]->GetWindowBoundsInScreen().CenterPoint()); EXPECT_LT(0, shelf_widgets[0]->GetDimmingAlphaForTest()); EXPECT_EQ(0, shelf_widgets[1]->GetDimmingAlphaForTest()); generator.MoveMouseTo(root_windows[1]->GetBoundsInScreen().CenterPoint()); EXPECT_LT(0, shelf_widgets[0]->GetDimmingAlphaForTest()); EXPECT_LT(0, shelf_widgets[1]->GetDimmingAlphaForTest()); } // Assertions around the dimming of the shelf in conjunction with menus. TEST_F(ShelfLayoutManagerTest, DimmingBehaviorWithMenus) { // Since ShelfLayoutManager queries for mouse location, move the mouse so // it isn't over the shelf. ui::test::EventGenerator generator(Shell::GetPrimaryRootWindow(), gfx::Point()); generator.MoveMouseTo(0, 0); ShelfLayoutManager* shelf = GetShelfLayoutManager(); shelf->shelf_widget()->DisableDimmingAnimationsForTest(); views::Widget* widget = new views::Widget; views::Widget::InitParams params(views::Widget::InitParams::TYPE_WINDOW); params.bounds = gfx::Rect(0, 0, 200, 200); params.context = CurrentContext(); // Widget is now owned by the parent window. widget->Init(params); widget->Show(); aura::Window* window = widget->GetNativeWindow(); gfx::Rect display_bounds( gfx::Screen::GetScreen()->GetDisplayNearestWindow(window).bounds()); // After maximization, the shelf should be visible and the dimmer created. widget->Maximize(); gfx::Point off_shelf = display_bounds.CenterPoint(); gfx::Point on_shelf = shelf->shelf_widget()->GetWindowBoundsInScreen().CenterPoint(); // Moving the mouse on the shelf should undim the bar. generator.MoveMouseTo(on_shelf.x(), on_shelf.y()); EXPECT_EQ(0, shelf->shelf_widget()->GetDimmingAlphaForTest()); // Simulate a menu opening. shelf->shelf_widget()->ForceUndimming(true); // Moving the mouse off the shelf should not dim the bar. generator.MoveMouseTo(off_shelf.x(), off_shelf.y()); EXPECT_EQ(0, shelf->shelf_widget()->GetDimmingAlphaForTest()); // No matter what the touch events do, the shelf should stay undimmed. generator.PressTouch(); generator.MoveTouch(off_shelf); EXPECT_EQ(0, shelf->shelf_widget()->GetDimmingAlphaForTest()); generator.MoveTouch(on_shelf); EXPECT_EQ(0, shelf->shelf_widget()->GetDimmingAlphaForTest()); generator.MoveTouch(off_shelf); EXPECT_EQ(0, shelf->shelf_widget()->GetDimmingAlphaForTest()); generator.ReleaseTouch(); EXPECT_EQ(0, shelf->shelf_widget()->GetDimmingAlphaForTest()); // "Closing the menu" should now turn off the menu since no event is inside // the shelf any longer. shelf->shelf_widget()->ForceUndimming(false); EXPECT_LT(0, shelf->shelf_widget()->GetDimmingAlphaForTest()); // Moving the mouse again on the shelf which should undim the bar again. // This time we check that the bar stays undimmed when the mouse remains on // the bar and the "menu gets closed". generator.MoveMouseTo(on_shelf.x(), on_shelf.y()); EXPECT_EQ(0, shelf->shelf_widget()->GetDimmingAlphaForTest()); shelf->shelf_widget()->ForceUndimming(true); generator.MoveMouseTo(off_shelf.x(), off_shelf.y()); EXPECT_EQ(0, shelf->shelf_widget()->GetDimmingAlphaForTest()); generator.MoveMouseTo(on_shelf.x(), on_shelf.y()); EXPECT_EQ(0, shelf->shelf_widget()->GetDimmingAlphaForTest()); shelf->shelf_widget()->ForceUndimming(true); EXPECT_EQ(0, shelf->shelf_widget()->GetDimmingAlphaForTest()); } // Verifies the shelf is visible when status/shelf is focused. TEST_F(ShelfLayoutManagerTest, VisibleWhenStatusOrShelfFocused) { // Since ShelfLayoutManager queries for mouse location, move the mouse so // it isn't over the shelf. ui::test::EventGenerator generator(Shell::GetPrimaryRootWindow(), gfx::Point()); generator.MoveMouseTo(0, 0); ShelfLayoutManager* shelf = GetShelfLayoutManager(); views::Widget* widget = new views::Widget; views::Widget::InitParams params(views::Widget::InitParams::TYPE_WINDOW); params.bounds = gfx::Rect(0, 0, 200, 200); params.context = CurrentContext(); // Widget is now owned by the parent window. widget->Init(params); widget->Show(); shelf->SetAutoHideBehavior(SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS); EXPECT_EQ(SHELF_AUTO_HIDE, shelf->visibility_state()); EXPECT_EQ(SHELF_AUTO_HIDE_HIDDEN, shelf->auto_hide_state()); // Focus the shelf. Have to go through the focus cycler as normal focus // requests to it do nothing. GetShelfWidget()->GetFocusCycler()->RotateFocus(FocusCycler::FORWARD); EXPECT_EQ(SHELF_AUTO_HIDE_SHOWN, shelf->auto_hide_state()); widget->Activate(); EXPECT_EQ(SHELF_AUTO_HIDE_HIDDEN, shelf->auto_hide_state()); // Trying to activate the status should fail, since we only allow activating // it when the user is using the keyboard (i.e. through FocusCycler). GetShelfWidget()->status_area_widget()->Activate(); EXPECT_EQ(SHELF_AUTO_HIDE_HIDDEN, shelf->auto_hide_state()); GetShelfWidget()->GetFocusCycler()->RotateFocus(FocusCycler::FORWARD); EXPECT_EQ(SHELF_AUTO_HIDE_SHOWN, shelf->auto_hide_state()); } // Makes sure shelf will be visible when app list opens as shelf is in // SHELF_VISIBLE state,and toggling app list won't change shelf // visibility state. TEST_F(ShelfLayoutManagerTest, OpenAppListWithShelfVisibleState) { Shell* shell = Shell::GetInstance(); ShelfLayoutManager* shelf = GetShelfLayoutManager(); shelf->LayoutShelf(); shelf->SetAutoHideBehavior(SHELF_AUTO_HIDE_BEHAVIOR_NEVER); // Create a normal unmaximized windowm shelf should be visible. aura::Window* window = CreateTestWindow(); window->SetBounds(gfx::Rect(0, 0, 100, 100)); window->Show(); EXPECT_FALSE(shell->GetAppListTargetVisibility()); EXPECT_EQ(SHELF_VISIBLE, shelf->visibility_state()); // Show app list and the shelf stays visible. shell->ShowAppList(nullptr); EXPECT_TRUE(shell->GetAppListTargetVisibility()); EXPECT_EQ(SHELF_VISIBLE, shelf->visibility_state()); // Hide app list and the shelf stays visible. shell->DismissAppList(); EXPECT_FALSE(shell->GetAppListTargetVisibility()); EXPECT_EQ(SHELF_VISIBLE, shelf->visibility_state()); } // Makes sure shelf will be shown with SHELF_AUTO_HIDE_SHOWN state // when app list opens as shelf is in SHELF_AUTO_HIDE state, and // toggling app list won't change shelf visibility state. TEST_F(ShelfLayoutManagerTest, OpenAppListWithShelfAutoHideState) { Shell* shell = Shell::GetInstance(); ShelfLayoutManager* shelf = GetShelfLayoutManager(); shelf->LayoutShelf(); shelf->SetAutoHideBehavior(SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS); // Create a window and show it in maximized state. aura::Window* window = CreateTestWindow(); window->SetBounds(gfx::Rect(0, 0, 100, 100)); window->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_MAXIMIZED); window->Show(); wm::ActivateWindow(window); EXPECT_FALSE(shell->GetAppListTargetVisibility()); EXPECT_EQ(SHELF_AUTO_HIDE, shelf->visibility_state()); // Show app list. shell->ShowAppList(nullptr); // The shelf's auto hide state won't be changed until the timer fires, so // calling shell->UpdateShelfVisibility() is kind of manually helping it to // update the state. shell->UpdateShelfVisibility(); EXPECT_TRUE(shell->GetAppListTargetVisibility()); EXPECT_EQ(SHELF_AUTO_HIDE, shelf->visibility_state()); EXPECT_EQ(SHELF_AUTO_HIDE_SHOWN, shelf->auto_hide_state()); // Hide app list. shell->DismissAppList(); EXPECT_FALSE(shell->GetAppListTargetVisibility()); EXPECT_EQ(SHELF_AUTO_HIDE, shelf->visibility_state()); } // Makes sure that when we have dual displays, with one or both shelves are set // to AutoHide, viewing the AppList on one of them doesn't unhide the other // hidden shelf. TEST_F(ShelfLayoutManagerTest, DualDisplayOpenAppListWithShelfAutoHideState) { if (!SupportsMultipleDisplays()) return; // Create two displays. Shell* shell = Shell::GetInstance(); DisplayManager* display_manager = shell->display_manager(); EXPECT_EQ(1U, display_manager->GetNumDisplays()); UpdateDisplay("0+0-200x200,+200+0-100x100"); EXPECT_EQ(2U, display_manager->GetNumDisplays()); WindowTreeHostManager* window_tree_host_manager = shell->window_tree_host_manager(); aura::Window::Windows root_windows = window_tree_host_manager->GetAllRootWindows(); EXPECT_EQ(root_windows.size(), 2U); // Get the shelves in both displays and set them to be 'AutoHide'. ShelfLayoutManager* shelf_1 = GetRootWindowController(root_windows[0])->GetShelfLayoutManager(); ShelfLayoutManager* shelf_2 = GetRootWindowController(root_windows[1])->GetShelfLayoutManager(); EXPECT_NE(shelf_1, shelf_2); EXPECT_NE(shelf_1->shelf_widget()->GetNativeWindow()->GetRootWindow(), shelf_2->shelf_widget()->GetNativeWindow()->GetRootWindow()); shelf_1->SetAutoHideBehavior(SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS); shelf_1->LayoutShelf(); shelf_2->SetAutoHideBehavior(SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS); shelf_2->LayoutShelf(); // Create a window in each display and show them in maximized state. aura::Window* window_1 = CreateTestWindowInParent(root_windows[0]); window_1->SetBounds(gfx::Rect(0, 0, 100, 100)); window_1->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_MAXIMIZED); window_1->Show(); aura::Window* window_2 = CreateTestWindowInParent(root_windows[1]); window_2->SetBounds(gfx::Rect(201, 0, 100, 100)); window_2->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_MAXIMIZED); window_2->Show(); EXPECT_EQ(shelf_1->shelf_widget()->GetNativeWindow()->GetRootWindow(), window_1->GetRootWindow()); EXPECT_EQ(shelf_2->shelf_widget()->GetNativeWindow()->GetRootWindow(), window_2->GetRootWindow()); // Activate one window in one display and manually trigger the update of shelf // visibility. wm::ActivateWindow(window_1); shell->UpdateShelfVisibility(); EXPECT_FALSE(shell->GetAppListTargetVisibility()); EXPECT_EQ(SHELF_AUTO_HIDE, shelf_1->visibility_state()); EXPECT_EQ(SHELF_AUTO_HIDE, shelf_2->visibility_state()); EXPECT_EQ(SHELF_AUTO_HIDE_HIDDEN, shelf_1->auto_hide_state()); EXPECT_EQ(SHELF_AUTO_HIDE_HIDDEN, shelf_2->auto_hide_state()); // Show app list. shell->ShowAppList(nullptr); shell->UpdateShelfVisibility(); // Only the shelf in the active display should be shown, the other is hidden. EXPECT_TRUE(shell->GetAppListTargetVisibility()); EXPECT_EQ(SHELF_AUTO_HIDE, shelf_1->visibility_state()); EXPECT_EQ(SHELF_AUTO_HIDE_SHOWN, shelf_1->auto_hide_state()); EXPECT_EQ(SHELF_AUTO_HIDE, shelf_2->visibility_state()); EXPECT_EQ(SHELF_AUTO_HIDE_HIDDEN, shelf_2->auto_hide_state()); // Hide app list, both shelves should be hidden. shell->DismissAppList(); EXPECT_FALSE(shell->GetAppListTargetVisibility()); EXPECT_EQ(SHELF_AUTO_HIDE, shelf_1->visibility_state()); EXPECT_EQ(SHELF_AUTO_HIDE, shelf_2->visibility_state()); EXPECT_EQ(SHELF_AUTO_HIDE_HIDDEN, shelf_1->auto_hide_state()); EXPECT_EQ(SHELF_AUTO_HIDE_HIDDEN, shelf_2->auto_hide_state()); } // Makes sure the shelf will be hidden when we have a fullscreen window, and it // will unhide when we open the app list. TEST_F(ShelfLayoutManagerTest, OpenAppListWithShelfHiddenState) { Shell* shell = Shell::GetInstance(); ShelfLayoutManager* shelf = GetShelfLayoutManager(); // For shelf to be visible, app list is not open in initial state. shelf->LayoutShelf(); // Create a window and make it full screen. aura::Window* window = CreateTestWindow(); window->SetBounds(gfx::Rect(0, 0, 100, 100)); window->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_FULLSCREEN); window->Show(); wm::ActivateWindow(window); // App list and shelf is not shown. EXPECT_FALSE(shell->GetAppListTargetVisibility()); EXPECT_EQ(SHELF_HIDDEN, shelf->visibility_state()); // Show app list. shell->ShowAppList(nullptr); EXPECT_TRUE(shell->GetAppListTargetVisibility()); EXPECT_EQ(SHELF_VISIBLE, shelf->visibility_state()); // Hide app list. shell->DismissAppList(); EXPECT_FALSE(shell->GetAppListTargetVisibility()); EXPECT_EQ(SHELF_HIDDEN, shelf->visibility_state()); } // Tests the correct behavior of the shelf when there is a system modal window // open when we have a single display. TEST_F(ShelfLayoutManagerTest, ShelfWithSystemModalWindowSingleDisplay) { Shell* shell = Shell::GetInstance(); ShelfLayoutManager* shelf = GetShelfLayoutManager(); shelf->LayoutShelf(); shelf->SetAutoHideBehavior(SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS); aura::Window* window = CreateTestWindow(); window->SetBounds(gfx::Rect(0, 0, 100, 100)); window->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_MAXIMIZED); window->Show(); wm::ActivateWindow(window); // Enable system modal dialog, and make sure shelf is still hidden. shell->SimulateModalWindowOpenForTesting(true); EXPECT_TRUE(shell->IsSystemModalWindowOpen()); EXPECT_FALSE(wm::CanActivateWindow(window)); shell->UpdateShelfVisibility(); EXPECT_EQ(SHELF_AUTO_HIDE, shelf->visibility_state()); EXPECT_EQ(SHELF_AUTO_HIDE_HIDDEN, shelf->auto_hide_state()); } // Tests the correct behavior of the shelf when there is a system modal window // open when we have dual display. TEST_F(ShelfLayoutManagerTest, ShelfWithSystemModalWindowDualDisplay) { if (!SupportsMultipleDisplays()) return; // Create two displays. Shell* shell = Shell::GetInstance(); DisplayManager* display_manager = shell->display_manager(); UpdateDisplay("200x200,100x100"); EXPECT_EQ(2U, display_manager->GetNumDisplays()); WindowTreeHostManager* window_tree_host_manager = shell->window_tree_host_manager(); aura::Window::Windows root_windows = window_tree_host_manager->GetAllRootWindows(); EXPECT_EQ(2U, root_windows.size()); // Get the shelves in both displays and set them to be 'AutoHide'. ShelfLayoutManager* shelf_1 = GetRootWindowController(root_windows[0])->GetShelfLayoutManager(); ShelfLayoutManager* shelf_2 = GetRootWindowController(root_windows[1])->GetShelfLayoutManager(); EXPECT_NE(shelf_1, shelf_2); EXPECT_NE(shelf_1->shelf_widget()->GetNativeWindow()->GetRootWindow(), shelf_2->shelf_widget()->GetNativeWindow()->GetRootWindow()); shelf_1->SetAutoHideBehavior(SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS); shelf_1->LayoutShelf(); shelf_2->SetAutoHideBehavior(SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS); shelf_2->LayoutShelf(); // Create a window in each display and show them in maximized state. aura::Window* window_1 = CreateTestWindowInParent(root_windows[0]); window_1->SetBounds(gfx::Rect(0, 0, 100, 100)); window_1->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_MAXIMIZED); window_1->Show(); aura::Window* window_2 = CreateTestWindowInParent(root_windows[1]); window_2->SetBounds(gfx::Rect(201, 0, 100, 100)); window_2->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_MAXIMIZED); window_2->Show(); EXPECT_EQ(shelf_1->shelf_widget()->GetNativeWindow()->GetRootWindow(), window_1->GetRootWindow()); EXPECT_EQ(shelf_2->shelf_widget()->GetNativeWindow()->GetRootWindow(), window_2->GetRootWindow()); EXPECT_TRUE(window_1->IsVisible()); EXPECT_TRUE(window_2->IsVisible()); // Enable system modal dialog, and make sure both shelves are still hidden. shell->SimulateModalWindowOpenForTesting(true); EXPECT_TRUE(shell->IsSystemModalWindowOpen()); EXPECT_FALSE(wm::CanActivateWindow(window_1)); EXPECT_FALSE(wm::CanActivateWindow(window_2)); shell->UpdateShelfVisibility(); EXPECT_EQ(SHELF_AUTO_HIDE, shelf_1->visibility_state()); EXPECT_EQ(SHELF_AUTO_HIDE_HIDDEN, shelf_1->auto_hide_state()); EXPECT_EQ(SHELF_AUTO_HIDE, shelf_2->visibility_state()); EXPECT_EQ(SHELF_AUTO_HIDE_HIDDEN, shelf_2->auto_hide_state()); } // Tests that the shelf is only hidden for a fullscreen window at the front and // toggles visibility when another window is activated. TEST_F(ShelfLayoutManagerTest, FullscreenWindowInFrontHidesShelf) { ShelfLayoutManager* shelf = GetShelfLayoutManager(); // Create a window and make it full screen. aura::Window* window1 = CreateTestWindow(); window1->SetBounds(gfx::Rect(0, 0, 100, 100)); window1->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_FULLSCREEN); window1->Show(); aura::Window* window2 = CreateTestWindow(); window2->SetBounds(gfx::Rect(0, 0, 100, 100)); window2->Show(); wm::GetWindowState(window1)->Activate(); EXPECT_EQ(SHELF_HIDDEN, shelf->visibility_state()); wm::GetWindowState(window2)->Activate(); EXPECT_EQ(SHELF_VISIBLE, shelf->visibility_state()); wm::GetWindowState(window1)->Activate(); EXPECT_EQ(SHELF_HIDDEN, shelf->visibility_state()); } // Test the behavior of the shelf when a window on one display is fullscreen // but the other display has the active window. TEST_F(ShelfLayoutManagerTest, FullscreenWindowOnSecondDisplay) { if (!SupportsMultipleDisplays()) return; UpdateDisplay("800x600,800x600"); DisplayManager* display_manager = Shell::GetInstance()->display_manager(); aura::Window::Windows root_windows = Shell::GetAllRootWindows(); Shell::RootWindowControllerList root_window_controllers = Shell::GetAllRootWindowControllers(); // Create windows on either display. aura::Window* window1 = CreateTestWindow(); window1->SetBoundsInScreen( gfx::Rect(0, 0, 100, 100), display_manager->GetDisplayAt(0)); window1->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_FULLSCREEN); window1->Show(); aura::Window* window2 = CreateTestWindow(); window2->SetBoundsInScreen( gfx::Rect(800, 0, 100, 100), display_manager->GetDisplayAt(1)); window2->Show(); EXPECT_EQ(root_windows[0], window1->GetRootWindow()); EXPECT_EQ(root_windows[1], window2->GetRootWindow()); wm::GetWindowState(window2)->Activate(); EXPECT_EQ(SHELF_HIDDEN, root_window_controllers[0]->GetShelfLayoutManager()->visibility_state()); EXPECT_EQ(SHELF_VISIBLE, root_window_controllers[1]->GetShelfLayoutManager()->visibility_state()); } #if defined(OS_WIN) // RootWindow and Display can't resize on Windows Ash. http://crbug.com/165962 #define MAYBE_SetAlignment DISABLED_SetAlignment #else #define MAYBE_SetAlignment SetAlignment #endif // Tests SHELF_ALIGNMENT_(LEFT, RIGHT, TOP). TEST_F(ShelfLayoutManagerTest, MAYBE_SetAlignment) { ShelfLayoutManager* shelf = GetShelfLayoutManager(); // Force an initial layout. shelf->SetAutoHideBehavior(SHELF_AUTO_HIDE_BEHAVIOR_NEVER); shelf->LayoutShelf(); EXPECT_EQ(SHELF_VISIBLE, shelf->visibility_state()); shelf->SetAlignment(SHELF_ALIGNMENT_LEFT); gfx::Rect shelf_bounds( GetShelfWidget()->GetWindowBoundsInScreen()); const gfx::Screen* screen = gfx::Screen::GetScreen(); gfx::Display display = screen->GetDisplayNearestWindow(Shell::GetPrimaryRootWindow()); ASSERT_NE(-1, display.id()); EXPECT_EQ(shelf->GetIdealBounds().width(), display.GetWorkAreaInsets().left()); EXPECT_GE( shelf_bounds.width(), GetShelfWidget()->GetContentsView()->GetPreferredSize().width()); EXPECT_EQ(SHELF_ALIGNMENT_LEFT, GetSystemTray()->shelf_alignment()); StatusAreaWidget* status_area_widget = GetShelfWidget()->status_area_widget(); gfx::Rect status_bounds(status_area_widget->GetWindowBoundsInScreen()); EXPECT_GE(status_bounds.width(), status_area_widget->GetContentsView()->GetPreferredSize().width()); EXPECT_EQ(shelf->GetIdealBounds().width(), display.GetWorkAreaInsets().left()); EXPECT_EQ(0, display.GetWorkAreaInsets().top()); EXPECT_EQ(0, display.GetWorkAreaInsets().bottom()); EXPECT_EQ(0, display.GetWorkAreaInsets().right()); EXPECT_EQ(display.bounds().x(), shelf_bounds.x()); EXPECT_EQ(display.bounds().y(), shelf_bounds.y()); EXPECT_EQ(display.bounds().height(), shelf_bounds.height()); shelf->SetAutoHideBehavior(SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS); display = screen->GetDisplayNearestWindow(Shell::GetPrimaryRootWindow()); EXPECT_EQ(ShelfLayoutManager::kAutoHideSize, display.GetWorkAreaInsets().left()); EXPECT_EQ(ShelfLayoutManager::kAutoHideSize, display.work_area().x()); shelf->SetAutoHideBehavior(SHELF_AUTO_HIDE_BEHAVIOR_NEVER); shelf->SetAlignment(SHELF_ALIGNMENT_RIGHT); display = screen->GetDisplayNearestWindow(Shell::GetPrimaryRootWindow()); shelf_bounds = GetShelfWidget()->GetWindowBoundsInScreen(); display = screen->GetDisplayNearestWindow(Shell::GetPrimaryRootWindow()); ASSERT_NE(-1, display.id()); EXPECT_EQ(shelf->GetIdealBounds().width(), display.GetWorkAreaInsets().right()); EXPECT_GE(shelf_bounds.width(), GetShelfWidget()->GetContentsView()->GetPreferredSize().width()); EXPECT_EQ(SHELF_ALIGNMENT_RIGHT, GetSystemTray()->shelf_alignment()); status_bounds = gfx::Rect(status_area_widget->GetWindowBoundsInScreen()); EXPECT_GE(status_bounds.width(), status_area_widget->GetContentsView()->GetPreferredSize().width()); EXPECT_EQ(shelf->GetIdealBounds().width(), display.GetWorkAreaInsets().right()); EXPECT_EQ(0, display.GetWorkAreaInsets().top()); EXPECT_EQ(0, display.GetWorkAreaInsets().bottom()); EXPECT_EQ(0, display.GetWorkAreaInsets().left()); EXPECT_EQ(display.work_area().right(), shelf_bounds.x()); EXPECT_EQ(display.bounds().y(), shelf_bounds.y()); EXPECT_EQ(display.bounds().height(), shelf_bounds.height()); shelf->SetAutoHideBehavior(SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS); display = screen->GetDisplayNearestWindow(Shell::GetPrimaryRootWindow()); EXPECT_EQ(ShelfLayoutManager::kAutoHideSize, display.GetWorkAreaInsets().right()); EXPECT_EQ(ShelfLayoutManager::kAutoHideSize, display.bounds().right() - display.work_area().right()); shelf->SetAutoHideBehavior(SHELF_AUTO_HIDE_BEHAVIOR_NEVER); shelf->SetAlignment(SHELF_ALIGNMENT_TOP); display = screen->GetDisplayNearestWindow(Shell::GetPrimaryRootWindow()); shelf_bounds = GetShelfWidget()->GetWindowBoundsInScreen(); display = screen->GetDisplayNearestWindow(Shell::GetPrimaryRootWindow()); ASSERT_NE(-1, display.id()); EXPECT_EQ(shelf->GetIdealBounds().height(), display.GetWorkAreaInsets().top()); EXPECT_GE(shelf_bounds.height(), GetShelfWidget()->GetContentsView()->GetPreferredSize().height()); EXPECT_EQ(SHELF_ALIGNMENT_TOP, GetSystemTray()->shelf_alignment()); status_bounds = gfx::Rect(status_area_widget->GetWindowBoundsInScreen()); EXPECT_GE(status_bounds.height(), status_area_widget->GetContentsView()->GetPreferredSize().height()); EXPECT_EQ(shelf->GetIdealBounds().height(), display.GetWorkAreaInsets().top()); EXPECT_EQ(0, display.GetWorkAreaInsets().right()); EXPECT_EQ(0, display.GetWorkAreaInsets().bottom()); EXPECT_EQ(0, display.GetWorkAreaInsets().left()); EXPECT_EQ(display.work_area().y(), shelf_bounds.bottom()); EXPECT_EQ(display.bounds().x(), shelf_bounds.x()); EXPECT_EQ(display.bounds().width(), shelf_bounds.width()); shelf->SetAutoHideBehavior(SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS); display = screen->GetDisplayNearestWindow(Shell::GetPrimaryRootWindow()); EXPECT_EQ(ShelfLayoutManager::kAutoHideSize, display.GetWorkAreaInsets().top()); EXPECT_EQ(ShelfLayoutManager::kAutoHideSize, display.work_area().y() - display.bounds().y()); } TEST_F(ShelfLayoutManagerTest, GestureEdgeSwipe) { ShelfLayoutManager* shelf = GetShelfLayoutManager(); shelf->SetAutoHideBehavior(SHELF_AUTO_HIDE_BEHAVIOR_NEVER); views::Widget* widget = new views::Widget; views::Widget::InitParams params(views::Widget::InitParams::TYPE_WINDOW); params.bounds = gfx::Rect(0, 0, 200, 200); params.context = CurrentContext(); widget->Init(params); widget->Show(); widget->Maximize(); ui::test::EventGenerator generator(Shell::GetPrimaryRootWindow()); aura::Window* window = widget->GetNativeWindow(); shelf->LayoutShelf(); gfx::Rect shelf_shown = GetShelfWidget()->GetWindowBoundsInScreen(); gfx::Rect bounds_shelf = window->bounds(); // Edge swipe when SHELF_VISIBLE should not change visibility state. EXPECT_EQ(SHELF_VISIBLE, shelf->visibility_state()); generator.GestureEdgeSwipe(); EXPECT_EQ(SHELF_VISIBLE, shelf->visibility_state()); // Edge swipe when AUTO_HIDE_HIDDEN should change to AUTO_HIDE_SHOWN. shelf->SetAutoHideBehavior(SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS); shelf->LayoutShelf(); EXPECT_EQ(SHELF_AUTO_HIDE, shelf->visibility_state()); EXPECT_EQ(SHELF_AUTO_HIDE_HIDDEN, shelf->auto_hide_state()); generator.GestureEdgeSwipe(); EXPECT_EQ(SHELF_AUTO_HIDE, shelf->visibility_state()); EXPECT_EQ(SHELF_AUTO_HIDE_SHOWN, shelf->auto_hide_state()); widget->SetFullscreen(true); wm::GetWindowState(window)->set_hide_shelf_when_fullscreen(false); shelf->UpdateVisibilityState(); // Edge swipe in fullscreen + AUTO_HIDE_HIDDEN should show the shelf and // remain fullscreen. EXPECT_TRUE(widget->IsFullscreen()); EXPECT_EQ(SHELF_AUTO_HIDE, shelf->visibility_state()); EXPECT_EQ(SHELF_AUTO_HIDE_HIDDEN, shelf->auto_hide_state()); generator.GestureEdgeSwipe(); EXPECT_EQ(SHELF_AUTO_HIDE, shelf->visibility_state()); EXPECT_EQ(SHELF_AUTO_HIDE_SHOWN, shelf->auto_hide_state()); EXPECT_TRUE(widget->IsFullscreen()); } // Tests that gesture edge swipe events are forwarded to the right shelf on the // right monitor (crbug.com/449851). TEST_F(ShelfLayoutManagerTest, GestureEdgeSwipeMultiMonitor) { if (!SupportsMultipleDisplays()) return; // Create two displays. Shell* shell = Shell::GetInstance(); DisplayManager* display_manager = shell->display_manager(); UpdateDisplay("200x200,100x100"); ASSERT_EQ(2U, display_manager->GetNumDisplays()); auto root_window_controllers = Shell::GetAllRootWindowControllers(); ASSERT_EQ(2U, root_window_controllers.size()); ShelfLayoutManager* shelf_1 = root_window_controllers[0]->GetShelfLayoutManager(); ShelfLayoutManager* shelf_2 = root_window_controllers[1]->GetShelfLayoutManager(); // Create two maximized windows, one in each display. aura::Window* window_1 = CreateTestWindowInParent(root_window_controllers[0]->GetRootWindow()); window_1->SetBounds(gfx::Rect(0, 0, 100, 100)); window_1->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_MAXIMIZED); window_1->Show(); aura::Window* window_2 = CreateTestWindowInParent(root_window_controllers[1]->GetRootWindow()); window_2->SetBounds(gfx::Rect(201, 0, 100, 100)); window_2->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_MAXIMIZED); window_2->Show(); // Make sure both are set to auto-hide and both are hidden. shelf_1->SetAutoHideBehavior(SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS); shelf_2->SetAutoHideBehavior(SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS); shelf_1->LayoutShelf(); shelf_2->LayoutShelf(); EXPECT_EQ(SHELF_AUTO_HIDE, shelf_1->visibility_state()); EXPECT_EQ(SHELF_AUTO_HIDE, shelf_2->visibility_state()); EXPECT_EQ(SHELF_AUTO_HIDE_HIDDEN, shelf_1->auto_hide_state()); EXPECT_EQ(SHELF_AUTO_HIDE_HIDDEN, shelf_2->auto_hide_state()); ui::test::EventGenerator monitor_1_generator( root_window_controllers[0]->GetRootWindow()); ui::test::EventGenerator monitor_2_generator( root_window_controllers[1]->GetRootWindow()); // An edge swipe in one display should only affect the shelf in that display. monitor_1_generator.GestureEdgeSwipe(); EXPECT_EQ(SHELF_AUTO_HIDE, shelf_1->visibility_state()); EXPECT_EQ(SHELF_AUTO_HIDE, shelf_2->visibility_state()); EXPECT_EQ(SHELF_AUTO_HIDE_SHOWN, shelf_1->auto_hide_state()); EXPECT_EQ(SHELF_AUTO_HIDE_HIDDEN, shelf_2->auto_hide_state()); // Back to normal after an update. shell->UpdateShelfVisibility(); EXPECT_EQ(SHELF_AUTO_HIDE, shelf_1->visibility_state()); EXPECT_EQ(SHELF_AUTO_HIDE, shelf_2->visibility_state()); EXPECT_EQ(SHELF_AUTO_HIDE_HIDDEN, shelf_1->auto_hide_state()); EXPECT_EQ(SHELF_AUTO_HIDE_HIDDEN, shelf_2->auto_hide_state()); monitor_2_generator.GestureEdgeSwipe(); EXPECT_EQ(SHELF_AUTO_HIDE, shelf_1->visibility_state()); EXPECT_EQ(SHELF_AUTO_HIDE, shelf_2->visibility_state()); EXPECT_EQ(SHELF_AUTO_HIDE_HIDDEN, shelf_1->auto_hide_state()); EXPECT_EQ(SHELF_AUTO_HIDE_SHOWN, shelf_2->auto_hide_state()); } #if defined(OS_WIN) // RootWindow and Display can't resize on Windows Ash. http://crbug.com/165962 #define MAYBE_GestureDrag DISABLED_GestureDrag #else #define MAYBE_GestureDrag GestureDrag #endif TEST_F(ShelfLayoutManagerTest, MAYBE_GestureDrag) { // Slop is an implementation detail of gesture recognition, and complicates // these tests. Ignore it. ui::GestureConfiguration::GetInstance() ->set_max_touch_move_in_pixels_for_click(0); ShelfLayoutManager* shelf = GetShelfLayoutManager(); { SCOPED_TRACE("BOTTOM"); RunGestureDragTests(gfx::Vector2d(0, 120)); } { SCOPED_TRACE("LEFT"); shelf->SetAlignment(SHELF_ALIGNMENT_LEFT); RunGestureDragTests(gfx::Vector2d(-120, 0)); } { SCOPED_TRACE("RIGHT"); shelf->SetAlignment(SHELF_ALIGNMENT_RIGHT); RunGestureDragTests(gfx::Vector2d(120, 0)); } } TEST_F(ShelfLayoutManagerTest, WindowVisibilityDisablesAutoHide) { if (!SupportsMultipleDisplays()) return; UpdateDisplay("800x600,800x600"); ShelfLayoutManager* shelf = GetShelfLayoutManager(); shelf->LayoutShelf(); shelf->SetAutoHideBehavior(SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS); // Create a visible window so auto-hide behavior is enforced views::Widget* dummy = CreateTestWidget(); // Window visible => auto hide behaves normally. shelf->UpdateVisibilityState(); EXPECT_EQ(SHELF_AUTO_HIDE_HIDDEN, shelf->auto_hide_state()); // Window minimized => auto hide disabled. dummy->Minimize(); EXPECT_EQ(SHELF_AUTO_HIDE_SHOWN, shelf->auto_hide_state()); // Window closed => auto hide disabled. dummy->CloseNow(); EXPECT_EQ(SHELF_AUTO_HIDE_SHOWN, shelf->auto_hide_state()); // Multiple window test views::Widget* window1 = CreateTestWidget(); views::Widget* window2 = CreateTestWidget(); // both visible => normal autohide EXPECT_EQ(SHELF_AUTO_HIDE_HIDDEN, shelf->auto_hide_state()); // either minimzed => normal autohide window2->Minimize(); EXPECT_EQ(SHELF_AUTO_HIDE_HIDDEN, shelf->auto_hide_state()); window2->Restore(); window1->Minimize(); EXPECT_EQ(SHELF_AUTO_HIDE_HIDDEN, shelf->auto_hide_state()); // both minimized => disable auto hide window2->Minimize(); EXPECT_EQ(SHELF_AUTO_HIDE_SHOWN, shelf->auto_hide_state()); // Test moving windows to/from other display. window2->Restore(); EXPECT_EQ(SHELF_AUTO_HIDE_HIDDEN, shelf->auto_hide_state()); // Move to second display. window2->SetBounds(gfx::Rect(850, 50, 50, 50)); EXPECT_EQ(SHELF_AUTO_HIDE_SHOWN, shelf->auto_hide_state()); // Move back to primary display. window2->SetBounds(gfx::Rect(50, 50, 50, 50)); EXPECT_EQ(SHELF_AUTO_HIDE_HIDDEN, shelf->auto_hide_state()); } // Test that the shelf animates back to its normal position upon a user // completing a gesture drag. TEST_F(ShelfLayoutManagerTest, ShelfAnimatesWhenGestureComplete) { if (!SupportsHostWindowResize()) return; // Test the shelf animates back to its original visible bounds when it is // dragged when there are no visible windows. ShelfLayoutManager* shelf = GetShelfLayoutManager(); shelf->SetAutoHideBehavior(SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS); EXPECT_EQ(SHELF_AUTO_HIDE, shelf->visibility_state()); EXPECT_EQ(SHELF_AUTO_HIDE_SHOWN, shelf->auto_hide_state()); gfx::Rect visible_bounds = GetShelfWidget()->GetWindowBoundsInScreen(); { // Enable animations so that we can make sure that they occur. ui::ScopedAnimationDurationScaleMode regular_animations( ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION); ui::test::EventGenerator generator(Shell::GetPrimaryRootWindow()); gfx::Rect shelf_bounds_in_screen = GetShelfWidget()->GetWindowBoundsInScreen(); gfx::Point start(shelf_bounds_in_screen.CenterPoint()); gfx::Point end(start.x(), shelf_bounds_in_screen.bottom()); generator.GestureScrollSequence(start, end, base::TimeDelta::FromMilliseconds(10), 5); EXPECT_EQ(SHELF_AUTO_HIDE, shelf->visibility_state()); EXPECT_EQ(SHELF_AUTO_HIDE_SHOWN, shelf->auto_hide_state()); ShelfAnimationWaiter waiter(visible_bounds); // Wait till the animation completes and check that it occurred. waiter.WaitTillDoneAnimating(); EXPECT_TRUE(waiter.WasValidAnimation()); } // Create a visible window so auto-hide behavior is enforced. CreateTestWidget(); // Get the bounds of the shelf when it is hidden. EXPECT_EQ(SHELF_AUTO_HIDE, shelf->visibility_state()); EXPECT_EQ(SHELF_AUTO_HIDE_HIDDEN, shelf->auto_hide_state()); gfx::Rect auto_hidden_bounds = GetShelfWidget()->GetWindowBoundsInScreen(); { // Enable the animations so that we can make sure they do occur. ui::ScopedAnimationDurationScaleMode regular_animations( ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION); gfx::Point start = GetShelfWidget()->GetWindowBoundsInScreen().CenterPoint(); gfx::Point end(start.x(), start.y() - 100); ui::test::EventGenerator generator(Shell::GetPrimaryRootWindow()); // Test that the shelf animates to the visible bounds after a swipe up on // the auto hidden shelf. generator.GestureScrollSequence(start, end, base::TimeDelta::FromMilliseconds(10), 1); EXPECT_EQ(SHELF_VISIBLE, shelf->visibility_state()); ShelfAnimationWaiter waiter1(visible_bounds); waiter1.WaitTillDoneAnimating(); EXPECT_TRUE(waiter1.WasValidAnimation()); // Test that the shelf animates to the auto hidden bounds after a swipe up // on the visible shelf. EXPECT_EQ(SHELF_VISIBLE, shelf->visibility_state()); generator.GestureScrollSequence(start, end, base::TimeDelta::FromMilliseconds(10), 1); EXPECT_EQ(SHELF_AUTO_HIDE, shelf->visibility_state()); EXPECT_EQ(SHELF_AUTO_HIDE_HIDDEN, shelf->auto_hide_state()); ShelfAnimationWaiter waiter2(auto_hidden_bounds); waiter2.WaitTillDoneAnimating(); EXPECT_TRUE(waiter2.WasValidAnimation()); } } TEST_F(ShelfLayoutManagerTest, ShelfFlickerOnTrayActivation) { ShelfLayoutManager* shelf = GetShelfLayoutManager(); // Create a visible window so auto-hide behavior is enforced. CreateTestWidget(); // Turn on auto-hide for the shelf. shelf->SetAutoHideBehavior(SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS); EXPECT_EQ(SHELF_AUTO_HIDE, shelf->visibility_state()); EXPECT_EQ(SHELF_AUTO_HIDE_HIDDEN, shelf->auto_hide_state()); // Show the status menu. That should make the shelf visible again. Shell::GetInstance()->accelerator_controller()->PerformActionIfEnabled( SHOW_SYSTEM_TRAY_BUBBLE); EXPECT_EQ(SHELF_AUTO_HIDE, shelf->visibility_state()); EXPECT_EQ(SHELF_AUTO_HIDE_SHOWN, shelf->auto_hide_state()); EXPECT_TRUE(GetSystemTray()->HasSystemBubble()); } TEST_F(ShelfLayoutManagerTest, WorkAreaChangeWorkspace) { // Make sure the shelf is always visible. ShelfLayoutManager* shelf = GetShelfLayoutManager(); shelf->SetAutoHideBehavior(SHELF_AUTO_HIDE_BEHAVIOR_NEVER); shelf->LayoutShelf(); views::Widget::InitParams params(views::Widget::InitParams::TYPE_WINDOW); params.bounds = gfx::Rect(0, 0, 200, 200); params.context = CurrentContext(); views::Widget* widget_one = CreateTestWidgetWithParams(params); widget_one->Maximize(); views::Widget* widget_two = CreateTestWidgetWithParams(params); widget_two->Maximize(); widget_two->Activate(); // Both windows are maximized. They should be of the same size. EXPECT_EQ(widget_one->GetNativeWindow()->bounds().ToString(), widget_two->GetNativeWindow()->bounds().ToString()); int area_when_shelf_shown = widget_one->GetNativeWindow()->bounds().size().GetArea(); // Now hide the shelf. shelf->SetAutoHideBehavior(SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS); // Both windows should be resized according to the shelf status. EXPECT_EQ(widget_one->GetNativeWindow()->bounds().ToString(), widget_two->GetNativeWindow()->bounds().ToString()); // Resized to small. EXPECT_LT(area_when_shelf_shown, widget_one->GetNativeWindow()->bounds().size().GetArea()); // Now show the shelf. shelf->SetAutoHideBehavior(SHELF_AUTO_HIDE_BEHAVIOR_NEVER); // Again both windows should be of the same size. EXPECT_EQ(widget_one->GetNativeWindow()->bounds().ToString(), widget_two->GetNativeWindow()->bounds().ToString()); EXPECT_EQ(area_when_shelf_shown, widget_one->GetNativeWindow()->bounds().size().GetArea()); } // Confirm that the shelf is dimmed only when content is maximized and // shelf is not autohidden. TEST_F(ShelfLayoutManagerTest, Dimming) { GetShelfLayoutManager()->SetAutoHideBehavior(SHELF_AUTO_HIDE_BEHAVIOR_NEVER); scoped_ptr w1(CreateTestWindow()); w1->Show(); wm::ActivateWindow(w1.get()); // Normal window doesn't dim shelf. w1->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_NORMAL); ShelfWidget* shelf = GetShelfWidget(); EXPECT_FALSE(shelf->GetDimsShelf()); // Maximized window does. w1->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_MAXIMIZED); EXPECT_TRUE(shelf->GetDimsShelf()); // Change back to normal stops dimming. w1->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_NORMAL); EXPECT_FALSE(shelf->GetDimsShelf()); // Changing back to maximized dims again. w1->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_MAXIMIZED); EXPECT_TRUE(shelf->GetDimsShelf()); // Changing shelf to autohide stops dimming. GetShelfLayoutManager()->SetAutoHideBehavior(SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS); EXPECT_FALSE(shelf->GetDimsShelf()); } // Make sure that the shelf will not hide if the mouse is between a bubble and // the shelf. TEST_F(ShelfLayoutManagerTest, BubbleEnlargesShelfMouseHitArea) { ShelfLayoutManager* shelf = GetShelfLayoutManager(); StatusAreaWidget* status_area_widget = Shell::GetPrimaryRootWindowController()->shelf()->status_area_widget(); SystemTray* tray = GetSystemTray(); // Create a visible window so auto-hide behavior is enforced. CreateTestWidget(); shelf->LayoutShelf(); ui::test::EventGenerator generator(Shell::GetPrimaryRootWindow()); // Make two iterations - first without a message bubble which should make // the shelf disappear and then with a message bubble which should keep it // visible. for (int i = 0; i < 2; i++) { // Make sure the shelf is visible and position the mouse over it. Then // allow auto hide. shelf->SetAutoHideBehavior(SHELF_AUTO_HIDE_BEHAVIOR_NEVER); EXPECT_FALSE(status_area_widget->IsMessageBubbleShown()); gfx::Point center = status_area_widget->GetWindowBoundsInScreen().CenterPoint(); generator.MoveMouseTo(center.x(), center.y()); shelf->SetAutoHideBehavior(SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS); EXPECT_TRUE(shelf->IsVisible()); if (!i) { // In our first iteration we make sure there is no bubble. tray->CloseSystemBubble(); EXPECT_FALSE(status_area_widget->IsMessageBubbleShown()); } else { // In our second iteration we show a bubble. TestItem *item = new TestItem; tray->AddTrayItem(item); tray->ShowNotificationView(item); EXPECT_TRUE(status_area_widget->IsMessageBubbleShown()); } // Move the pointer over the edge of the shelf. generator.MoveMouseTo( center.x(), status_area_widget->GetWindowBoundsInScreen().y() - 8); shelf->UpdateVisibilityState(); if (i) { EXPECT_TRUE(shelf->IsVisible()); EXPECT_TRUE(status_area_widget->IsMessageBubbleShown()); } else { EXPECT_FALSE(shelf->IsVisible()); EXPECT_FALSE(status_area_widget->IsMessageBubbleShown()); } } } TEST_F(ShelfLayoutManagerTest, ShelfBackgroundColor) { EXPECT_EQ(SHELF_BACKGROUND_DEFAULT, GetShelfWidget()->GetBackgroundType()); scoped_ptr w1(CreateTestWindow()); w1->Show(); wm::ActivateWindow(w1.get()); EXPECT_EQ(SHELF_BACKGROUND_DEFAULT, GetShelfWidget()->GetBackgroundType()); w1->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_MAXIMIZED); EXPECT_EQ(SHELF_BACKGROUND_MAXIMIZED, GetShelfWidget()->GetBackgroundType()); scoped_ptr w2(CreateTestWindow()); w2->Show(); wm::ActivateWindow(w2.get()); // Overlaps with shelf. w2->SetBounds(GetShelfLayoutManager()->GetIdealBounds()); // Still background is 'maximized'. EXPECT_EQ(SHELF_BACKGROUND_MAXIMIZED, GetShelfWidget()->GetBackgroundType()); w1->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_MINIMIZED); EXPECT_EQ(SHELF_BACKGROUND_OVERLAP, GetShelfWidget()->GetBackgroundType()); w2->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_MINIMIZED); EXPECT_EQ(SHELF_BACKGROUND_DEFAULT, GetShelfWidget()->GetBackgroundType()); w1->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_MAXIMIZED); EXPECT_EQ(SHELF_BACKGROUND_MAXIMIZED, GetShelfWidget()->GetBackgroundType()); w1.reset(); EXPECT_EQ(SHELF_BACKGROUND_DEFAULT, GetShelfWidget()->GetBackgroundType()); } // Verify that the shelf doesn't have the opaque background if it's auto-hide // status. TEST_F(ShelfLayoutManagerTest, ShelfBackgroundColorAutoHide) { EXPECT_EQ(SHELF_BACKGROUND_DEFAULT, GetShelfWidget ()->GetBackgroundType()); GetShelfLayoutManager()->SetAutoHideBehavior(SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS); scoped_ptr w1(CreateTestWindow()); w1->Show(); wm::ActivateWindow(w1.get()); EXPECT_EQ(SHELF_BACKGROUND_OVERLAP, GetShelfWidget()->GetBackgroundType()); w1->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_MAXIMIZED); EXPECT_EQ(SHELF_BACKGROUND_OVERLAP, GetShelfWidget()->GetBackgroundType()); } #if defined(OS_CHROMEOS) #define MAYBE_StatusAreaHitBoxCoversEdge StatusAreaHitBoxCoversEdge #else #define MAYBE_StatusAreaHitBoxCoversEdge DISABLED_StatusAreaHitBoxCoversEdge #endif // Verify the hit bounds of the status area extend to the edge of the shelf. TEST_F(ShelfLayoutManagerTest, MAYBE_StatusAreaHitBoxCoversEdge) { UpdateDisplay("400x400"); ShelfLayoutManager* shelf = GetShelfLayoutManager(); StatusAreaWidget* status_area_widget = Shell::GetPrimaryRootWindowController()->shelf()->status_area_widget(); ui::test::EventGenerator generator(Shell::GetPrimaryRootWindow()); generator.MoveMouseTo(399,399); // Test bottom right pixel for bottom alignment. EXPECT_FALSE(status_area_widget->IsMessageBubbleShown()); generator.ClickLeftButton(); EXPECT_TRUE(status_area_widget->IsMessageBubbleShown()); generator.ClickLeftButton(); EXPECT_FALSE(status_area_widget->IsMessageBubbleShown()); // Test bottom right pixel for right alignment. shelf->SetAlignment(SHELF_ALIGNMENT_RIGHT); EXPECT_FALSE(status_area_widget->IsMessageBubbleShown()); generator.ClickLeftButton(); EXPECT_TRUE(status_area_widget->IsMessageBubbleShown()); generator.ClickLeftButton(); EXPECT_FALSE(status_area_widget->IsMessageBubbleShown()); // Test bottom left pixel for left alignment. generator.MoveMouseTo(0, 399); shelf->SetAlignment(SHELF_ALIGNMENT_LEFT); EXPECT_FALSE(status_area_widget->IsMessageBubbleShown()); generator.ClickLeftButton(); EXPECT_TRUE(status_area_widget->IsMessageBubbleShown()); generator.ClickLeftButton(); EXPECT_FALSE(status_area_widget->IsMessageBubbleShown()); } // Tests that when the auto-hide behaviour is changed during an animation the // target bounds are updated to reflect the new state. TEST_F(ShelfLayoutManagerTest, ShelfAutoHideToggleDuringAnimationUpdatesBounds) { ShelfLayoutManager* shelf_manager = GetShelfLayoutManager(); aura::Window* status_window = GetShelfWidget()->status_area_widget()-> GetNativeView(); gfx::Rect initial_bounds = status_window->bounds(); ui::ScopedAnimationDurationScaleMode regular_animations( ui::ScopedAnimationDurationScaleMode::SLOW_DURATION); shelf_manager->SetAutoHideBehavior(SHELF_AUTO_HIDE_ALWAYS_HIDDEN); gfx::Rect hide_target_bounds = status_window->GetTargetBounds(); EXPECT_GT(hide_target_bounds.y(), initial_bounds.y()); shelf_manager->SetAutoHideBehavior(SHELF_AUTO_HIDE_BEHAVIOR_NEVER); gfx::Rect reshow_target_bounds = status_window->GetTargetBounds(); EXPECT_EQ(initial_bounds, reshow_target_bounds); } // Tests that during shutdown, that window activation changes are properly // handled, and do not crash (crbug.com/458768) TEST_F(ShelfLayoutManagerTest, ShutdownHandlesWindowActivation) { ShelfLayoutManager* shelf_manager = GetShelfLayoutManager(); ShelfWidget* shelf = GetShelfWidget(); shelf_manager->SetAutoHideBehavior(SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS); aura::Window* window1 = CreateTestWindowInShellWithId(0); window1->SetBounds(gfx::Rect(0, 0, 100, 100)); window1->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_MAXIMIZED); window1->Show(); scoped_ptr window2(CreateTestWindowInShellWithId(0)); window2->SetBounds(gfx::Rect(0, 0, 100, 100)); window2->Show(); wm::ActivateWindow(window1); shelf->ShutdownStatusAreaWidget(); shelf_manager->PrepareForShutdown(); // Deleting a focused maximized window will switch focus to |window2|. This // would normally cause the ShelfLayoutManager to update its state. However // during shutdown we want to handle this without crashing. delete window1; } TEST_F(ShelfLayoutManagerTest, ShelfLayoutInUnifiedDesktop) { if (!SupportsMultipleDisplays()) return; Shell::GetInstance()->display_manager()->SetUnifiedDesktopEnabled(true); UpdateDisplay("500x500, 500x500"); StatusAreaWidget* status_area_widget = Shell::GetPrimaryRootWindowController()->shelf()->status_area_widget(); EXPECT_TRUE(status_area_widget->IsVisible()); // Shelf should be in the first display's area. // TODO: make this test more robust against changes in font, font size. EXPECT_EQ("353,453 147x47", status_area_widget->GetWindowBoundsInScreen().ToString()); } } // namespace ash