1// Copyright 2014 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 "athena/wm/public/window_manager.h"
6
7#include "athena/screen/public/screen_manager.h"
8#include "athena/test/athena_test_base.h"
9#include "athena/wm/public/window_list_provider.h"
10#include "athena/wm/split_view_controller.h"
11#include "athena/wm/test/window_manager_impl_test_api.h"
12#include "athena/wm/window_manager_impl.h"
13#include "ui/aura/client/window_tree_client.h"
14#include "ui/aura/test/test_window_delegate.h"
15#include "ui/aura/window.h"
16#include "ui/base/hit_test.h"
17#include "ui/events/test/event_generator.h"
18#include "ui/gfx/display.h"
19#include "ui/gfx/screen.h"
20#include "ui/wm/core/window_util.h"
21
22namespace athena {
23
24class WindowManagerTest : public test::AthenaTestBase {
25 public:
26  WindowManagerTest() {}
27  virtual ~WindowManagerTest() {}
28
29  scoped_ptr<aura::Window> CreateAndActivateWindow(
30      aura::WindowDelegate* delegate) {
31    scoped_ptr<aura::Window> window(CreateTestWindow(delegate, gfx::Rect()));
32    window->Show();
33    wm::ActivateWindow(window.get());
34    return window.Pass();
35  }
36
37 private:
38  DISALLOW_COPY_AND_ASSIGN(WindowManagerTest);
39};
40
41TEST_F(WindowManagerTest, OverviewModeBasics) {
42  aura::test::TestWindowDelegate delegate;
43  scoped_ptr<aura::Window> first(CreateAndActivateWindow(&delegate));
44  scoped_ptr<aura::Window> second(CreateAndActivateWindow(&delegate));
45
46  test::WindowManagerImplTestApi wm_api;
47  wm::ActivateWindow(second.get());
48
49  ASSERT_FALSE(WindowManager::Get()->IsOverviewModeActive());
50  EXPECT_EQ(first->bounds().ToString(), second->bounds().ToString());
51  EXPECT_EQ(gfx::Screen::GetNativeScreen()
52                ->GetPrimaryDisplay()
53                .work_area()
54                .size()
55                .ToString(),
56            first->bounds().size().ToString());
57  EXPECT_FALSE(WindowManager::Get()->IsOverviewModeActive());
58
59  // Tests that going into overview mode does not change the window bounds.
60  WindowManager::Get()->ToggleOverview();
61  ASSERT_TRUE(WindowManager::Get()->IsOverviewModeActive());
62  EXPECT_EQ(first->bounds().ToString(), second->bounds().ToString());
63  EXPECT_EQ(gfx::Screen::GetNativeScreen()
64                ->GetPrimaryDisplay()
65                .work_area()
66                .size()
67                .ToString(),
68            first->bounds().size().ToString());
69  EXPECT_TRUE(first->IsVisible());
70  EXPECT_TRUE(second->IsVisible());
71
72  // Terminate overview mode. |first| should be hidden, since it's not visible
73  // to the user anymore.
74  WindowManager::Get()->ToggleOverview();
75  ASSERT_FALSE(WindowManager::Get()->IsOverviewModeActive());
76  EXPECT_FALSE(first->IsVisible());
77  EXPECT_TRUE(second->IsVisible());
78}
79
80TEST_F(WindowManagerTest, OverviewToSplitViewMode) {
81  test::WindowManagerImplTestApi wm_api;
82
83  aura::test::TestWindowDelegate delegate;
84  scoped_ptr<aura::Window> w1(CreateAndActivateWindow(&delegate));
85  scoped_ptr<aura::Window> w2(CreateAndActivateWindow(&delegate));
86  scoped_ptr<aura::Window> w3(CreateAndActivateWindow(&delegate));
87  wm::ActivateWindow(w3.get());
88
89  WindowManager::Get()->ToggleOverview();
90  EXPECT_TRUE(w1->IsVisible());
91  EXPECT_TRUE(w2->IsVisible());
92  EXPECT_TRUE(w3->IsVisible());
93
94  // Go into split-view mode.
95  WindowOverviewModeDelegate* overview_delegate = wm_api.wm();
96  overview_delegate->OnSelectSplitViewWindow(w3.get(), NULL, w3.get());
97  EXPECT_TRUE(w3->IsVisible());
98  EXPECT_TRUE(w2->IsVisible());
99  EXPECT_FALSE(w1->IsVisible());
100}
101
102TEST_F(WindowManagerTest, NewWindowFromOverview) {
103  aura::test::TestWindowDelegate delegate;
104  scoped_ptr<aura::Window> w1(CreateAndActivateWindow(&delegate));
105  scoped_ptr<aura::Window> w2(CreateAndActivateWindow(&delegate));
106
107  WindowManager::Get()->ToggleOverview();
108  EXPECT_TRUE(w1->IsVisible());
109  EXPECT_TRUE(w2->IsVisible());
110
111  // Test that opening a new window exits overview mode. The new window could
112  // have been opened by JavaScript or by the home card.
113  scoped_ptr<aura::Window> w3(CreateAndActivateWindow(&delegate));
114
115  ASSERT_FALSE(WindowManager::Get()->IsOverviewModeActive());
116  EXPECT_TRUE(w3->IsVisible());
117  EXPECT_TRUE(wm::IsActiveWindow(w3.get()));
118  EXPECT_FALSE(w1->IsVisible());
119  EXPECT_FALSE(w2->IsVisible());
120}
121
122TEST_F(WindowManagerTest, BezelGestureToSplitViewMode) {
123  aura::test::TestWindowDelegate delegate;
124  scoped_ptr<aura::Window> first(CreateAndActivateWindow(&delegate));
125  scoped_ptr<aura::Window> second(CreateAndActivateWindow(&delegate));
126  scoped_ptr<aura::Window> third(CreateAndActivateWindow(&delegate));
127
128  test::WindowManagerImplTestApi wm_api;
129
130  // Test that going into split-view mode with two-finger gesture selects the
131  // correct windows on left and right splits.
132  ui::test::EventGenerator generator(root_window());
133  const gfx::Point start_points[2] = {
134      gfx::Point(2, 10), gfx::Point(4, 20),
135  };
136  const int kEventTimeSepration = 16;
137  int x_middle = root_window()->bounds().width() / 2;
138  generator.GestureMultiFingerScroll(
139      2, start_points, kEventTimeSepration, 1, x_middle, 0);
140  ASSERT_TRUE(wm_api.GetSplitViewController()->IsSplitViewModeActive());
141  EXPECT_EQ(second.get(), wm_api.GetSplitViewController()->left_window());
142  EXPECT_EQ(third.get(), wm_api.GetSplitViewController()->right_window());
143  EXPECT_EQ(second->bounds().size().ToString(),
144            third->bounds().size().ToString());
145}
146
147TEST_F(WindowManagerTest, BezelGestureToSwitchBetweenWindows) {
148  aura::test::TestWindowDelegate delegate;
149  scoped_ptr<aura::Window> first(CreateAndActivateWindow(&delegate));
150  scoped_ptr<aura::Window> second(CreateAndActivateWindow(&delegate));
151  scoped_ptr<aura::Window> third(CreateAndActivateWindow(&delegate));
152  first->Hide();
153  second->Hide();
154
155  test::WindowManagerImplTestApi wm_api;
156
157  EXPECT_EQ(third.get(),
158            wm_api.GetWindowListProvider()->GetWindowList().back());
159
160  // Do a two-finger swipe from the left bezel.
161  ui::test::EventGenerator generator(root_window());
162  const gfx::Point left_bezel_points[2] = {
163      gfx::Point(2, 10), gfx::Point(4, 20),
164  };
165  const int kEventTimeSeparation = 16;
166  int width = root_window()->bounds().width();
167  generator.GestureMultiFingerScroll(
168      2, left_bezel_points, kEventTimeSeparation, 1, width, 0);
169  EXPECT_TRUE(wm::IsActiveWindow(second.get()));
170  EXPECT_EQ(second.get(),
171            wm_api.GetWindowListProvider()->GetWindowList().back());
172
173  // Do a two-finger swipe from the right bezel.
174  const gfx::Point right_bezel_points[2] = {
175      gfx::Point(width - 5, 10),
176      gfx::Point(width - 10, 20)
177  };
178  generator.GestureMultiFingerScroll(
179      2, right_bezel_points, kEventTimeSeparation, 1, -width, 0);
180  EXPECT_TRUE(wm::IsActiveWindow(third.get()));
181  EXPECT_EQ(third.get(),
182            wm_api.GetWindowListProvider()->GetWindowList().back());
183}
184
185TEST_F(WindowManagerTest, TitleDragSwitchBetweenWindows) {
186  aura::test::TestWindowDelegate delegate;
187  delegate.set_window_component(HTCAPTION);
188  scoped_ptr<aura::Window> first(CreateAndActivateWindow(&delegate));
189  scoped_ptr<aura::Window> second(CreateAndActivateWindow(&delegate));
190  scoped_ptr<aura::Window> third(CreateAndActivateWindow(&delegate));
191
192  test::WindowManagerImplTestApi wm_api;
193
194  EXPECT_EQ(third.get(),
195            wm_api.GetWindowListProvider()->GetWindowList().back());
196
197  // Do a title-swipe from the top to switch to the previous window.
198  ui::test::EventGenerator generator(root_window());
199  generator.GestureScrollSequence(gfx::Point(20, 10),
200                                  gfx::Point(20, 400),
201                                  base::TimeDelta::FromMilliseconds(20),
202                                  5);
203  EXPECT_TRUE(wm::IsActiveWindow(second.get()));
204  EXPECT_EQ(second.get(),
205            wm_api.GetWindowListProvider()->GetWindowList().back());
206  EXPECT_TRUE(second->IsVisible());
207  EXPECT_FALSE(third->IsVisible());
208
209  // Performing the same gesture again will switch back to |third|.
210  generator.GestureScrollSequence(gfx::Point(20, 10),
211                                  gfx::Point(20, 400),
212                                  base::TimeDelta::FromMilliseconds(20),
213                                  5);
214  EXPECT_TRUE(wm::IsActiveWindow(third.get()));
215  EXPECT_EQ(third.get(),
216            wm_api.GetWindowListProvider()->GetWindowList().back());
217  EXPECT_FALSE(second->IsVisible());
218  EXPECT_TRUE(third->IsVisible());
219
220  // Perform a swipe that doesn't go enough to perform the window switch.
221  generator.GestureScrollSequence(gfx::Point(20, 10),
222                                  gfx::Point(20, 90),
223                                  base::TimeDelta::FromMilliseconds(20),
224                                  5);
225  EXPECT_TRUE(wm::IsActiveWindow(third.get()));
226  EXPECT_EQ(third.get(),
227            wm_api.GetWindowListProvider()->GetWindowList().back());
228  EXPECT_FALSE(second->IsVisible());
229  EXPECT_TRUE(third->IsVisible());
230}
231
232TEST_F(WindowManagerTest, TitleDragSwitchBetweenWindowsInSplitViewMode) {
233  aura::test::TestWindowDelegate delegate;
234  delegate.set_window_component(HTCAPTION);
235  scoped_ptr<aura::Window> first(CreateAndActivateWindow(&delegate));
236  scoped_ptr<aura::Window> second(CreateAndActivateWindow(&delegate));
237  scoped_ptr<aura::Window> third(CreateAndActivateWindow(&delegate));
238  scoped_ptr<aura::Window> fourth(CreateAndActivateWindow(&delegate));
239
240  test::WindowManagerImplTestApi wm_api;
241
242  // Test that going into split-view mode with two-finger gesture selects the
243  // correct windows on left and right splits.
244  ui::test::EventGenerator generator(root_window());
245  const gfx::Point start_points[2] = {
246      gfx::Point(2, 10), gfx::Point(4, 20),
247  };
248  const int kEventTimeSepration = 16;
249  int x_middle = root_window()->bounds().width() / 2;
250  generator.GestureMultiFingerScroll(
251      2, start_points, kEventTimeSepration, 1, x_middle, 0);
252  ASSERT_TRUE(wm_api.GetSplitViewController()->IsSplitViewModeActive());
253  EXPECT_EQ(third.get(), wm_api.GetSplitViewController()->left_window());
254  EXPECT_EQ(fourth.get(), wm_api.GetSplitViewController()->right_window());
255
256  // Swipe the title of the left window. It should switch to |second|.
257  generator.GestureScrollSequence(gfx::Point(20, 10),
258                                  gfx::Point(20, 400),
259                                  base::TimeDelta::FromMilliseconds(20),
260                                  5);
261  EXPECT_EQ(second.get(), wm_api.GetSplitViewController()->left_window());
262  EXPECT_EQ(fourth.get(), wm_api.GetSplitViewController()->right_window());
263  aura::Window::Windows windows =
264      wm_api.GetWindowListProvider()->GetWindowList();
265  ASSERT_EQ(4u, windows.size());
266  EXPECT_EQ(second.get(), windows[3]);
267  EXPECT_EQ(fourth.get(), windows[2]);
268
269  // Swipe the title of the right window now. It should switch to |third|.
270  generator.GestureScrollSequence(gfx::Point(x_middle + 20, 10),
271                                  gfx::Point(x_middle + 20, 400),
272                                  base::TimeDelta::FromMilliseconds(20),
273                                  5);
274  EXPECT_EQ(second.get(), wm_api.GetSplitViewController()->left_window());
275  EXPECT_EQ(third.get(), wm_api.GetSplitViewController()->right_window());
276  windows = wm_api.GetWindowListProvider()->GetWindowList();
277  ASSERT_EQ(4u, windows.size());
278  EXPECT_EQ(third.get(), windows[3]);
279  EXPECT_EQ(second.get(), windows[2]);
280}
281
282TEST_F(WindowManagerTest, NewWindowBounds) {
283  aura::test::TestWindowDelegate delegate;
284  scoped_ptr<aura::Window> first(CreateAndActivateWindow(&delegate));
285
286  test::WindowManagerImplTestApi wm_api;
287  // The window should have the same size as the container.
288  const gfx::Size work_area =
289      gfx::Screen::GetNativeScreen()->GetPrimaryDisplay().work_area().size();
290  EXPECT_EQ(work_area.ToString(),
291            first->bounds().size().ToString());
292  EXPECT_TRUE(first->bounds().origin().IsOrigin());
293
294  // A second window should have the same bounds as the first one.
295  scoped_ptr<aura::Window> second(CreateAndActivateWindow(&delegate));
296  EXPECT_EQ(first->bounds().ToString(), second->bounds().ToString());
297
298  // Get into split view.
299  wm_api.GetSplitViewController()->ActivateSplitMode(NULL, NULL, NULL);
300  const gfx::Rect left_bounds =
301      wm_api.GetSplitViewController()->left_window()->bounds();
302  EXPECT_NE(work_area.ToString(),
303            left_bounds.size().ToString());
304
305  // A new window should replace the left window when in split view.
306  scoped_ptr<aura::Window> third(CreateAndActivateWindow(&delegate));
307  EXPECT_EQ(wm_api.GetSplitViewController()->left_window(), third.get());
308  EXPECT_EQ(left_bounds.ToString(), third->bounds().ToString());
309}
310
311TEST_F(WindowManagerTest, SplitModeActivationByShortcut) {
312  test::WindowManagerImplTestApi wm_api;
313
314  aura::test::TestWindowDelegate delegate;
315  scoped_ptr<aura::Window> w1(CreateAndActivateWindow(&delegate));
316
317  // Splitview mode needs at least two windows.
318  wm_api.wm()->ToggleSplitView();
319  EXPECT_FALSE(wm_api.GetSplitViewController()->IsSplitViewModeActive());
320
321  scoped_ptr<aura::Window> w2(CreateAndActivateWindow(&delegate));
322  w2->Show();
323
324  wm_api.wm()->ToggleSplitView();
325  EXPECT_TRUE(wm_api.GetSplitViewController()->IsSplitViewModeActive());
326  int width =
327      gfx::Screen::GetNativeScreen()->GetPrimaryDisplay().work_area().width();
328
329  EXPECT_EQ(w1->bounds().width(), w2->bounds().width());
330  EXPECT_GE(width / 2, w1->bounds().width());
331
332  // Toggle back to normal mode.
333  wm_api.wm()->ToggleSplitView();
334  EXPECT_FALSE(wm_api.GetSplitViewController()->IsSplitViewModeActive());
335
336  EXPECT_EQ(width, w1->bounds().width());
337  EXPECT_EQ(width, w2->bounds().width());
338}
339
340TEST_F(WindowManagerTest, OverviewModeFromSplitMode) {
341  test::WindowManagerImplTestApi wm_api;
342
343  aura::test::TestWindowDelegate delegate;
344  scoped_ptr<aura::Window> w1(CreateAndActivateWindow(&delegate));
345  scoped_ptr<aura::Window> w2(CreateAndActivateWindow(&delegate));
346  scoped_ptr<aura::Window> w3(CreateAndActivateWindow(&delegate));
347
348  // Get into split-view mode, and then turn on overview mode.
349  wm_api.GetSplitViewController()->ActivateSplitMode(NULL, NULL, NULL);
350  WindowManager::Get()->ToggleOverview();
351  EXPECT_TRUE(wm_api.GetSplitViewController()->IsSplitViewModeActive());
352  EXPECT_EQ(w3.get(), wm_api.GetSplitViewController()->left_window());
353  EXPECT_EQ(w2.get(), wm_api.GetSplitViewController()->right_window());
354
355  WindowOverviewModeDelegate* overview_delegate = wm_api.wm();
356  overview_delegate->OnSelectWindow(w1.get());
357  EXPECT_FALSE(wm_api.GetSplitViewController()->IsSplitViewModeActive());
358  EXPECT_TRUE(w1->IsVisible());
359  // Make sure the windows that were in split-view mode are hidden.
360  EXPECT_FALSE(w2->IsVisible());
361  EXPECT_FALSE(w3->IsVisible());
362}
363
364}  // namespace athena
365