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