// Copyright 2013 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "ash/shelf/shelf_tooltip_manager.h" #include "ash/root_window_controller.h" #include "ash/shelf/shelf_layout_manager.h" #include "ash/shelf/shelf_widget.h" #include "ash/shell.h" #include "ash/shell_window_ids.h" #include "ash/test/ash_test_base.h" #include "ash/test/launcher_test_api.h" #include "ash/wm/window_util.h" #include "base/strings/string16.h" #include "base/time/time.h" #include "ui/aura/root_window.h" #include "ui/events/event.h" #include "ui/events/event_constants.h" #include "ui/events/event_handler.h" #include "ui/events/keycodes/keyboard_codes.h" #include "ui/events/test/events_test_utils.h" #include "ui/views/widget/widget.h" namespace { void SetEventTarget(ui::EventTarget* target, ui::Event* event) { ui::Event::DispatcherApi dispatch_helper(event); dispatch_helper.set_target(target); } } namespace ash { namespace test { class ShelfTooltipManagerTest : public AshTestBase { public: ShelfTooltipManagerTest() {} virtual ~ShelfTooltipManagerTest() {} virtual void SetUp() OVERRIDE { AshTestBase::SetUp(); internal::RootWindowController* controller = Shell::GetPrimaryRootWindowController(); tooltip_manager_.reset(new internal::ShelfTooltipManager( controller->GetShelfLayoutManager(), LauncherTestAPI(controller->shelf()->launcher()).shelf_view())); } virtual void TearDown() OVERRIDE { tooltip_manager_.reset(); AshTestBase::TearDown(); } void ShowDelayed() { CreateWidget(); tooltip_manager_->ShowDelayed(dummy_anchor_.get(), base::string16()); } void ShowImmediately() { CreateWidget(); tooltip_manager_->ShowImmediately(dummy_anchor_.get(), base::string16()); } bool TooltipIsVisible() { return tooltip_manager_->IsVisible(); } bool IsTimerRunning() { return tooltip_manager_->timer_.get() != NULL; } ui::EventHandler* GetEventHandler() { return tooltip_manager_.get(); } views::Widget* GetTooltipWidget() { return tooltip_manager_->widget_; } protected: scoped_ptr<views::Widget> widget_; scoped_ptr<views::View> dummy_anchor_; scoped_ptr<internal::ShelfTooltipManager> tooltip_manager_; private: void CreateWidget() { dummy_anchor_.reset(new views::View); widget_.reset(new views::Widget); views::Widget::InitParams params( views::Widget::InitParams::TYPE_WINDOW_FRAMELESS); params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW; params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; params.parent = Shell::GetContainer( Shell::GetPrimaryRootWindow(), ash::internal::kShellWindowId_ShelfContainer); widget_->Init(params); widget_->SetContentsView(dummy_anchor_.get()); } DISALLOW_COPY_AND_ASSIGN(ShelfTooltipManagerTest); }; TEST_F(ShelfTooltipManagerTest, ShowingBasics) { // ShowDelayed() should just start the timer instead of showing immediately. ShowDelayed(); EXPECT_FALSE(TooltipIsVisible()); EXPECT_TRUE(IsTimerRunning()); ShowImmediately(); EXPECT_TRUE(TooltipIsVisible()); EXPECT_FALSE(IsTimerRunning()); } TEST_F(ShelfTooltipManagerTest, HideWhenShelfIsHidden) { ShowImmediately(); ASSERT_TRUE(TooltipIsVisible()); // Create a full-screen window to hide the shelf. scoped_ptr<views::Widget> widget(new views::Widget); views::Widget::InitParams params(views::Widget::InitParams::TYPE_WINDOW); params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; params.context = CurrentContext(); widget->Init(params); widget->SetFullscreen(true); widget->Show(); // Once the shelf is hidden, the tooltip should be invisible. ASSERT_EQ( SHELF_HIDDEN, Shell::GetPrimaryRootWindowController()-> GetShelfLayoutManager()->visibility_state()); EXPECT_FALSE(TooltipIsVisible()); // Do not show the view if the shelf is hidden. ShowImmediately(); EXPECT_FALSE(TooltipIsVisible()); // ShowDelayed() doesn't even start the timer for the hidden shelf. ShowDelayed(); EXPECT_FALSE(IsTimerRunning()); } TEST_F(ShelfTooltipManagerTest, HideWhenShelfIsAutoHide) { // Create a visible window so auto-hide behavior is enforced. views::Widget* dummy = new views::Widget; views::Widget::InitParams params(views::Widget::InitParams::TYPE_WINDOW); params.bounds = gfx::Rect(0, 0, 200, 200); params.context = CurrentContext(); dummy->Init(params); dummy->Show(); ShowImmediately(); ASSERT_TRUE(TooltipIsVisible()); internal::ShelfLayoutManager* shelf = Shell::GetPrimaryRootWindowController()->GetShelfLayoutManager(); shelf->SetAutoHideBehavior(SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS); shelf->UpdateAutoHideState(); ASSERT_EQ(SHELF_AUTO_HIDE_HIDDEN, shelf->auto_hide_state()); // Tooltip visibility change for auto hide may take time. EXPECT_TRUE(TooltipIsVisible()); RunAllPendingInMessageLoop(); EXPECT_FALSE(TooltipIsVisible()); // Do not show the view if the shelf is hidden. ShowImmediately(); EXPECT_FALSE(TooltipIsVisible()); // ShowDelayed doesn't even run the timer for the hidden shelf. ShowDelayed(); EXPECT_FALSE(IsTimerRunning()); } TEST_F(ShelfTooltipManagerTest, ShouldHideForEvents) { ShowImmediately(); ASSERT_TRUE(TooltipIsVisible()); aura::Window* root_window = Shell::GetInstance()->GetPrimaryRootWindow(); ui::EventHandler* event_handler = GetEventHandler(); // Should not hide for key events. ui::KeyEvent key_event(ui::ET_KEY_PRESSED, ui::VKEY_A, ui::EF_NONE, false); SetEventTarget(root_window, &key_event); event_handler->OnKeyEvent(&key_event); EXPECT_FALSE(key_event.handled()); EXPECT_TRUE(TooltipIsVisible()); // Should hide for touch events. ui::TouchEvent touch_event( ui::ET_TOUCH_PRESSED, gfx::Point(), 0, base::TimeDelta()); SetEventTarget(root_window, &touch_event); event_handler->OnTouchEvent(&touch_event); EXPECT_FALSE(touch_event.handled()); EXPECT_FALSE(TooltipIsVisible()); // Shouldn't hide if the touch happens on the tooltip. ShowImmediately(); views::Widget* tooltip_widget = GetTooltipWidget(); SetEventTarget(tooltip_widget->GetNativeWindow(), &touch_event); event_handler->OnTouchEvent(&touch_event); EXPECT_FALSE(touch_event.handled()); EXPECT_TRUE(TooltipIsVisible()); // Should hide for gesture events. ui::GestureEvent gesture_event( ui::ET_GESTURE_BEGIN, 0, 0, ui::EF_NONE, base::TimeDelta::FromMilliseconds(base::Time::Now().ToDoubleT() * 1000), ui::GestureEventDetails(ui::ET_GESTURE_BEGIN, 0.0f, 0.0f), 0); SetEventTarget(tooltip_widget->GetNativeWindow(), &gesture_event); event_handler->OnGestureEvent(&gesture_event); EXPECT_FALSE(gesture_event.handled()); RunAllPendingInMessageLoop(); EXPECT_FALSE(TooltipIsVisible()); } TEST_F(ShelfTooltipManagerTest, HideForMouseMoveEvent) { ShowImmediately(); ASSERT_TRUE(TooltipIsVisible()); aura::Window* root_window = Shell::GetInstance()->GetPrimaryRootWindow(); ui::EventHandler* event_handler = GetEventHandler(); gfx::Rect tooltip_rect = GetTooltipWidget()->GetNativeWindow()->bounds(); ASSERT_FALSE(tooltip_rect.IsEmpty()); // Shouldn't hide if the mouse is in the tooltip. ui::MouseEvent mouse_event(ui::ET_MOUSE_MOVED, tooltip_rect.CenterPoint(), tooltip_rect.CenterPoint(), ui::EF_NONE); ui::LocatedEventTestApi test_api(&mouse_event); SetEventTarget(root_window, &mouse_event); event_handler->OnMouseEvent(&mouse_event); EXPECT_FALSE(mouse_event.handled()); EXPECT_TRUE(TooltipIsVisible()); // Should hide if the mouse is out of the tooltip. test_api.set_location(tooltip_rect.origin() + gfx::Vector2d(-1, -1)); event_handler->OnMouseEvent(&mouse_event); EXPECT_FALSE(mouse_event.handled()); RunAllPendingInMessageLoop(); EXPECT_FALSE(TooltipIsVisible()); } // Checks that tooltip is hidden when mouse is pressed in anywhere. TEST_F(ShelfTooltipManagerTest, HideForMouseClickEvent) { ShowImmediately(); ASSERT_TRUE(TooltipIsVisible()); aura::Window* root_window = Shell::GetInstance()->GetPrimaryRootWindow(); ui::EventHandler* event_handler = GetEventHandler(); gfx::Rect tooltip_rect = GetTooltipWidget()->GetNativeWindow()->bounds(); ASSERT_FALSE(tooltip_rect.IsEmpty()); // Should hide if the mouse is pressed in the tooltip. ui::MouseEvent mouse_event(ui::ET_MOUSE_PRESSED, tooltip_rect.CenterPoint(), tooltip_rect.CenterPoint(), ui::EF_NONE); SetEventTarget(root_window, &mouse_event); event_handler->OnMouseEvent(&mouse_event); EXPECT_FALSE(mouse_event.handled()); RunAllPendingInMessageLoop(); EXPECT_FALSE(TooltipIsVisible()); // Should hide if the mouse is pressed outside of the tooltip. ShowImmediately(); ASSERT_TRUE(TooltipIsVisible()); ui::LocatedEventTestApi test_api(&mouse_event); test_api.set_location(tooltip_rect.origin() + gfx::Vector2d(-1, -1)); SetEventTarget(root_window, &mouse_event); event_handler->OnMouseEvent(&mouse_event); EXPECT_FALSE(mouse_event.handled()); RunAllPendingInMessageLoop(); EXPECT_FALSE(TooltipIsVisible()); } } // namespace test } // namespace ash