1 // Copyright 2013 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "ash/shelf/shelf_tooltip_manager.h" 6 7 #include "ash/root_window_controller.h" 8 #include "ash/shelf/shelf_layout_manager.h" 9 #include "ash/shelf/shelf_widget.h" 10 #include "ash/shell.h" 11 #include "ash/shell_window_ids.h" 12 #include "ash/test/ash_test_base.h" 13 #include "ash/test/shelf_test_api.h" 14 #include "ash/wm/window_util.h" 15 #include "base/strings/string16.h" 16 #include "base/time/time.h" 17 #include "ui/aura/window_event_dispatcher.h" 18 #include "ui/events/event.h" 19 #include "ui/events/event_constants.h" 20 #include "ui/events/event_handler.h" 21 #include "ui/events/keycodes/keyboard_codes.h" 22 #include "ui/events/test/events_test_utils.h" 23 #include "ui/views/widget/widget.h" 24 25 namespace { 26 27 void SetEventTarget(ui::EventTarget* target, 28 ui::Event* event) { 29 ui::Event::DispatcherApi dispatch_helper(event); 30 dispatch_helper.set_target(target); 31 } 32 33 } 34 35 namespace ash { 36 namespace test { 37 38 class ShelfTooltipManagerTest : public AshTestBase { 39 public: 40 ShelfTooltipManagerTest() {} 41 virtual ~ShelfTooltipManagerTest() {} 42 43 virtual void SetUp() OVERRIDE { 44 AshTestBase::SetUp(); 45 RootWindowController* controller = Shell::GetPrimaryRootWindowController(); 46 tooltip_manager_.reset(new ShelfTooltipManager( 47 controller->GetShelfLayoutManager(), 48 ShelfTestAPI(controller->shelf()->shelf()).shelf_view())); 49 } 50 51 virtual void TearDown() OVERRIDE { 52 tooltip_manager_.reset(); 53 AshTestBase::TearDown(); 54 } 55 56 void ShowDelayed() { 57 CreateWidget(); 58 tooltip_manager_->ShowDelayed(dummy_anchor_.get(), base::string16()); 59 } 60 61 void ShowImmediately() { 62 CreateWidget(); 63 tooltip_manager_->ShowImmediately(dummy_anchor_.get(), base::string16()); 64 } 65 66 bool TooltipIsVisible() { 67 return tooltip_manager_->IsVisible(); 68 } 69 70 bool IsTimerRunning() { 71 return tooltip_manager_->timer_.get() != NULL; 72 } 73 74 ui::EventHandler* GetEventHandler() { 75 return tooltip_manager_.get(); 76 } 77 78 views::Widget* GetTooltipWidget() { 79 return tooltip_manager_->widget_; 80 } 81 82 protected: 83 scoped_ptr<views::Widget> widget_; 84 scoped_ptr<views::View> dummy_anchor_; 85 scoped_ptr<ShelfTooltipManager> tooltip_manager_; 86 87 private: 88 void CreateWidget() { 89 dummy_anchor_.reset(new views::View); 90 91 widget_.reset(new views::Widget); 92 views::Widget::InitParams params( 93 views::Widget::InitParams::TYPE_WINDOW_FRAMELESS); 94 params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW; 95 params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; 96 params.parent = Shell::GetContainer(Shell::GetPrimaryRootWindow(), 97 ash::kShellWindowId_ShelfContainer); 98 99 widget_->Init(params); 100 widget_->SetContentsView(dummy_anchor_.get()); 101 } 102 103 DISALLOW_COPY_AND_ASSIGN(ShelfTooltipManagerTest); 104 }; 105 106 TEST_F(ShelfTooltipManagerTest, ShowingBasics) { 107 // ShowDelayed() should just start the timer instead of showing immediately. 108 ShowDelayed(); 109 EXPECT_FALSE(TooltipIsVisible()); 110 EXPECT_TRUE(IsTimerRunning()); 111 112 ShowImmediately(); 113 EXPECT_TRUE(TooltipIsVisible()); 114 EXPECT_FALSE(IsTimerRunning()); 115 } 116 117 TEST_F(ShelfTooltipManagerTest, HideWhenShelfIsHidden) { 118 ShowImmediately(); 119 ASSERT_TRUE(TooltipIsVisible()); 120 121 // Create a full-screen window to hide the shelf. 122 scoped_ptr<views::Widget> widget(new views::Widget); 123 views::Widget::InitParams params(views::Widget::InitParams::TYPE_WINDOW); 124 params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; 125 params.context = CurrentContext(); 126 widget->Init(params); 127 widget->SetFullscreen(true); 128 widget->Show(); 129 130 // Once the shelf is hidden, the tooltip should be invisible. 131 ASSERT_EQ( 132 SHELF_HIDDEN, 133 Shell::GetPrimaryRootWindowController()-> 134 GetShelfLayoutManager()->visibility_state()); 135 EXPECT_FALSE(TooltipIsVisible()); 136 137 // Do not show the view if the shelf is hidden. 138 ShowImmediately(); 139 EXPECT_FALSE(TooltipIsVisible()); 140 141 // ShowDelayed() doesn't even start the timer for the hidden shelf. 142 ShowDelayed(); 143 EXPECT_FALSE(IsTimerRunning()); 144 } 145 146 TEST_F(ShelfTooltipManagerTest, HideWhenShelfIsAutoHide) { 147 // Create a visible window so auto-hide behavior is enforced. 148 views::Widget* dummy = new views::Widget; 149 views::Widget::InitParams params(views::Widget::InitParams::TYPE_WINDOW); 150 params.bounds = gfx::Rect(0, 0, 200, 200); 151 params.context = CurrentContext(); 152 dummy->Init(params); 153 dummy->Show(); 154 155 ShowImmediately(); 156 ASSERT_TRUE(TooltipIsVisible()); 157 158 ShelfLayoutManager* shelf = 159 Shell::GetPrimaryRootWindowController()->GetShelfLayoutManager(); 160 shelf->SetAutoHideBehavior(SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS); 161 shelf->UpdateAutoHideState(); 162 ASSERT_EQ(SHELF_AUTO_HIDE_HIDDEN, shelf->auto_hide_state()); 163 164 // Tooltip visibility change for auto hide may take time. 165 EXPECT_TRUE(TooltipIsVisible()); 166 RunAllPendingInMessageLoop(); 167 EXPECT_FALSE(TooltipIsVisible()); 168 169 // Do not show the view if the shelf is hidden. 170 ShowImmediately(); 171 EXPECT_FALSE(TooltipIsVisible()); 172 173 // ShowDelayed doesn't even run the timer for the hidden shelf. 174 ShowDelayed(); 175 EXPECT_FALSE(IsTimerRunning()); 176 } 177 178 TEST_F(ShelfTooltipManagerTest, ShouldHideForEvents) { 179 ShowImmediately(); 180 ASSERT_TRUE(TooltipIsVisible()); 181 182 aura::Window* root_window = Shell::GetInstance()->GetPrimaryRootWindow(); 183 ui::EventHandler* event_handler = GetEventHandler(); 184 185 // Should not hide for key events. 186 ui::KeyEvent key_event(ui::ET_KEY_PRESSED, ui::VKEY_A, ui::EF_NONE, false); 187 SetEventTarget(root_window, &key_event); 188 event_handler->OnKeyEvent(&key_event); 189 EXPECT_FALSE(key_event.handled()); 190 EXPECT_TRUE(TooltipIsVisible()); 191 192 // Should hide for touch events. 193 ui::TouchEvent touch_event( 194 ui::ET_TOUCH_PRESSED, gfx::Point(), 0, base::TimeDelta()); 195 SetEventTarget(root_window, &touch_event); 196 event_handler->OnTouchEvent(&touch_event); 197 EXPECT_FALSE(touch_event.handled()); 198 EXPECT_FALSE(TooltipIsVisible()); 199 200 // Shouldn't hide if the touch happens on the tooltip. 201 ShowImmediately(); 202 views::Widget* tooltip_widget = GetTooltipWidget(); 203 SetEventTarget(tooltip_widget->GetNativeWindow(), &touch_event); 204 event_handler->OnTouchEvent(&touch_event); 205 EXPECT_FALSE(touch_event.handled()); 206 EXPECT_TRUE(TooltipIsVisible()); 207 208 // Should hide for gesture events. 209 ui::GestureEvent gesture_event( 210 ui::ET_GESTURE_BEGIN, 0, 0, ui::EF_NONE, 211 base::TimeDelta::FromMilliseconds(base::Time::Now().ToDoubleT() * 1000), 212 ui::GestureEventDetails(ui::ET_GESTURE_BEGIN, 0.0f, 0.0f), 0); 213 SetEventTarget(tooltip_widget->GetNativeWindow(), &gesture_event); 214 event_handler->OnGestureEvent(&gesture_event); 215 EXPECT_FALSE(gesture_event.handled()); 216 RunAllPendingInMessageLoop(); 217 EXPECT_FALSE(TooltipIsVisible()); 218 } 219 220 TEST_F(ShelfTooltipManagerTest, HideForMouseMoveEvent) { 221 ShowImmediately(); 222 ASSERT_TRUE(TooltipIsVisible()); 223 224 aura::Window* root_window = Shell::GetInstance()->GetPrimaryRootWindow(); 225 ui::EventHandler* event_handler = GetEventHandler(); 226 227 gfx::Rect tooltip_rect = GetTooltipWidget()->GetNativeWindow()->bounds(); 228 ASSERT_FALSE(tooltip_rect.IsEmpty()); 229 230 // Shouldn't hide if the mouse is in the tooltip. 231 ui::MouseEvent mouse_event(ui::ET_MOUSE_MOVED, tooltip_rect.CenterPoint(), 232 tooltip_rect.CenterPoint(), ui::EF_NONE, 233 ui::EF_NONE); 234 ui::LocatedEventTestApi test_api(&mouse_event); 235 236 SetEventTarget(root_window, &mouse_event); 237 event_handler->OnMouseEvent(&mouse_event); 238 EXPECT_FALSE(mouse_event.handled()); 239 EXPECT_TRUE(TooltipIsVisible()); 240 241 // Should hide if the mouse is out of the tooltip. 242 test_api.set_location(tooltip_rect.origin() + gfx::Vector2d(-1, -1)); 243 event_handler->OnMouseEvent(&mouse_event); 244 EXPECT_FALSE(mouse_event.handled()); 245 RunAllPendingInMessageLoop(); 246 EXPECT_FALSE(TooltipIsVisible()); 247 } 248 249 // Checks that tooltip is hidden when mouse is pressed in anywhere. 250 TEST_F(ShelfTooltipManagerTest, HideForMouseClickEvent) { 251 ShowImmediately(); 252 ASSERT_TRUE(TooltipIsVisible()); 253 254 aura::Window* root_window = Shell::GetInstance()->GetPrimaryRootWindow(); 255 ui::EventHandler* event_handler = GetEventHandler(); 256 257 gfx::Rect tooltip_rect = GetTooltipWidget()->GetNativeWindow()->bounds(); 258 ASSERT_FALSE(tooltip_rect.IsEmpty()); 259 260 // Should hide if the mouse is pressed in the tooltip. 261 ui::MouseEvent mouse_event(ui::ET_MOUSE_PRESSED, tooltip_rect.CenterPoint(), 262 tooltip_rect.CenterPoint(), ui::EF_NONE, 263 ui::EF_NONE); 264 265 SetEventTarget(root_window, &mouse_event); 266 event_handler->OnMouseEvent(&mouse_event); 267 EXPECT_FALSE(mouse_event.handled()); 268 RunAllPendingInMessageLoop(); 269 EXPECT_FALSE(TooltipIsVisible()); 270 271 // Should hide if the mouse is pressed outside of the tooltip. 272 ShowImmediately(); 273 ASSERT_TRUE(TooltipIsVisible()); 274 275 ui::LocatedEventTestApi test_api(&mouse_event); 276 test_api.set_location(tooltip_rect.origin() + gfx::Vector2d(-1, -1)); 277 278 SetEventTarget(root_window, &mouse_event); 279 event_handler->OnMouseEvent(&mouse_event); 280 EXPECT_FALSE(mouse_event.handled()); 281 RunAllPendingInMessageLoop(); 282 EXPECT_FALSE(TooltipIsVisible()); 283 } 284 285 } // namespace test 286 } // namespace ash 287