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/launcher_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/root_window.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 internal::RootWindowController* controller = 46 Shell::GetPrimaryRootWindowController(); 47 tooltip_manager_.reset(new internal::ShelfTooltipManager( 48 controller->GetShelfLayoutManager(), 49 LauncherTestAPI(controller->shelf()->launcher()).shelf_view())); 50 } 51 52 virtual void TearDown() OVERRIDE { 53 tooltip_manager_.reset(); 54 AshTestBase::TearDown(); 55 } 56 57 void ShowDelayed() { 58 CreateWidget(); 59 tooltip_manager_->ShowDelayed(dummy_anchor_.get(), base::string16()); 60 } 61 62 void ShowImmediately() { 63 CreateWidget(); 64 tooltip_manager_->ShowImmediately(dummy_anchor_.get(), base::string16()); 65 } 66 67 bool TooltipIsVisible() { 68 return tooltip_manager_->IsVisible(); 69 } 70 71 bool IsTimerRunning() { 72 return tooltip_manager_->timer_.get() != NULL; 73 } 74 75 ui::EventHandler* GetEventHandler() { 76 return tooltip_manager_.get(); 77 } 78 79 views::Widget* GetTooltipWidget() { 80 return tooltip_manager_->widget_; 81 } 82 83 protected: 84 scoped_ptr<views::Widget> widget_; 85 scoped_ptr<views::View> dummy_anchor_; 86 scoped_ptr<internal::ShelfTooltipManager> tooltip_manager_; 87 88 private: 89 void CreateWidget() { 90 dummy_anchor_.reset(new views::View); 91 92 widget_.reset(new views::Widget); 93 views::Widget::InitParams params( 94 views::Widget::InitParams::TYPE_WINDOW_FRAMELESS); 95 params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW; 96 params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; 97 params.parent = Shell::GetContainer( 98 Shell::GetPrimaryRootWindow(), 99 ash::internal::kShellWindowId_ShelfContainer); 100 101 widget_->Init(params); 102 widget_->SetContentsView(dummy_anchor_.get()); 103 } 104 105 DISALLOW_COPY_AND_ASSIGN(ShelfTooltipManagerTest); 106 }; 107 108 TEST_F(ShelfTooltipManagerTest, ShowingBasics) { 109 // ShowDelayed() should just start the timer instead of showing immediately. 110 ShowDelayed(); 111 EXPECT_FALSE(TooltipIsVisible()); 112 EXPECT_TRUE(IsTimerRunning()); 113 114 ShowImmediately(); 115 EXPECT_TRUE(TooltipIsVisible()); 116 EXPECT_FALSE(IsTimerRunning()); 117 } 118 119 TEST_F(ShelfTooltipManagerTest, HideWhenShelfIsHidden) { 120 ShowImmediately(); 121 ASSERT_TRUE(TooltipIsVisible()); 122 123 // Create a full-screen window to hide the shelf. 124 scoped_ptr<views::Widget> widget(new views::Widget); 125 views::Widget::InitParams params(views::Widget::InitParams::TYPE_WINDOW); 126 params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; 127 params.context = CurrentContext(); 128 widget->Init(params); 129 widget->SetFullscreen(true); 130 widget->Show(); 131 132 // Once the shelf is hidden, the tooltip should be invisible. 133 ASSERT_EQ( 134 SHELF_HIDDEN, 135 Shell::GetPrimaryRootWindowController()-> 136 GetShelfLayoutManager()->visibility_state()); 137 EXPECT_FALSE(TooltipIsVisible()); 138 139 // Do not show the view if the shelf is hidden. 140 ShowImmediately(); 141 EXPECT_FALSE(TooltipIsVisible()); 142 143 // ShowDelayed() doesn't even start the timer for the hidden shelf. 144 ShowDelayed(); 145 EXPECT_FALSE(IsTimerRunning()); 146 } 147 148 TEST_F(ShelfTooltipManagerTest, HideWhenShelfIsAutoHide) { 149 // Create a visible window so auto-hide behavior is enforced. 150 views::Widget* dummy = new views::Widget; 151 views::Widget::InitParams params(views::Widget::InitParams::TYPE_WINDOW); 152 params.bounds = gfx::Rect(0, 0, 200, 200); 153 params.context = CurrentContext(); 154 dummy->Init(params); 155 dummy->Show(); 156 157 ShowImmediately(); 158 ASSERT_TRUE(TooltipIsVisible()); 159 160 internal::ShelfLayoutManager* shelf = 161 Shell::GetPrimaryRootWindowController()->GetShelfLayoutManager(); 162 shelf->SetAutoHideBehavior(SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS); 163 shelf->UpdateAutoHideState(); 164 ASSERT_EQ(SHELF_AUTO_HIDE_HIDDEN, shelf->auto_hide_state()); 165 166 // Tooltip visibility change for auto hide may take time. 167 EXPECT_TRUE(TooltipIsVisible()); 168 RunAllPendingInMessageLoop(); 169 EXPECT_FALSE(TooltipIsVisible()); 170 171 // Do not show the view if the shelf is hidden. 172 ShowImmediately(); 173 EXPECT_FALSE(TooltipIsVisible()); 174 175 // ShowDelayed doesn't even run the timer for the hidden shelf. 176 ShowDelayed(); 177 EXPECT_FALSE(IsTimerRunning()); 178 } 179 180 TEST_F(ShelfTooltipManagerTest, ShouldHideForEvents) { 181 ShowImmediately(); 182 ASSERT_TRUE(TooltipIsVisible()); 183 184 aura::Window* root_window = Shell::GetInstance()->GetPrimaryRootWindow(); 185 ui::EventHandler* event_handler = GetEventHandler(); 186 187 // Should not hide for key events. 188 ui::KeyEvent key_event(ui::ET_KEY_PRESSED, ui::VKEY_A, ui::EF_NONE, false); 189 SetEventTarget(root_window, &key_event); 190 event_handler->OnKeyEvent(&key_event); 191 EXPECT_FALSE(key_event.handled()); 192 EXPECT_TRUE(TooltipIsVisible()); 193 194 // Should hide for touch events. 195 ui::TouchEvent touch_event( 196 ui::ET_TOUCH_PRESSED, gfx::Point(), 0, base::TimeDelta()); 197 SetEventTarget(root_window, &touch_event); 198 event_handler->OnTouchEvent(&touch_event); 199 EXPECT_FALSE(touch_event.handled()); 200 EXPECT_FALSE(TooltipIsVisible()); 201 202 // Shouldn't hide if the touch happens on the tooltip. 203 ShowImmediately(); 204 views::Widget* tooltip_widget = GetTooltipWidget(); 205 SetEventTarget(tooltip_widget->GetNativeWindow(), &touch_event); 206 event_handler->OnTouchEvent(&touch_event); 207 EXPECT_FALSE(touch_event.handled()); 208 EXPECT_TRUE(TooltipIsVisible()); 209 210 // Should hide for gesture events. 211 ui::GestureEvent gesture_event( 212 ui::ET_GESTURE_BEGIN, 0, 0, ui::EF_NONE, 213 base::TimeDelta::FromMilliseconds(base::Time::Now().ToDoubleT() * 1000), 214 ui::GestureEventDetails(ui::ET_GESTURE_BEGIN, 0.0f, 0.0f), 0); 215 SetEventTarget(tooltip_widget->GetNativeWindow(), &gesture_event); 216 event_handler->OnGestureEvent(&gesture_event); 217 EXPECT_FALSE(gesture_event.handled()); 218 RunAllPendingInMessageLoop(); 219 EXPECT_FALSE(TooltipIsVisible()); 220 } 221 222 TEST_F(ShelfTooltipManagerTest, HideForMouseMoveEvent) { 223 ShowImmediately(); 224 ASSERT_TRUE(TooltipIsVisible()); 225 226 aura::Window* root_window = Shell::GetInstance()->GetPrimaryRootWindow(); 227 ui::EventHandler* event_handler = GetEventHandler(); 228 229 gfx::Rect tooltip_rect = GetTooltipWidget()->GetNativeWindow()->bounds(); 230 ASSERT_FALSE(tooltip_rect.IsEmpty()); 231 232 // Shouldn't hide if the mouse is in the tooltip. 233 ui::MouseEvent mouse_event(ui::ET_MOUSE_MOVED, tooltip_rect.CenterPoint(), 234 tooltip_rect.CenterPoint(), ui::EF_NONE); 235 ui::LocatedEventTestApi test_api(&mouse_event); 236 237 SetEventTarget(root_window, &mouse_event); 238 event_handler->OnMouseEvent(&mouse_event); 239 EXPECT_FALSE(mouse_event.handled()); 240 EXPECT_TRUE(TooltipIsVisible()); 241 242 // Should hide if the mouse is out of the tooltip. 243 test_api.set_location(tooltip_rect.origin() + gfx::Vector2d(-1, -1)); 244 event_handler->OnMouseEvent(&mouse_event); 245 EXPECT_FALSE(mouse_event.handled()); 246 RunAllPendingInMessageLoop(); 247 EXPECT_FALSE(TooltipIsVisible()); 248 } 249 250 // Checks that tooltip is hidden when mouse is pressed in anywhere. 251 TEST_F(ShelfTooltipManagerTest, HideForMouseClickEvent) { 252 ShowImmediately(); 253 ASSERT_TRUE(TooltipIsVisible()); 254 255 aura::Window* root_window = Shell::GetInstance()->GetPrimaryRootWindow(); 256 ui::EventHandler* event_handler = GetEventHandler(); 257 258 gfx::Rect tooltip_rect = GetTooltipWidget()->GetNativeWindow()->bounds(); 259 ASSERT_FALSE(tooltip_rect.IsEmpty()); 260 261 // Should hide if the mouse is pressed in the tooltip. 262 ui::MouseEvent mouse_event(ui::ET_MOUSE_PRESSED, tooltip_rect.CenterPoint(), 263 tooltip_rect.CenterPoint(), 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