panel_window_resizer_unittest.cc revision 58537e28ecd584eab876aee8be7156509866d23a
1// Copyright (c) 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/wm/panels/panel_window_resizer.h"
6
7#include "ash/launcher/launcher.h"
8#include "ash/launcher/launcher_model.h"
9#include "ash/root_window_controller.h"
10#include "ash/shelf/shelf_layout_manager.h"
11#include "ash/shelf/shelf_types.h"
12#include "ash/shelf/shelf_widget.h"
13#include "ash/shell.h"
14#include "ash/shell_window_ids.h"
15#include "ash/test/ash_test_base.h"
16#include "ash/test/cursor_manager_test_api.h"
17#include "ash/test/shell_test_api.h"
18#include "ash/test/test_launcher_delegate.h"
19#include "ash/wm/drag_window_resizer.h"
20#include "ash/wm/panels/panel_layout_manager.h"
21#include "ash/wm/window_settings.h"
22#include "ui/aura/client/aura_constants.h"
23#include "ui/aura/root_window.h"
24#include "ui/base/hit_test.h"
25#include "ui/base/l10n/l10n_util.h"
26#include "ui/base/ui_base_types.h"
27#include "ui/views/widget/widget.h"
28
29namespace ash {
30namespace internal {
31
32class PanelWindowResizerTest : public test::AshTestBase {
33 public:
34  PanelWindowResizerTest() {}
35  virtual ~PanelWindowResizerTest() {}
36
37  virtual void SetUp() OVERRIDE {
38    AshTestBase::SetUp();
39    UpdateDisplay("600x400");
40    test::ShellTestApi test_api(Shell::GetInstance());
41    model_ = test_api.launcher_model();
42    launcher_delegate_ = test::TestLauncherDelegate::instance();
43  }
44
45  virtual void TearDown() OVERRIDE {
46    AshTestBase::TearDown();
47  }
48
49 protected:
50  gfx::Point CalculateDragPoint(const WindowResizer& resizer,
51                                int delta_x,
52                                int delta_y) const {
53    gfx::Point location = resizer.GetInitialLocation();
54    location.set_x(location.x() + delta_x);
55    location.set_y(location.y() + delta_y);
56    return location;
57  }
58
59  aura::Window* CreatePanelWindow(const gfx::Rect& bounds) {
60    aura::Window* window = CreateTestWindowInShellWithDelegateAndType(
61        NULL,
62        aura::client::WINDOW_TYPE_PANEL,
63        0,
64        bounds);
65    launcher_delegate_->AddLauncherItem(window);
66    PanelLayoutManager* manager =
67        static_cast<PanelLayoutManager*>(
68            Shell::GetContainer(window->GetRootWindow(),
69                                internal::kShellWindowId_PanelContainer)->
70                layout_manager());
71    manager->Relayout();
72    return window;
73  }
74
75  void DragStart(aura::Window* window) {
76    resizer_.reset(CreateWindowResizer(
77        window,
78        window->bounds().origin(),
79        HTCAPTION,
80        aura::client::WINDOW_MOVE_SOURCE_MOUSE).release());
81    ASSERT_TRUE(resizer_.get());
82  }
83
84  void DragMove(int dx, int dy) {
85    resizer_->Drag(CalculateDragPoint(*resizer_, dx, dy), 0);
86  }
87
88  void DragEnd() {
89    resizer_->CompleteDrag(0);
90    resizer_.reset();
91  }
92
93  void DragRevert() {
94    resizer_->RevertDrag();
95    resizer_.reset();
96  }
97
98  // Test dragging the panel slightly, then detaching, and then reattaching
99  // dragging out by the vector (dx, dy).
100  void DetachReattachTest(aura::Window* window, int dx, int dy) {
101    EXPECT_TRUE(wm::GetWindowSettings(window)->panel_attached());
102    aura::RootWindow* root_window = window->GetRootWindow();
103    EXPECT_EQ(internal::kShellWindowId_PanelContainer, window->parent()->id());
104    DragStart(window);
105    gfx::Rect initial_bounds = window->GetBoundsInScreen();
106
107    // Drag the panel slightly. The window should still be snapped to the
108    // launcher.
109    DragMove(dx * 5, dy * 5);
110    EXPECT_EQ(initial_bounds.x(), window->GetBoundsInScreen().x());
111    EXPECT_EQ(initial_bounds.y(), window->GetBoundsInScreen().y());
112
113    // Drag further out and the window should now move to the cursor.
114    DragMove(dx * 100, dy * 100);
115    EXPECT_EQ(initial_bounds.x() + dx * 100, window->GetBoundsInScreen().x());
116    EXPECT_EQ(initial_bounds.y() + dy * 100, window->GetBoundsInScreen().y());
117
118    // The panel should be detached when the drag completes.
119    DragEnd();
120
121    EXPECT_FALSE(wm::GetWindowSettings(window)->panel_attached());
122    EXPECT_EQ(internal::kShellWindowId_DefaultContainer,
123              window->parent()->id());
124    EXPECT_EQ(root_window, window->GetRootWindow());
125
126    DragStart(window);
127    // Drag the panel down.
128    DragMove(dx * -95, dy * -95);
129    // Release the mouse and the panel should be reattached.
130    DragEnd();
131
132    // The panel should be reattached and have snapped to the launcher.
133    EXPECT_TRUE(wm::GetWindowSettings(window)->panel_attached());
134    EXPECT_EQ(initial_bounds.x(), window->GetBoundsInScreen().x());
135    EXPECT_EQ(initial_bounds.y(), window->GetBoundsInScreen().y());
136    EXPECT_EQ(internal::kShellWindowId_PanelContainer, window->parent()->id());
137  }
138
139  void TestWindowOrder(const std::vector<aura::Window*>& window_order) {
140    int panel_index = model_->FirstPanelIndex();
141    EXPECT_EQ((int)(panel_index + window_order.size()), model_->item_count());
142    for (std::vector<aura::Window*>::const_iterator iter =
143         window_order.begin(); iter != window_order.end();
144         ++iter, ++panel_index) {
145      LauncherID id = launcher_delegate_->GetIDByWindow(*iter);
146      EXPECT_EQ(id, model_->items()[panel_index].id);
147    }
148  }
149
150  // Test dragging panel window along the shelf and verify that panel icons
151  // are reordered appropriately.
152  void DragAlongShelfReorder(int dx, int dy) {
153    gfx::Rect bounds(0, 0, 201, 201);
154    scoped_ptr<aura::Window> w1(CreatePanelWindow(bounds));
155    scoped_ptr<aura::Window> w2(CreatePanelWindow(bounds));
156    std::vector<aura::Window*> window_order_original;
157    std::vector<aura::Window*> window_order_swapped;
158    window_order_original.push_back(w1.get());
159    window_order_original.push_back(w2.get());
160    window_order_swapped.push_back(w2.get());
161    window_order_swapped.push_back(w1.get());
162    TestWindowOrder(window_order_original);
163
164    // Drag window #2 to the beginning of the shelf.
165    DragStart(w2.get());
166    DragMove(400 * dx, 400 * dy);
167    TestWindowOrder(window_order_swapped);
168    DragEnd();
169
170    // Expect swapped window order.
171    TestWindowOrder(window_order_swapped);
172
173    // Drag window #2 back to the end.
174    DragStart(w2.get());
175    DragMove(-400 * dx, -400 * dy);
176    TestWindowOrder(window_order_original);
177    DragEnd();
178
179    // Expect original order.
180    TestWindowOrder(window_order_original);
181  }
182
183 private:
184  scoped_ptr<WindowResizer> resizer_;
185  internal::PanelLayoutManager* panel_layout_manager_;
186  LauncherModel* model_;
187  test::TestLauncherDelegate* launcher_delegate_;
188
189  DISALLOW_COPY_AND_ASSIGN(PanelWindowResizerTest);
190};
191
192class PanelWindowResizerTextDirectionTest
193    : public PanelWindowResizerTest,
194      public testing::WithParamInterface<bool> {
195 public:
196  PanelWindowResizerTextDirectionTest() : is_rtl_(GetParam()) {}
197  virtual ~PanelWindowResizerTextDirectionTest() {}
198
199  virtual void SetUp() OVERRIDE {
200    original_locale = l10n_util::GetApplicationLocale(std::string());
201    if (is_rtl_)
202      base::i18n::SetICUDefaultLocale("he");
203    PanelWindowResizerTest::SetUp();
204    ASSERT_EQ(is_rtl_, base::i18n::IsRTL());
205  }
206
207  virtual void TearDown() OVERRIDE {
208    if (is_rtl_)
209      base::i18n::SetICUDefaultLocale(original_locale);
210    PanelWindowResizerTest::TearDown();
211  }
212
213 private:
214  bool is_rtl_;
215  std::string original_locale;
216
217  DISALLOW_COPY_AND_ASSIGN(PanelWindowResizerTextDirectionTest);
218};
219
220// Verifies a window can be dragged from the panel and detached and then
221// reattached.
222TEST_F(PanelWindowResizerTest, PanelDetachReattachBottom) {
223 if (!SupportsHostWindowResize())
224    return;
225
226  scoped_ptr<aura::Window> window(
227      CreatePanelWindow(gfx::Rect(0, 0, 201, 201)));
228  DetachReattachTest(window.get(), 0, -1);
229}
230
231TEST_F(PanelWindowResizerTest, PanelDetachReattachLeft) {
232 if (!SupportsHostWindowResize())
233    return;
234
235  ash::Shell* shell = ash::Shell::GetInstance();
236  shell->SetShelfAlignment(SHELF_ALIGNMENT_LEFT, shell->GetPrimaryRootWindow());
237  scoped_ptr<aura::Window> window(
238      CreatePanelWindow(gfx::Rect(0, 0, 201, 201)));
239  DetachReattachTest(window.get(), 1, 0);
240}
241
242TEST_F(PanelWindowResizerTest, PanelDetachReattachRight) {
243  if (!SupportsHostWindowResize())
244    return;
245
246  ash::Shell* shell = ash::Shell::GetInstance();
247  shell->SetShelfAlignment(SHELF_ALIGNMENT_RIGHT,
248                           shell->GetPrimaryRootWindow());
249  scoped_ptr<aura::Window> window(
250      CreatePanelWindow(gfx::Rect(0, 0, 201, 201)));
251  DetachReattachTest(window.get(), -1, 0);
252}
253
254TEST_F(PanelWindowResizerTest, PanelDetachReattachTop) {
255 if (!SupportsHostWindowResize())
256    return;
257
258  ash::Shell* shell = ash::Shell::GetInstance();
259  shell->SetShelfAlignment(SHELF_ALIGNMENT_TOP, shell->GetPrimaryRootWindow());
260  scoped_ptr<aura::Window> window(
261      CreatePanelWindow(gfx::Rect(0, 0, 201, 201)));
262  DetachReattachTest(window.get(), 0, 1);
263}
264
265TEST_F(PanelWindowResizerTest, PanelDetachReattachMultipleDisplays) {
266  if (!SupportsMultipleDisplays())
267    return;
268
269  UpdateDisplay("600x400,600x400");
270  Shell::RootWindowList root_windows = Shell::GetAllRootWindows();
271  scoped_ptr<aura::Window> window(
272      CreatePanelWindow(gfx::Rect(600, 0, 201, 201)));
273  EXPECT_EQ(root_windows[1], window->GetRootWindow());
274  DetachReattachTest(window.get(), 0, -1);
275}
276
277TEST_F(PanelWindowResizerTest, DetachThenDragAcrossDisplays) {
278  if (!SupportsMultipleDisplays())
279    return;
280
281  UpdateDisplay("600x400,600x400");
282  Shell::RootWindowList root_windows = Shell::GetAllRootWindows();
283  scoped_ptr<aura::Window> window(
284      CreatePanelWindow(gfx::Rect(0, 0, 201, 201)));
285  gfx::Rect initial_bounds = window->GetBoundsInScreen();
286  EXPECT_EQ(root_windows[0], window->GetRootWindow());
287  DragStart(window.get());
288  DragMove(0, -100);
289  DragEnd();
290  EXPECT_EQ(root_windows[0], window->GetRootWindow());
291  EXPECT_EQ(initial_bounds.x(), window->GetBoundsInScreen().x());
292  EXPECT_EQ(initial_bounds.y() - 100, window->GetBoundsInScreen().y());
293  EXPECT_FALSE(wm::GetWindowSettings(window.get())->panel_attached());
294  EXPECT_EQ(internal::kShellWindowId_DefaultContainer,
295            window->parent()->id());
296
297  DragStart(window.get());
298  DragMove(500, 0);
299  DragEnd();
300  EXPECT_EQ(root_windows[1], window->GetRootWindow());
301  EXPECT_EQ(initial_bounds.x() + 500, window->GetBoundsInScreen().x());
302  EXPECT_EQ(initial_bounds.y() - 100, window->GetBoundsInScreen().y());
303  EXPECT_FALSE(wm::GetWindowSettings(window.get())->panel_attached());
304  EXPECT_EQ(internal::kShellWindowId_DefaultContainer,
305            window->parent()->id());
306}
307
308TEST_F(PanelWindowResizerTest, DetachAcrossDisplays) {
309  if (!SupportsMultipleDisplays())
310    return;
311
312  UpdateDisplay("600x400,600x400");
313  Shell::RootWindowList root_windows = Shell::GetAllRootWindows();
314  scoped_ptr<aura::Window> window(
315      CreatePanelWindow(gfx::Rect(0, 0, 201, 201)));
316  gfx::Rect initial_bounds = window->GetBoundsInScreen();
317  EXPECT_EQ(root_windows[0], window->GetRootWindow());
318  DragStart(window.get());
319  DragMove(500, -100);
320  DragEnd();
321  EXPECT_EQ(root_windows[1], window->GetRootWindow());
322  EXPECT_EQ(initial_bounds.x() + 500, window->GetBoundsInScreen().x());
323  EXPECT_EQ(initial_bounds.y() - 100, window->GetBoundsInScreen().y());
324  EXPECT_FALSE(wm::GetWindowSettings(window.get())->panel_attached());
325  EXPECT_EQ(internal::kShellWindowId_DefaultContainer,
326            window->parent()->id());
327}
328
329TEST_F(PanelWindowResizerTest, DetachThenAttachToSecondDisplay) {
330  if (!SupportsMultipleDisplays())
331    return;
332
333  UpdateDisplay("600x400,600x600");
334  Shell::RootWindowList root_windows = Shell::GetAllRootWindows();
335  scoped_ptr<aura::Window> window(
336      CreatePanelWindow(gfx::Rect(0, 0, 201, 201)));
337  gfx::Rect initial_bounds = window->GetBoundsInScreen();
338  EXPECT_EQ(root_windows[0], window->GetRootWindow());
339
340  // Detach the window.
341  DragStart(window.get());
342  DragMove(0, -100);
343  DragEnd();
344  EXPECT_EQ(root_windows[0], window->GetRootWindow());
345  EXPECT_FALSE(wm::GetWindowSettings(window.get())->panel_attached());
346
347  // Drag the window just above the other display's launcher.
348  DragStart(window.get());
349  DragMove(500, 295);
350  EXPECT_EQ(initial_bounds.x() + 500, window->GetBoundsInScreen().x());
351
352  // Should stick to other launcher.
353  EXPECT_EQ(initial_bounds.y() + 200, window->GetBoundsInScreen().y());
354  DragEnd();
355
356  // When dropped should move to second display's panel container.
357  EXPECT_EQ(root_windows[1], window->GetRootWindow());
358  EXPECT_TRUE(wm::GetWindowSettings(window.get())->panel_attached());
359  EXPECT_EQ(internal::kShellWindowId_PanelContainer, window->parent()->id());
360}
361
362TEST_F(PanelWindowResizerTest, AttachToSecondDisplay) {
363  if (!SupportsMultipleDisplays())
364    return;
365
366  UpdateDisplay("600x400,600x600");
367  Shell::RootWindowList root_windows = Shell::GetAllRootWindows();
368  scoped_ptr<aura::Window> window(
369      CreatePanelWindow(gfx::Rect(0, 0, 201, 201)));
370  gfx::Rect initial_bounds = window->GetBoundsInScreen();
371  EXPECT_EQ(root_windows[0], window->GetRootWindow());
372
373  // Drag the window just above the other display's launcher.
374  DragStart(window.get());
375  DragMove(500, 195);
376  EXPECT_EQ(initial_bounds.x() + 500, window->GetBoundsInScreen().x());
377
378  // Should stick to other launcher.
379  EXPECT_EQ(initial_bounds.y() + 200, window->GetBoundsInScreen().y());
380  DragEnd();
381
382  // When dropped should move to second display's panel container.
383  EXPECT_EQ(root_windows[1], window->GetRootWindow());
384  EXPECT_TRUE(wm::GetWindowSettings(window.get())->panel_attached());
385  EXPECT_EQ(internal::kShellWindowId_PanelContainer, window->parent()->id());
386}
387
388TEST_F(PanelWindowResizerTest, RevertDragRestoresAttachment) {
389  scoped_ptr<aura::Window> window(
390      CreatePanelWindow(gfx::Rect(0, 0, 201, 201)));
391  EXPECT_TRUE(wm::GetWindowSettings(window.get())->panel_attached());
392  EXPECT_EQ(internal::kShellWindowId_PanelContainer, window->parent()->id());
393  DragStart(window.get());
394  DragMove(0, -100);
395  DragRevert();
396  EXPECT_TRUE(wm::GetWindowSettings(window.get())->panel_attached());
397  EXPECT_EQ(internal::kShellWindowId_PanelContainer, window->parent()->id());
398
399  // Detach panel.
400  DragStart(window.get());
401  DragMove(0, -100);
402  DragEnd();
403  EXPECT_FALSE(wm::GetWindowSettings(window.get())->panel_attached());
404  EXPECT_EQ(internal::kShellWindowId_DefaultContainer,
405            window->parent()->id());
406
407  // Drag back to launcher.
408  DragStart(window.get());
409  DragMove(0, 100);
410
411  // When the drag is reverted it should remain detached.
412  DragRevert();
413  EXPECT_FALSE(wm::GetWindowSettings(window.get())->panel_attached());
414  EXPECT_EQ(internal::kShellWindowId_DefaultContainer,
415            window->parent()->id());
416}
417
418TEST_F(PanelWindowResizerTest, DragMovesToPanelLayer) {
419  scoped_ptr<aura::Window> window(CreatePanelWindow(gfx::Rect(0, 0, 201, 201)));
420  DragStart(window.get());
421  DragMove(0, -100);
422  DragEnd();
423  EXPECT_EQ(internal::kShellWindowId_DefaultContainer,
424            window->parent()->id());
425
426  // While moving the panel window should be moved to the panel container.
427  DragStart(window.get());
428  DragMove(20, 0);
429  EXPECT_EQ(internal::kShellWindowId_PanelContainer, window->parent()->id());
430  DragEnd();
431
432  // When dropped it should return to the default container.
433  EXPECT_EQ(internal::kShellWindowId_DefaultContainer,
434            window->parent()->id());
435}
436
437TEST_P(PanelWindowResizerTextDirectionTest, DragReordersPanelsHorizontal) {
438  if (!SupportsHostWindowResize())
439    return;
440
441  DragAlongShelfReorder(base::i18n::IsRTL() ? 1 : -1, 0);
442}
443
444TEST_F(PanelWindowResizerTest, DragReordersPanelsVertical) {
445  if (!SupportsHostWindowResize())
446    return;
447
448  ash::Shell* shell = ash::Shell::GetInstance();
449  shell->SetShelfAlignment(SHELF_ALIGNMENT_LEFT, shell->GetPrimaryRootWindow());
450  DragAlongShelfReorder(0, -1);
451}
452
453INSTANTIATE_TEST_CASE_P(LtrRtl, PanelWindowResizerTextDirectionTest,
454                        testing::Bool());
455
456}  // namespace internal
457}  // namespace ash
458