1// Copyright (c) 2012 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/launcher/launcher_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/wm/window_util.h"
14#include "base/strings/string16.h"
15#include "base/time/time.h"
16#include "ui/aura/root_window.h"
17#include "ui/base/events/event.h"
18#include "ui/base/events/event_constants.h"
19#include "ui/base/events/event_handler.h"
20#include "ui/base/keycodes/keyboard_codes.h"
21#include "ui/views/widget/widget.h"
22
23namespace {
24
25void SetEventTarget(ui::EventTarget* target,
26                    ui::Event* event) {
27  ui::Event::DispatcherApi dispatch_helper(event);
28  dispatch_helper.set_target(target);
29}
30
31}
32
33namespace ash {
34namespace test {
35
36class LauncherTooltipManagerTest : public AshTestBase {
37 public:
38  LauncherTooltipManagerTest() {}
39  virtual ~LauncherTooltipManagerTest() {}
40
41  virtual void SetUp() OVERRIDE {
42    AshTestBase::SetUp();
43    internal::RootWindowController* controller =
44        Shell::GetPrimaryRootWindowController();
45    tooltip_manager_.reset(new internal::LauncherTooltipManager(
46        controller->GetShelfLayoutManager(),
47        controller->shelf()->launcher()->GetLauncherViewForTest()));
48  }
49
50  virtual void TearDown() OVERRIDE {
51    tooltip_manager_.reset();
52    AshTestBase::TearDown();
53  }
54
55  void ShowDelayed() {
56    CreateWidget();
57    tooltip_manager_->ShowDelayed(dummy_anchor_.get(), base::string16());
58  }
59
60  void ShowImmediately() {
61    CreateWidget();
62    tooltip_manager_->ShowImmediately(dummy_anchor_.get(), base::string16());
63  }
64
65  bool TooltipIsVisible() {
66    return tooltip_manager_->IsVisible();
67  }
68
69  bool IsTimerRunning() {
70    return tooltip_manager_->timer_.get() != NULL;
71  }
72
73  ui::EventHandler* GetEventHandler() {
74    return tooltip_manager_.get();
75  }
76
77  views::Widget* GetTooltipWidget() {
78    return tooltip_manager_->widget_;
79  }
80
81 protected:
82  scoped_ptr<views::Widget> widget_;
83  scoped_ptr<views::View> dummy_anchor_;
84  scoped_ptr<internal::LauncherTooltipManager> tooltip_manager_;
85
86 private:
87  void CreateWidget() {
88    dummy_anchor_.reset(new views::View);
89
90    widget_.reset(new views::Widget);
91    views::Widget::InitParams params(
92        views::Widget::InitParams::TYPE_WINDOW_FRAMELESS);
93    params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW;
94    params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
95    params.parent = Shell::GetContainer(
96        Shell::GetPrimaryRootWindow(),
97        ash::internal::kShellWindowId_ShelfContainer);
98
99    widget_->Init(params);
100    widget_->SetContentsView(dummy_anchor_.get());
101  }
102
103  DISALLOW_COPY_AND_ASSIGN(LauncherTooltipManagerTest);
104};
105
106TEST_F(LauncherTooltipManagerTest, 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(LauncherTooltipManagerTest, 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(LauncherTooltipManagerTest, 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  internal::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(LauncherTooltipManagerTest, ShouldHideForEvents) {
179  ShowImmediately();
180  ASSERT_TRUE(TooltipIsVisible());
181
182  aura::RootWindow* 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
220TEST_F(LauncherTooltipManagerTest, HideForMouseEvent) {
221  ShowImmediately();
222  ASSERT_TRUE(TooltipIsVisible());
223
224  aura::RootWindow* 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::LocatedEvent::TestApi test_api(&mouse_event);
234
235  SetEventTarget(root_window, &mouse_event);
236  event_handler->OnMouseEvent(&mouse_event);
237  EXPECT_FALSE(mouse_event.handled());
238  EXPECT_TRUE(TooltipIsVisible());
239
240  // Should hide if the mouse is out of the tooltip.
241  test_api.set_location(tooltip_rect.origin() + gfx::Vector2d(-1, -1));
242  event_handler->OnMouseEvent(&mouse_event);
243  EXPECT_FALSE(mouse_event.handled());
244  RunAllPendingInMessageLoop();
245  EXPECT_FALSE(TooltipIsVisible());
246}
247
248}  // namespace test
249}  // namespace ash
250