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 <algorithm>
6
7#include "ash/accessibility_delegate.h"
8#include "ash/drag_drop/drag_drop_controller.h"
9#include "ash/root_window_controller.h"
10#include "ash/screen_util.h"
11#include "ash/shelf/shelf.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/shelf_test_api.h"
17#include "ash/test/shelf_view_test_api.h"
18#include "ash/test/shell_test_api.h"
19#include "ash/test/test_shelf_delegate.h"
20#include "ash/wm/mru_window_tracker.h"
21#include "ash/wm/overview/window_grid.h"
22#include "ash/wm/overview/window_selector.h"
23#include "ash/wm/overview/window_selector_controller.h"
24#include "ash/wm/overview/window_selector_item.h"
25#include "ash/wm/panels/panel_layout_manager.h"
26#include "ash/wm/window_state.h"
27#include "ash/wm/window_util.h"
28#include "ash/wm/wm_event.h"
29#include "base/basictypes.h"
30#include "base/compiler_specific.h"
31#include "base/memory/scoped_vector.h"
32#include "base/run_loop.h"
33#include "base/strings/utf_string_conversions.h"
34#include "ui/aura/client/aura_constants.h"
35#include "ui/aura/client/cursor_client.h"
36#include "ui/aura/client/focus_client.h"
37#include "ui/aura/test/event_generator.h"
38#include "ui/aura/test/test_window_delegate.h"
39#include "ui/aura/test/test_windows.h"
40#include "ui/aura/window.h"
41#include "ui/aura/window_event_dispatcher.h"
42#include "ui/compositor/scoped_animation_duration_scale_mode.h"
43#include "ui/gfx/rect_conversions.h"
44#include "ui/gfx/transform.h"
45#include "ui/views/controls/label.h"
46#include "ui/views/widget/native_widget_aura.h"
47#include "ui/views/widget/widget_delegate.h"
48#include "ui/wm/core/window_util.h"
49#include "ui/wm/public/activation_delegate.h"
50
51namespace ash {
52namespace {
53
54class NonActivatableActivationDelegate
55    : public aura::client::ActivationDelegate {
56 public:
57  virtual bool ShouldActivate() const OVERRIDE {
58    return false;
59  }
60};
61
62void CancelDrag(DragDropController* controller, bool* canceled) {
63  if (controller->IsDragDropInProgress()) {
64    *canceled = true;
65    controller->DragCancel();
66  }
67}
68
69}  // namespace
70
71class WindowSelectorTest : public test::AshTestBase {
72 public:
73  WindowSelectorTest() {}
74  virtual ~WindowSelectorTest() {}
75
76  virtual void SetUp() OVERRIDE {
77    test::AshTestBase::SetUp();
78    ASSERT_TRUE(test::TestShelfDelegate::instance());
79
80    shelf_view_test_.reset(new test::ShelfViewTestAPI(
81        test::ShelfTestAPI(Shelf::ForPrimaryDisplay()).shelf_view()));
82    shelf_view_test_->SetAnimationDuration(1);
83  }
84
85  aura::Window* CreateWindow(const gfx::Rect& bounds) {
86    return CreateTestWindowInShellWithDelegate(&delegate_, -1, bounds);
87  }
88
89  aura::Window* CreateWindowWithId(const gfx::Rect& bounds, int id) {
90    return CreateTestWindowInShellWithDelegate(&delegate_, id, bounds);
91  }
92  aura::Window* CreateNonActivatableWindow(const gfx::Rect& bounds) {
93    aura::Window* window = CreateWindow(bounds);
94    aura::client::SetActivationDelegate(window,
95                                        &non_activatable_activation_delegate_);
96    EXPECT_FALSE(ash::wm::CanActivateWindow(window));
97    return window;
98  }
99
100  aura::Window* CreatePanelWindow(const gfx::Rect& bounds) {
101    aura::Window* window = CreateTestWindowInShellWithDelegateAndType(
102        NULL, ui::wm::WINDOW_TYPE_PANEL, 0, bounds);
103    test::TestShelfDelegate::instance()->AddShelfItem(window);
104    shelf_view_test()->RunMessageLoopUntilAnimationsDone();
105    return window;
106  }
107
108  views::Widget* CreatePanelWindowWidget(const gfx::Rect& bounds) {
109    views::Widget* widget = new views::Widget;
110    views::Widget::InitParams params;
111    params.bounds = bounds;
112    params.type = views::Widget::InitParams::TYPE_PANEL;
113    params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
114    widget->Init(params);
115    widget->Show();
116    ParentWindowInPrimaryRootWindow(widget->GetNativeWindow());
117    return widget;
118  }
119
120  bool WindowsOverlapping(aura::Window* window1, aura::Window* window2) {
121    gfx::RectF window1_bounds = GetTransformedTargetBounds(window1);
122    gfx::RectF window2_bounds = GetTransformedTargetBounds(window2);
123    return window1_bounds.Intersects(window2_bounds);
124  }
125
126  void ToggleOverview() {
127    ash::Shell::GetInstance()->window_selector_controller()->ToggleOverview();
128  }
129
130  gfx::Transform GetTransformRelativeTo(gfx::PointF origin,
131                                        const gfx::Transform& transform) {
132    gfx::Transform t;
133    t.Translate(origin.x(), origin.y());
134    t.PreconcatTransform(transform);
135    t.Translate(-origin.x(), -origin.y());
136    return t;
137  }
138
139  gfx::RectF GetTransformedBounds(aura::Window* window) {
140    gfx::RectF bounds(ScreenUtil::ConvertRectToScreen(
141        window->parent(), window->layer()->bounds()));
142    gfx::Transform transform(GetTransformRelativeTo(bounds.origin(),
143        window->layer()->transform()));
144    transform.TransformRect(&bounds);
145    return bounds;
146  }
147
148  gfx::RectF GetTransformedTargetBounds(aura::Window* window) {
149    gfx::RectF bounds(ScreenUtil::ConvertRectToScreen(
150        window->parent(), window->layer()->GetTargetBounds()));
151    gfx::Transform transform(GetTransformRelativeTo(bounds.origin(),
152        window->layer()->GetTargetTransform()));
153    transform.TransformRect(&bounds);
154    return bounds;
155  }
156
157  gfx::RectF GetTransformedBoundsInRootWindow(aura::Window* window) {
158    gfx::RectF bounds = gfx::Rect(window->bounds().size());
159    aura::Window* root = window->GetRootWindow();
160    CHECK(window->layer());
161    CHECK(root->layer());
162    gfx::Transform transform;
163    if (!window->layer()->GetTargetTransformRelativeTo(root->layer(),
164                                                       &transform)) {
165      return gfx::RectF();
166    }
167    transform.TransformRect(&bounds);
168    return bounds;
169  }
170
171  void ClickWindow(aura::Window* window) {
172    aura::test::EventGenerator event_generator(window->GetRootWindow(), window);
173    gfx::RectF target = GetTransformedBounds(window);
174    event_generator.ClickLeftButton();
175  }
176
177  void SendKey(ui::KeyboardCode key) {
178      aura::test::EventGenerator event_generator(Shell::GetPrimaryRootWindow());
179      event_generator.PressKey(key, 0);
180      event_generator.ReleaseKey(key, 0);
181  }
182
183  bool IsSelecting() {
184    return ash::Shell::GetInstance()->window_selector_controller()->
185        IsSelecting();
186  }
187
188  aura::Window* GetFocusedWindow() {
189    return aura::client::GetFocusClient(
190        Shell::GetPrimaryRootWindow())->GetFocusedWindow();
191    }
192
193  const std::vector<WindowSelectorItem*>& GetWindowItemsForRoot(int index) {
194    return ash::Shell::GetInstance()->window_selector_controller()->
195        window_selector_->grid_list_[index]->window_list_.get();
196    }
197
198  const aura::Window* GetSelectedWindow() {
199    WindowSelector* ws = ash::Shell::GetInstance()->
200        window_selector_controller()->window_selector_.get();
201    return ws->grid_list_[ws->selected_grid_index_]->
202        SelectedWindow()->SelectionWindow();
203  }
204
205  views::Widget* GetCloseButton(ash::WindowSelectorItem* window) {
206    return window->close_button_.get();
207  }
208
209  views::Widget* GetLabelWidget(ash::WindowSelectorItem* window) {
210    return window->window_label_.get();
211  }
212
213  // Tests that a window is contained within a given WindowSelectorItem, and
214  // that both the window and its matching close button are within the same
215  // screen.
216  void IsWindowAndCloseButtonInScreen(aura::Window* window,
217                                      WindowSelectorItem* window_item) {
218    aura::Window* root_window = window_item->GetRootWindow();
219    EXPECT_TRUE(window_item->Contains(window));
220    EXPECT_TRUE(root_window->GetBoundsInScreen().Contains(
221        ToEnclosingRect(GetTransformedTargetBounds(window))));
222    EXPECT_TRUE(root_window->GetBoundsInScreen().Contains(
223        ToEnclosingRect(GetTransformedTargetBounds(
224            GetCloseButton(window_item)->GetNativeView()))));
225  }
226
227  test::ShelfViewTestAPI* shelf_view_test() {
228    return shelf_view_test_.get();
229  }
230
231 private:
232  aura::test::TestWindowDelegate delegate_;
233  NonActivatableActivationDelegate non_activatable_activation_delegate_;
234  scoped_ptr<test::ShelfViewTestAPI> shelf_view_test_;
235
236  DISALLOW_COPY_AND_ASSIGN(WindowSelectorTest);
237};
238
239// Tests that an a11y alert is sent on entering overview mode.
240TEST_F(WindowSelectorTest, A11yAlertOnOverviewMode) {
241  gfx::Rect bounds(0, 0, 400, 400);
242  AccessibilityDelegate* delegate =
243      ash::Shell::GetInstance()->accessibility_delegate();
244  scoped_ptr<aura::Window> window1(CreateWindow(bounds));
245  EXPECT_NE(delegate->GetLastAccessibilityAlert(),
246            A11Y_ALERT_WINDOW_OVERVIEW_MODE_ENTERED);
247  ToggleOverview();
248  EXPECT_EQ(delegate->GetLastAccessibilityAlert(),
249            A11Y_ALERT_WINDOW_OVERVIEW_MODE_ENTERED);
250}
251
252// Tests entering overview mode with two windows and selecting one by clicking.
253TEST_F(WindowSelectorTest, Basic) {
254  gfx::Rect bounds(0, 0, 400, 400);
255  aura::Window* root_window = Shell::GetPrimaryRootWindow();
256  scoped_ptr<aura::Window> window1(CreateWindow(bounds));
257  scoped_ptr<aura::Window> window2(CreateWindow(bounds));
258  scoped_ptr<aura::Window> panel1(CreatePanelWindow(bounds));
259  scoped_ptr<aura::Window> panel2(CreatePanelWindow(bounds));
260  EXPECT_TRUE(WindowsOverlapping(window1.get(), window2.get()));
261  EXPECT_TRUE(WindowsOverlapping(panel1.get(), panel2.get()));
262  wm::ActivateWindow(window2.get());
263  EXPECT_FALSE(wm::IsActiveWindow(window1.get()));
264  EXPECT_TRUE(wm::IsActiveWindow(window2.get()));
265  EXPECT_EQ(window2.get(), GetFocusedWindow());
266  // Hide the cursor before entering overview to test that it will be shown.
267  aura::client::GetCursorClient(root_window)->HideCursor();
268
269  // In overview mode the windows should no longer overlap and focus should
270  // be removed from the window.
271  ToggleOverview();
272  EXPECT_EQ(NULL, GetFocusedWindow());
273  EXPECT_FALSE(WindowsOverlapping(window1.get(), window2.get()));
274  EXPECT_FALSE(WindowsOverlapping(window1.get(), panel1.get()));
275  // Panels 1 and 2 should still be overlapping being in a single selector
276  // item.
277  EXPECT_TRUE(WindowsOverlapping(panel1.get(), panel2.get()));
278
279  // Clicking window 1 should activate it.
280  ClickWindow(window1.get());
281  EXPECT_TRUE(wm::IsActiveWindow(window1.get()));
282  EXPECT_FALSE(wm::IsActiveWindow(window2.get()));
283  EXPECT_EQ(window1.get(), GetFocusedWindow());
284
285  // Cursor should have been unlocked.
286  EXPECT_FALSE(aura::client::GetCursorClient(root_window)->IsCursorLocked());
287}
288
289// Tests selecting a window by tapping on it.
290TEST_F(WindowSelectorTest, BasicGesture) {
291  gfx::Rect bounds(0, 0, 400, 400);
292  scoped_ptr<aura::Window> window1(CreateWindow(bounds));
293  scoped_ptr<aura::Window> window2(CreateWindow(bounds));
294  wm::ActivateWindow(window1.get());
295  EXPECT_EQ(window1.get(), GetFocusedWindow());
296  ToggleOverview();
297  EXPECT_EQ(NULL, GetFocusedWindow());
298  aura::test::EventGenerator generator(Shell::GetPrimaryRootWindow(),
299                                       window2.get());
300  generator.GestureTapAt(gfx::ToEnclosingRect(
301      GetTransformedTargetBounds(window2.get())).CenterPoint());
302  EXPECT_EQ(window2.get(), GetFocusedWindow());
303}
304
305// Tests that a window does not receive located events when in overview mode.
306TEST_F(WindowSelectorTest, WindowDoesNotReceiveEvents) {
307  gfx::Rect window_bounds(20, 10, 200, 300);
308  aura::Window* root_window = Shell::GetPrimaryRootWindow();
309  scoped_ptr<aura::Window> window(CreateWindow(window_bounds));
310
311  gfx::Point point1(window_bounds.x() + 10, window_bounds.y() + 10);
312
313  ui::MouseEvent event1(ui::ET_MOUSE_PRESSED, point1, point1,
314                        ui::EF_NONE, ui::EF_NONE);
315
316  ui::EventTarget* root_target = root_window;
317  ui::EventTargeter* targeter = root_target->GetEventTargeter();
318
319  // The event should target the window because we are still not in overview
320  // mode.
321  EXPECT_EQ(window, static_cast<aura::Window*>(
322      targeter->FindTargetForEvent(root_target, &event1)));
323
324  ToggleOverview();
325
326  // The bounds have changed, take that into account.
327  gfx::RectF bounds = GetTransformedBoundsInRootWindow(window.get());
328  gfx::Point point2(bounds.x() + 10, bounds.y() + 10);
329  ui::MouseEvent event2(ui::ET_MOUSE_PRESSED, point2, point2,
330                        ui::EF_NONE, ui::EF_NONE);
331
332  // Now the transparent window should be intercepting this event.
333  EXPECT_NE(window, static_cast<aura::Window*>(
334        targeter->FindTargetForEvent(root_target, &event2)));
335}
336
337// Tests that clicking on the close button effectively closes the window.
338TEST_F(WindowSelectorTest, CloseButton) {
339  scoped_ptr<aura::Window> window1(CreateWindow(gfx::Rect(200, 300, 250, 450)));
340
341  // We need a widget for the close button the work, a bare window will crash.
342  scoped_ptr<views::Widget> widget(new views::Widget);
343  views::Widget::InitParams params;
344  params.bounds = gfx::Rect(0, 0, 400, 400);
345  params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
346  params.parent = window1->parent();
347  widget->Init(params);
348  widget->Show();
349  ToggleOverview();
350
351  aura::Window* window2 = widget->GetNativeWindow();
352  gfx::RectF bounds = GetTransformedBoundsInRootWindow(window2);
353  gfx::Point point(bounds.top_right().x() - 1, bounds.top_right().y() - 1);
354  aura::test::EventGenerator event_generator(window2->GetRootWindow(), point);
355
356  EXPECT_FALSE(widget->IsClosed());
357  event_generator.ClickLeftButton();
358  EXPECT_TRUE(widget->IsClosed());
359}
360
361// Tests entering overview mode with two windows and selecting one.
362TEST_F(WindowSelectorTest, FullscreenWindow) {
363  gfx::Rect bounds(0, 0, 400, 400);
364  scoped_ptr<aura::Window> window1(CreateWindow(bounds));
365  scoped_ptr<aura::Window> window2(CreateWindow(bounds));
366  scoped_ptr<aura::Window> panel1(CreatePanelWindow(bounds));
367  wm::ActivateWindow(window1.get());
368
369  const wm::WMEvent toggle_fullscreen_event(wm::WM_EVENT_TOGGLE_FULLSCREEN);
370  wm::GetWindowState(window1.get())->OnWMEvent(&toggle_fullscreen_event);
371  // The panel is hidden in fullscreen mode.
372  EXPECT_FALSE(panel1->IsVisible());
373  EXPECT_TRUE(wm::GetWindowState(window1.get())->IsFullscreen());
374
375  // Enter overview and select the fullscreen window.
376  ToggleOverview();
377
378  // The panel becomes temporarily visible for the overview.
379  EXPECT_TRUE(panel1->IsVisible());
380  ClickWindow(window1.get());
381
382  // The window is still fullscreen as it was selected. The panel should again
383  // be hidden.
384  EXPECT_TRUE(wm::GetWindowState(window1.get())->IsFullscreen());
385  EXPECT_FALSE(panel1->IsVisible());
386
387  // Entering overview and selecting another window, the previous window remains
388  // fullscreen.
389  // TODO(flackr): Currently the panel remains hidden, but should become visible
390  // again.
391  ToggleOverview();
392  ClickWindow(window2.get());
393  EXPECT_TRUE(wm::GetWindowState(window1.get())->IsFullscreen());
394}
395
396// Tests that the shelf dimming state is removed while in overview and restored
397// on exiting overview.
398TEST_F(WindowSelectorTest, OverviewUndimsShelf) {
399  gfx::Rect bounds(0, 0, 400, 400);
400  scoped_ptr<aura::Window> window1(CreateWindow(bounds));
401  wm::WindowState* window_state = wm::GetWindowState(window1.get());
402  window_state->Maximize();
403  ash::ShelfWidget* shelf = Shell::GetPrimaryRootWindowController()->shelf();
404  EXPECT_TRUE(shelf->GetDimsShelf());
405  ToggleOverview();
406  EXPECT_FALSE(shelf->GetDimsShelf());
407  ToggleOverview();
408  EXPECT_TRUE(shelf->GetDimsShelf());
409}
410
411// Tests that beginning window selection hides the app list.
412TEST_F(WindowSelectorTest, SelectingHidesAppList) {
413  gfx::Rect bounds(0, 0, 400, 400);
414  scoped_ptr<aura::Window> window1(CreateWindow(bounds));
415  scoped_ptr<aura::Window> window2(CreateWindow(bounds));
416  Shell::GetInstance()->ToggleAppList(NULL);
417  EXPECT_TRUE(Shell::GetInstance()->GetAppListTargetVisibility());
418  ToggleOverview();
419  EXPECT_FALSE(Shell::GetInstance()->GetAppListTargetVisibility());
420  ToggleOverview();
421}
422
423// Tests that a minimized window's visibility and layer visibility is correctly
424// changed when entering overview and restored when leaving overview mode.
425// Crashes after the skia roll in http://crrev.com/274114.
426// http://crbug.com/379570
427TEST_F(WindowSelectorTest, DISABLED_MinimizedWindowVisibility) {
428  gfx::Rect bounds(0, 0, 400, 400);
429  scoped_ptr<aura::Window> window1(CreateWindow(bounds));
430  wm::WindowState* window_state = wm::GetWindowState(window1.get());
431  window_state->Minimize();
432  EXPECT_FALSE(window1->IsVisible());
433  EXPECT_FALSE(window1->layer()->GetTargetVisibility());
434  {
435    ui::ScopedAnimationDurationScaleMode normal_duration_mode(
436        ui::ScopedAnimationDurationScaleMode::NORMAL_DURATION);
437    ToggleOverview();
438    EXPECT_TRUE(window1->IsVisible());
439    EXPECT_TRUE(window1->layer()->GetTargetVisibility());
440  }
441  {
442    ui::ScopedAnimationDurationScaleMode normal_duration_mode(
443        ui::ScopedAnimationDurationScaleMode::NORMAL_DURATION);
444    ToggleOverview();
445    EXPECT_FALSE(window1->IsVisible());
446    EXPECT_FALSE(window1->layer()->GetTargetVisibility());
447  }
448}
449
450// Tests that a bounds change during overview is corrected for.
451TEST_F(WindowSelectorTest, BoundsChangeDuringOverview) {
452  scoped_ptr<aura::Window> window(CreateWindow(gfx::Rect(0, 0, 400, 400)));
453  ToggleOverview();
454  gfx::Rect overview_bounds =
455      ToEnclosingRect(GetTransformedTargetBounds(window.get()));
456  window->SetBounds(gfx::Rect(200, 0, 200, 200));
457  gfx::Rect new_overview_bounds =
458      ToEnclosingRect(GetTransformedTargetBounds(window.get()));
459  EXPECT_EQ(overview_bounds.x(), new_overview_bounds.x());
460  EXPECT_EQ(overview_bounds.y(), new_overview_bounds.y());
461  EXPECT_EQ(overview_bounds.width(), new_overview_bounds.width());
462  EXPECT_EQ(overview_bounds.height(), new_overview_bounds.height());
463  ToggleOverview();
464}
465
466// Tests that a newly created window aborts overview.
467TEST_F(WindowSelectorTest, NewWindowCancelsOveriew) {
468  gfx::Rect bounds(0, 0, 400, 400);
469  scoped_ptr<aura::Window> window1(CreateWindow(bounds));
470  scoped_ptr<aura::Window> window2(CreateWindow(bounds));
471  ToggleOverview();
472  EXPECT_TRUE(IsSelecting());
473
474  // A window being created should exit overview mode.
475  scoped_ptr<aura::Window> window3(CreateWindow(bounds));
476  EXPECT_FALSE(IsSelecting());
477}
478
479// Tests that a window activation exits overview mode.
480TEST_F(WindowSelectorTest, ActivationCancelsOveriew) {
481  gfx::Rect bounds(0, 0, 400, 400);
482  scoped_ptr<aura::Window> window1(CreateWindow(bounds));
483  scoped_ptr<aura::Window> window2(CreateWindow(bounds));
484  window2->Focus();
485  ToggleOverview();
486  EXPECT_TRUE(IsSelecting());
487
488  // A window being activated should exit overview mode.
489  window1->Focus();
490  EXPECT_FALSE(IsSelecting());
491
492  // window1 should be focused after exiting even though window2 was focused on
493  // entering overview because we exited due to an activation.
494  EXPECT_EQ(window1.get(), GetFocusedWindow());
495}
496
497// Tests that exiting overview mode without selecting a window restores focus
498// to the previously focused window.
499TEST_F(WindowSelectorTest, CancelRestoresFocus) {
500  gfx::Rect bounds(0, 0, 400, 400);
501  scoped_ptr<aura::Window> window(CreateWindow(bounds));
502  wm::ActivateWindow(window.get());
503  EXPECT_EQ(window.get(), GetFocusedWindow());
504
505  // In overview mode, focus should be removed.
506  ToggleOverview();
507  EXPECT_EQ(NULL, GetFocusedWindow());
508
509  // If canceling overview mode, focus should be restored.
510  ToggleOverview();
511  EXPECT_EQ(window.get(), GetFocusedWindow());
512}
513
514// Tests that overview mode is exited if the last remaining window is destroyed.
515TEST_F(WindowSelectorTest, LastWindowDestroyed) {
516  gfx::Rect bounds(0, 0, 400, 400);
517  scoped_ptr<aura::Window> window1(CreateWindow(bounds));
518  scoped_ptr<aura::Window> window2(CreateWindow(bounds));
519  ToggleOverview();
520
521  window1.reset();
522  window2.reset();
523  EXPECT_FALSE(IsSelecting());
524}
525
526// Tests that entering overview mode restores a window to its original
527// target location.
528TEST_F(WindowSelectorTest, QuickReentryRestoresInitialTransform) {
529  gfx::Rect bounds(0, 0, 400, 400);
530  scoped_ptr<aura::Window> window(CreateWindow(bounds));
531  gfx::Rect initial_bounds = ToEnclosingRect(
532      GetTransformedBounds(window.get()));
533  ToggleOverview();
534  // Quickly exit and reenter overview mode. The window should still be
535  // animating when we reenter. We cannot short circuit animations for this but
536  // we also don't have to wait for them to complete.
537  {
538    ui::ScopedAnimationDurationScaleMode normal_duration_mode(
539        ui::ScopedAnimationDurationScaleMode::NORMAL_DURATION);
540    ToggleOverview();
541    ToggleOverview();
542  }
543  EXPECT_NE(initial_bounds, ToEnclosingRect(
544      GetTransformedTargetBounds(window.get())));
545  ToggleOverview();
546  EXPECT_FALSE(IsSelecting());
547  EXPECT_EQ(initial_bounds, ToEnclosingRect(
548      GetTransformedTargetBounds(window.get())));
549}
550
551// Tests that non-activatable windows are hidden when entering overview mode.
552TEST_F(WindowSelectorTest, NonActivatableWindowsHidden) {
553  gfx::Rect bounds(0, 0, 400, 400);
554  scoped_ptr<aura::Window> window1(CreateWindow(bounds));
555  scoped_ptr<aura::Window> window2(CreateWindow(bounds));
556  scoped_ptr<aura::Window> non_activatable_window(
557      CreateNonActivatableWindow(Shell::GetPrimaryRootWindow()->bounds()));
558  EXPECT_TRUE(non_activatable_window->IsVisible());
559  ToggleOverview();
560  EXPECT_FALSE(non_activatable_window->IsVisible());
561  ToggleOverview();
562  EXPECT_TRUE(non_activatable_window->IsVisible());
563
564  // Test that a window behind the fullscreen non-activatable window can be
565  // clicked.
566  non_activatable_window->parent()->StackChildAtTop(
567      non_activatable_window.get());
568  ToggleOverview();
569  ClickWindow(window1.get());
570  EXPECT_FALSE(IsSelecting());
571  EXPECT_TRUE(wm::IsActiveWindow(window1.get()));
572}
573
574// Tests that windows with modal child windows are transformed with the modal
575// child even though not activatable themselves.
576TEST_F(WindowSelectorTest, ModalChild) {
577  gfx::Rect bounds(0, 0, 400, 400);
578  scoped_ptr<aura::Window> window1(CreateWindow(bounds));
579  scoped_ptr<aura::Window> child1(CreateWindow(bounds));
580  child1->SetProperty(aura::client::kModalKey, ui::MODAL_TYPE_WINDOW);
581  ::wm::AddTransientChild(window1.get(), child1.get());
582  EXPECT_EQ(window1->parent(), child1->parent());
583  ToggleOverview();
584  EXPECT_TRUE(window1->IsVisible());
585  EXPECT_TRUE(child1->IsVisible());
586  EXPECT_EQ(ToEnclosingRect(GetTransformedTargetBounds(child1.get())),
587      ToEnclosingRect(GetTransformedTargetBounds(window1.get())));
588  ToggleOverview();
589}
590
591// Tests that clicking a modal window's parent activates the modal window in
592// overview.
593TEST_F(WindowSelectorTest, ClickModalWindowParent) {
594  scoped_ptr<aura::Window> window1(CreateWindow(gfx::Rect(0, 0, 180, 180)));
595  scoped_ptr<aura::Window> child1(CreateWindow(gfx::Rect(200, 0, 180, 180)));
596  child1->SetProperty(aura::client::kModalKey, ui::MODAL_TYPE_WINDOW);
597  ::wm::AddTransientChild(window1.get(), child1.get());
598  EXPECT_FALSE(WindowsOverlapping(window1.get(), child1.get()));
599  EXPECT_EQ(window1->parent(), child1->parent());
600  ToggleOverview();
601  // Given that their relative positions are preserved, the windows should still
602  // not overlap.
603  EXPECT_FALSE(WindowsOverlapping(window1.get(), child1.get()));
604  ClickWindow(window1.get());
605  EXPECT_FALSE(IsSelecting());
606
607  // Clicking on window1 should activate child1.
608  EXPECT_TRUE(wm::IsActiveWindow(child1.get()));
609}
610
611// Tests that windows remain on the display they are currently on in overview
612// mode, and that the close buttons are on matching displays.
613TEST_F(WindowSelectorTest, MultipleDisplays) {
614  if (!SupportsMultipleDisplays())
615    return;
616
617  UpdateDisplay("600x400,600x400");
618  aura::Window::Windows root_windows = Shell::GetAllRootWindows();
619  gfx::Rect bounds1(0, 0, 400, 400);
620  gfx::Rect bounds2(650, 0, 400, 400);
621
622  scoped_ptr<aura::Window> window1(CreateWindow(bounds1));
623  scoped_ptr<aura::Window> window2(CreateWindow(bounds1));
624  scoped_ptr<aura::Window> window3(CreateWindow(bounds2));
625  scoped_ptr<aura::Window> window4(CreateWindow(bounds2));
626  scoped_ptr<aura::Window> panel1(CreatePanelWindow(bounds1));
627  scoped_ptr<aura::Window> panel2(CreatePanelWindow(bounds1));
628  scoped_ptr<aura::Window> panel3(CreatePanelWindow(bounds2));
629  scoped_ptr<aura::Window> panel4(CreatePanelWindow(bounds2));
630  EXPECT_EQ(root_windows[0], window1->GetRootWindow());
631  EXPECT_EQ(root_windows[0], window2->GetRootWindow());
632  EXPECT_EQ(root_windows[1], window3->GetRootWindow());
633  EXPECT_EQ(root_windows[1], window4->GetRootWindow());
634
635  EXPECT_EQ(root_windows[0], panel1->GetRootWindow());
636  EXPECT_EQ(root_windows[0], panel2->GetRootWindow());
637  EXPECT_EQ(root_windows[1], panel3->GetRootWindow());
638  EXPECT_EQ(root_windows[1], panel4->GetRootWindow());
639
640  // In overview mode, each window remains in the same root window.
641  ToggleOverview();
642  EXPECT_EQ(root_windows[0], window1->GetRootWindow());
643  EXPECT_EQ(root_windows[0], window2->GetRootWindow());
644  EXPECT_EQ(root_windows[1], window3->GetRootWindow());
645  EXPECT_EQ(root_windows[1], window4->GetRootWindow());
646  EXPECT_EQ(root_windows[0], panel1->GetRootWindow());
647  EXPECT_EQ(root_windows[0], panel2->GetRootWindow());
648  EXPECT_EQ(root_windows[1], panel3->GetRootWindow());
649  EXPECT_EQ(root_windows[1], panel4->GetRootWindow());
650
651  const std::vector<WindowSelectorItem*>& primary_window_items =
652      GetWindowItemsForRoot(0);
653  const std::vector<WindowSelectorItem*>& secondary_window_items =
654      GetWindowItemsForRoot(1);
655
656  // Window indices are based on top-down order. The reverse of our creation.
657  IsWindowAndCloseButtonInScreen(window1.get(), primary_window_items[2]);
658  IsWindowAndCloseButtonInScreen(window2.get(), primary_window_items[1]);
659  IsWindowAndCloseButtonInScreen(window3.get(), secondary_window_items[2]);
660  IsWindowAndCloseButtonInScreen(window4.get(), secondary_window_items[1]);
661
662  IsWindowAndCloseButtonInScreen(panel1.get(), primary_window_items[0]);
663  IsWindowAndCloseButtonInScreen(panel2.get(), primary_window_items[0]);
664  IsWindowAndCloseButtonInScreen(panel3.get(), secondary_window_items[0]);
665  IsWindowAndCloseButtonInScreen(panel4.get(), secondary_window_items[0]);
666
667  EXPECT_TRUE(WindowsOverlapping(panel1.get(), panel2.get()));
668  EXPECT_TRUE(WindowsOverlapping(panel3.get(), panel4.get()));
669  EXPECT_FALSE(WindowsOverlapping(panel1.get(), panel3.get()));
670}
671
672// Tests shutting down during overview.
673TEST_F(WindowSelectorTest, Shutdown) {
674  gfx::Rect bounds(0, 0, 400, 400);
675  // These windows will be deleted when the test exits and the Shell instance
676  // is shut down.
677  aura::Window* window1(CreateWindow(bounds));
678  aura::Window* window2(CreateWindow(bounds));
679  aura::Window* window3(CreatePanelWindow(bounds));
680  aura::Window* window4(CreatePanelWindow(bounds));
681
682  wm::ActivateWindow(window4);
683  wm::ActivateWindow(window3);
684  wm::ActivateWindow(window2);
685  wm::ActivateWindow(window1);
686
687  ToggleOverview();
688}
689
690// Tests removing a display during overview.
691TEST_F(WindowSelectorTest, RemoveDisplay) {
692  if (!SupportsMultipleDisplays())
693    return;
694
695  UpdateDisplay("400x400,400x400");
696  gfx::Rect bounds1(0, 0, 100, 100);
697  gfx::Rect bounds2(450, 0, 100, 100);
698  scoped_ptr<aura::Window> window1(CreateWindow(bounds1));
699  scoped_ptr<aura::Window> window2(CreateWindow(bounds2));
700  scoped_ptr<aura::Window> window3(CreatePanelWindow(bounds1));
701  scoped_ptr<aura::Window> window4(CreatePanelWindow(bounds2));
702
703  aura::Window::Windows root_windows = Shell::GetAllRootWindows();
704  EXPECT_EQ(root_windows[0], window1->GetRootWindow());
705  EXPECT_EQ(root_windows[1], window2->GetRootWindow());
706  EXPECT_EQ(root_windows[0], window3->GetRootWindow());
707  EXPECT_EQ(root_windows[1], window4->GetRootWindow());
708
709  wm::ActivateWindow(window4.get());
710  wm::ActivateWindow(window3.get());
711  wm::ActivateWindow(window2.get());
712  wm::ActivateWindow(window1.get());
713
714  ToggleOverview();
715  EXPECT_TRUE(IsSelecting());
716  UpdateDisplay("400x400");
717  EXPECT_FALSE(IsSelecting());
718}
719
720// Tests starting overview during a drag and drop tracking operation.
721// TODO(flackr): Fix memory corruption crash when running locally (not failing
722// on bots). See http://crbug.com/342528.
723TEST_F(WindowSelectorTest, DISABLED_DragDropInProgress) {
724  bool drag_canceled_by_test = false;
725  gfx::Rect bounds(0, 0, 400, 400);
726  scoped_ptr<aura::Window> window(CreateWindow(bounds));
727  test::ShellTestApi shell_test_api(Shell::GetInstance());
728  ash::DragDropController* drag_drop_controller =
729      shell_test_api.drag_drop_controller();
730  ui::OSExchangeData data;
731  base::MessageLoopForUI::current()->PostTask(FROM_HERE,
732      base::Bind(&WindowSelectorTest::ToggleOverview,
733                 base::Unretained(this)));
734  base::MessageLoopForUI::current()->PostTask(FROM_HERE,
735      base::Bind(&CancelDrag, drag_drop_controller, &drag_canceled_by_test));
736  data.SetString(base::UTF8ToUTF16("I am being dragged"));
737  drag_drop_controller->StartDragAndDrop(data, window->GetRootWindow(),
738      window.get(), gfx::Point(5, 5), ui::DragDropTypes::DRAG_MOVE,
739      ui::DragDropTypes::DRAG_EVENT_SOURCE_MOUSE);
740  RunAllPendingInMessageLoop();
741  EXPECT_FALSE(drag_canceled_by_test);
742  ASSERT_TRUE(IsSelecting());
743  RunAllPendingInMessageLoop();
744}
745
746// Test that a label is created under the window on entering overview mode.
747TEST_F(WindowSelectorTest, CreateLabelUnderWindow) {
748  scoped_ptr<aura::Window> window(CreateWindow(gfx::Rect(0, 0, 100, 100)));
749  base::string16 window_title = base::UTF8ToUTF16("My window");
750  window->set_title(window_title);
751  ToggleOverview();
752  WindowSelectorItem* window_item = GetWindowItemsForRoot(0).back();
753  views::Widget* widget = GetLabelWidget(window_item);
754  // Has the label widget been created?
755  ASSERT_TRUE(widget);
756  views::Label* label = static_cast<views::Label*>(widget->GetContentsView());
757  // Verify the label matches the window title.
758  EXPECT_EQ(label->text(), window_title);
759  // Labels are located based on target_bounds, not the actual window item
760  // bounds.
761  gfx::Rect target_bounds(window_item->target_bounds());
762  gfx::Rect expected_label_bounds(target_bounds.x(),
763                                  target_bounds.bottom(),
764                                  target_bounds.width(),
765                                  label->GetPreferredSize().height());
766  gfx::Rect real_label_bounds = widget->GetNativeWindow()->bounds();
767  EXPECT_EQ(widget->GetNativeWindow()->bounds(), real_label_bounds);
768}
769
770// Tests that a label is created for the active panel in a group of panels in
771// overview mode.
772TEST_F(WindowSelectorTest, CreateLabelUnderPanel) {
773  scoped_ptr<aura::Window> panel1(CreatePanelWindow(gfx::Rect(0, 0, 100, 100)));
774  scoped_ptr<aura::Window> panel2(CreatePanelWindow(gfx::Rect(0, 0, 100, 100)));
775  base::string16 panel1_title = base::UTF8ToUTF16("My panel");
776  base::string16 panel2_title = base::UTF8ToUTF16("Another panel");
777  panel1->set_title(panel1_title);
778  panel2->set_title(panel2_title);
779  wm::ActivateWindow(panel1.get());
780  ToggleOverview();
781  WindowSelectorItem* window_item = GetWindowItemsForRoot(0).back();
782  views::Widget* widget = GetLabelWidget(window_item);
783  // Has the label widget been created?
784  ASSERT_TRUE(widget);
785  views::Label* label = static_cast<views::Label*>(widget->GetContentsView());
786  // Verify the label matches the active window title.
787  EXPECT_EQ(label->text(), panel1_title);
788}
789
790// Tests that overview updates the window positions if the display orientation
791// changes.
792TEST_F(WindowSelectorTest, DisplayOrientationChanged) {
793  if (!SupportsHostWindowResize())
794    return;
795
796  aura::Window* root_window = Shell::GetInstance()->GetPrimaryRootWindow();
797  UpdateDisplay("600x200");
798  EXPECT_EQ("0,0 600x200", root_window->bounds().ToString());
799  gfx::Rect window_bounds(0, 0, 150, 150);
800  ScopedVector<aura::Window> windows;
801  for (int i = 0; i < 3; i++) {
802    windows.push_back(CreateWindow(window_bounds));
803  }
804
805  ToggleOverview();
806  for (ScopedVector<aura::Window>::iterator iter = windows.begin();
807       iter != windows.end(); ++iter) {
808    EXPECT_TRUE(root_window->bounds().Contains(
809        ToEnclosingRect(GetTransformedTargetBounds(*iter))));
810  }
811
812  // Rotate the display, windows should be repositioned to be within the screen
813  // bounds.
814  UpdateDisplay("600x200/r");
815  EXPECT_EQ("0,0 200x600", root_window->bounds().ToString());
816  for (ScopedVector<aura::Window>::iterator iter = windows.begin();
817       iter != windows.end(); ++iter) {
818    EXPECT_TRUE(root_window->bounds().Contains(
819        ToEnclosingRect(GetTransformedTargetBounds(*iter))));
820  }
821}
822
823// Tests traversing some windows in overview mode with the arrow keys in every
824// possible direction.
825TEST_F(WindowSelectorTest, BasicArrowKeyNavigation) {
826  if (!SupportsHostWindowResize())
827    return;
828  const size_t test_windows = 7;
829  UpdateDisplay("400x300");
830  ScopedVector<aura::Window> windows;
831  for (size_t i = test_windows; i > 0; i--)
832    windows.push_back(CreateWindowWithId(gfx::Rect(0, 0, 100, 100), i));
833
834  ui::KeyboardCode arrow_keys[] = {
835      ui::VKEY_RIGHT,
836      ui::VKEY_DOWN,
837      ui::VKEY_LEFT,
838      ui::VKEY_UP
839  };
840  // Expected window layout:
841  // +-------+  +-------+  +-------+
842  // |   1   |  |   2   |  |   3   |
843  // +-------+  +-------+  +-------+
844  // +-------+  +-------+  +-------+
845  // |   4   |  |   5   |  |   6   |
846  // +-------+  +-------+  +-------+
847  // +-------+
848  // |   7   |
849  // +-------+
850  // Index for each window during a full loop plus wrapping around.
851  int index_path_for_direction[][test_windows + 1] = {
852      {1, 2, 3, 4, 5, 6, 7, 1},  // Right
853      {1, 4, 7, 2, 5, 3, 6, 1},  // Down
854      {7, 6, 5, 4, 3, 2, 1, 7},  // Left
855      {6, 3, 5, 2, 7, 4, 1, 6}   // Up
856  };
857
858  for (size_t key_index = 0; key_index < arraysize(arrow_keys); key_index++) {
859    ToggleOverview();
860    for (size_t i = 0; i < test_windows + 1; i++) {
861      SendKey(arrow_keys[key_index]);
862      // TODO(nsatragno): Add a more readable error message by constructing a
863      // string from the window IDs.
864      EXPECT_EQ(GetSelectedWindow()->id(),
865                index_path_for_direction[key_index][i]);
866    }
867    ToggleOverview();
868  }
869}
870
871// Tests basic selection across multiple monitors.
872TEST_F(WindowSelectorTest, BasicMultiMonitorArrowKeyNavigation) {
873  if (!SupportsMultipleDisplays())
874    return;
875
876  UpdateDisplay("400x400,400x400");
877  gfx::Rect bounds1(0, 0, 100, 100);
878  gfx::Rect bounds2(450, 0, 100, 100);
879  scoped_ptr<aura::Window> window4(CreateWindow(bounds2));
880  scoped_ptr<aura::Window> window3(CreateWindow(bounds2));
881  scoped_ptr<aura::Window> window2(CreateWindow(bounds1));
882  scoped_ptr<aura::Window> window1(CreateWindow(bounds1));
883
884
885  ToggleOverview();
886
887  SendKey(ui::VKEY_RIGHT);
888  EXPECT_EQ(GetSelectedWindow(), window1.get());
889  SendKey(ui::VKEY_RIGHT);
890  EXPECT_EQ(GetSelectedWindow(), window2.get());
891  SendKey(ui::VKEY_RIGHT);
892  EXPECT_EQ(GetSelectedWindow(), window3.get());
893  SendKey(ui::VKEY_RIGHT);
894  EXPECT_EQ(GetSelectedWindow(), window4.get());
895}
896
897// Tests selecting a window in overview mode with the return key.
898TEST_F(WindowSelectorTest, SelectWindowWithReturnKey) {
899  gfx::Rect bounds(0, 0, 100, 100);
900  scoped_ptr<aura::Window> window2(CreateWindow(bounds));
901  scoped_ptr<aura::Window> window1(CreateWindow(bounds));
902  ToggleOverview();
903
904  // Pressing the return key without a selection widget should not do anything.
905  SendKey(ui::VKEY_RETURN);
906  EXPECT_TRUE(IsSelecting());
907
908  // Select the first window.
909  SendKey(ui::VKEY_RIGHT);
910  SendKey(ui::VKEY_RETURN);
911  ASSERT_FALSE(IsSelecting());
912  EXPECT_TRUE(wm::IsActiveWindow(window1.get()));
913
914  // Select the second window.
915  ToggleOverview();
916  SendKey(ui::VKEY_RIGHT);
917  SendKey(ui::VKEY_RIGHT);
918  SendKey(ui::VKEY_RETURN);
919  EXPECT_FALSE(IsSelecting());
920  EXPECT_TRUE(wm::IsActiveWindow(window2.get()));
921}
922
923// Tests that overview mode hides the callout widget.
924TEST_F(WindowSelectorTest, WindowOverviewHidesCalloutWidgets) {
925  scoped_ptr<aura::Window> panel1(CreatePanelWindow(gfx::Rect(0, 0, 100, 100)));
926  scoped_ptr<aura::Window> panel2(CreatePanelWindow(gfx::Rect(0, 0, 100, 100)));
927  PanelLayoutManager* panel_manager =
928        static_cast<PanelLayoutManager*>(panel1->parent()->layout_manager());
929
930  // By default, panel callout widgets are visible.
931  EXPECT_TRUE(
932      panel_manager->GetCalloutWidgetForPanel(panel1.get())->IsVisible());
933  EXPECT_TRUE(
934      panel_manager->GetCalloutWidgetForPanel(panel2.get())->IsVisible());
935
936  // Toggling the overview should hide the callout widgets.
937  ToggleOverview();
938  EXPECT_FALSE(
939      panel_manager->GetCalloutWidgetForPanel(panel1.get())->IsVisible());
940  EXPECT_FALSE(
941      panel_manager->GetCalloutWidgetForPanel(panel2.get())->IsVisible());
942
943  // Ending the overview should show them again.
944  ToggleOverview();
945  EXPECT_TRUE(
946      panel_manager->GetCalloutWidgetForPanel(panel1.get())->IsVisible());
947  EXPECT_TRUE(
948      panel_manager->GetCalloutWidgetForPanel(panel2.get())->IsVisible());
949}
950
951// Tests that when panels are grouped that the close button only closes the
952// currently active panel. After the removal window selection should still be
953// active, and the label should have changed. Removing the last panel should
954// cause selection to end.
955TEST_F(WindowSelectorTest, CloseButtonOnPanels) {
956  scoped_ptr<views::Widget> widget1(CreatePanelWindowWidget(
957      gfx::Rect(0, 0, 300, 100)));
958  scoped_ptr<views::Widget> widget2(CreatePanelWindowWidget(
959      gfx::Rect(100, 0, 100, 100)));
960  aura::Window* window1 = widget1->GetNativeWindow();
961  aura::Window* window2 = widget2->GetNativeWindow();
962  base::string16 panel1_title = base::UTF8ToUTF16("Panel 1");
963  base::string16 panel2_title = base::UTF8ToUTF16("Panel 2");
964  window1->set_title(panel1_title);
965  window2->set_title(panel2_title);
966  wm::ActivateWindow(window1);
967  ToggleOverview();
968
969  gfx::RectF bounds1 = GetTransformedBoundsInRootWindow(window1);
970  gfx::Point point1(bounds1.top_right().x() - 1, bounds1.top_right().y() - 1);
971  aura::test::EventGenerator event_generator1(window1->GetRootWindow(), point1);
972
973  EXPECT_FALSE(widget1->IsClosed());
974  event_generator1.ClickLeftButton();
975  EXPECT_TRUE(widget1->IsClosed());
976  RunAllPendingInMessageLoop();
977  EXPECT_TRUE(IsSelecting());
978  WindowSelectorItem* window_item = GetWindowItemsForRoot(0).front();
979  EXPECT_FALSE(window_item->empty());
980  EXPECT_TRUE(window_item->Contains(window2));
981  EXPECT_TRUE(GetCloseButton(window_item)->IsVisible());
982
983  views::Widget* widget = GetLabelWidget(window_item);
984  views::Label* label = static_cast<views::Label*>(widget->GetContentsView());
985  EXPECT_EQ(label->text(), panel2_title);
986
987  gfx::RectF bounds2 = GetTransformedBoundsInRootWindow(window2);
988  gfx::Point point2(bounds2.top_right().x() - 1, bounds2.top_right().y() - 1);
989  aura::test::EventGenerator event_generator2(window2->GetRootWindow(), point2);
990
991  EXPECT_FALSE(widget2->IsClosed());
992  event_generator2.ClickLeftButton();
993  EXPECT_TRUE(widget2->IsClosed());
994  RunAllPendingInMessageLoop();
995  EXPECT_FALSE(IsSelecting());
996}
997
998}  // namespace ash
999