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
25namespace {
26
27void 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
35namespace ash {
36namespace test {
37
38class 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
106TEST_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
117TEST_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
146TEST_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
178TEST_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);
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      0,
211      0,
212      ui::EF_NONE,
213      base::TimeDelta::FromMilliseconds(base::Time::Now().ToDoubleT() * 1000),
214      ui::GestureEventDetails(ui::ET_GESTURE_BEGIN));
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
222TEST_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::EF_NONE);
236  ui::LocatedEventTestApi test_api(&mouse_event);
237
238  SetEventTarget(root_window, &mouse_event);
239  event_handler->OnMouseEvent(&mouse_event);
240  EXPECT_FALSE(mouse_event.handled());
241  EXPECT_TRUE(TooltipIsVisible());
242
243  // Should hide if the mouse is out of the tooltip.
244  test_api.set_location(tooltip_rect.origin() + gfx::Vector2d(-1, -1));
245  event_handler->OnMouseEvent(&mouse_event);
246  EXPECT_FALSE(mouse_event.handled());
247  RunAllPendingInMessageLoop();
248  EXPECT_FALSE(TooltipIsVisible());
249}
250
251// Checks that tooltip is hidden when mouse is pressed in anywhere.
252TEST_F(ShelfTooltipManagerTest, HideForMouseClickEvent) {
253  ShowImmediately();
254  ASSERT_TRUE(TooltipIsVisible());
255
256  aura::Window* root_window = Shell::GetInstance()->GetPrimaryRootWindow();
257  ui::EventHandler* event_handler = GetEventHandler();
258
259  gfx::Rect tooltip_rect = GetTooltipWidget()->GetNativeWindow()->bounds();
260  ASSERT_FALSE(tooltip_rect.IsEmpty());
261
262  // Should hide if the mouse is pressed in the tooltip.
263  ui::MouseEvent mouse_event(ui::ET_MOUSE_PRESSED, tooltip_rect.CenterPoint(),
264                             tooltip_rect.CenterPoint(), ui::EF_NONE,
265                             ui::EF_NONE);
266
267  SetEventTarget(root_window, &mouse_event);
268  event_handler->OnMouseEvent(&mouse_event);
269  EXPECT_FALSE(mouse_event.handled());
270  RunAllPendingInMessageLoop();
271  EXPECT_FALSE(TooltipIsVisible());
272
273  // Should hide if the mouse is pressed outside of the tooltip.
274  ShowImmediately();
275  ASSERT_TRUE(TooltipIsVisible());
276
277  ui::LocatedEventTestApi test_api(&mouse_event);
278  test_api.set_location(tooltip_rect.origin() + gfx::Vector2d(-1, -1));
279
280  SetEventTarget(root_window, &mouse_event);
281  event_handler->OnMouseEvent(&mouse_event);
282  EXPECT_FALSE(mouse_event.handled());
283  RunAllPendingInMessageLoop();
284  EXPECT_FALSE(TooltipIsVisible());
285}
286
287}  // namespace test
288}  // namespace ash
289