1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "ash/wm/system_gesture_event_filter.h"
7 #include "ash/accelerators/accelerator_controller.h"
8 #include "ash/ash_switches.h"
9 #include "ash/display/display_manager.h"
10 #include "ash/shelf/shelf.h"
11 #include "ash/shelf/shelf_model.h"
12 #include "ash/shell.h"
13 #include "ash/system/tray/system_tray_delegate.h"
14 #include "ash/test/ash_test_base.h"
15 #include "ash/test/display_manager_test_api.h"
16 #include "ash/test/shell_test_api.h"
17 #include "ash/test/test_shelf_delegate.h"
18 #include "ash/wm/gestures/long_press_affordance_handler.h"
19 #include "ash/wm/window_state.h"
20 #include "ash/wm/window_util.h"
21 #include "ash/wm/workspace/snap_sizer.h"
22 #include "base/command_line.h"
23 #include "base/time/time.h"
24 #include "base/timer/timer.h"
25 #include "ui/aura/env.h"
26 #include "ui/aura/root_window.h"
27 #include "ui/aura/test/event_generator.h"
28 #include "ui/aura/test/test_event_handler.h"
29 #include "ui/aura/test/test_window_delegate.h"
30 #include "ui/aura/test/test_windows.h"
31 #include "ui/base/hit_test.h"
32 #include "ui/base/ui_base_switches.h"
33 #include "ui/events/event.h"
34 #include "ui/events/event_handler.h"
35 #include "ui/events/event_utils.h"
36 #include "ui/events/gestures/gesture_configuration.h"
37 #include "ui/gfx/screen.h"
38 #include "ui/gfx/size.h"
39 #include "ui/views/widget/widget_delegate.h"
46 class ResizableWidgetDelegate : public views::WidgetDelegateView {
48 ResizableWidgetDelegate() {}
49 virtual ~ResizableWidgetDelegate() {}
52 virtual bool CanResize() const OVERRIDE { return true; }
53 virtual bool CanMaximize() const OVERRIDE { return true; }
54 virtual void DeleteDelegate() OVERRIDE { delete this; }
56 DISALLOW_COPY_AND_ASSIGN(ResizableWidgetDelegate);
59 // Support class for testing windows with a maximum size.
60 class MaxSizeNCFV : public views::NonClientFrameView {
64 virtual gfx::Size GetMaximumSize() OVERRIDE {
65 return gfx::Size(200, 200);
67 virtual gfx::Rect GetBoundsForClientView() const OVERRIDE {
71 virtual gfx::Rect GetWindowBoundsForClientBounds(
72 const gfx::Rect& client_bounds) const OVERRIDE {
76 // This function must ask the ClientView to do a hittest. We don't do this in
77 // the parent NonClientView because that makes it more difficult to calculate
78 // hittests for regions that are partially obscured by the ClientView, e.g.
80 virtual int NonClientHitTest(const gfx::Point& point) OVERRIDE {
83 virtual void GetWindowMask(const gfx::Size& size,
84 gfx::Path* window_mask) OVERRIDE {}
85 virtual void ResetWindowControls() OVERRIDE {}
86 virtual void UpdateWindowIcon() OVERRIDE {}
87 virtual void UpdateWindowTitle() OVERRIDE {}
89 DISALLOW_COPY_AND_ASSIGN(MaxSizeNCFV);
92 class MaxSizeWidgetDelegate : public views::WidgetDelegateView {
94 MaxSizeWidgetDelegate() {}
95 virtual ~MaxSizeWidgetDelegate() {}
98 virtual bool CanResize() const OVERRIDE { return true; }
99 virtual bool CanMaximize() const OVERRIDE { return false; }
100 virtual void DeleteDelegate() OVERRIDE { delete this; }
101 virtual views::NonClientFrameView* CreateNonClientFrameView(
102 views::Widget* widget) OVERRIDE {
103 return new MaxSizeNCFV;
106 DISALLOW_COPY_AND_ASSIGN(MaxSizeWidgetDelegate);
111 class SystemGestureEventFilterTest
112 : public AshTestBase,
113 public testing::WithParamInterface<bool> {
115 SystemGestureEventFilterTest() : AshTestBase(), docked_enabled_(GetParam()) {}
116 virtual ~SystemGestureEventFilterTest() {}
118 internal::LongPressAffordanceHandler* GetLongPressAffordance() {
119 ShellTestApi shell_test(Shell::GetInstance());
120 return shell_test.system_gesture_event_filter()->
121 long_press_affordance_.get();
124 base::OneShotTimer<internal::LongPressAffordanceHandler>*
125 GetLongPressAffordanceTimer() {
126 return &GetLongPressAffordance()->timer_;
129 aura::Window* GetLongPressAffordanceTarget() {
130 return GetLongPressAffordance()->tap_down_target_;
133 views::View* GetLongPressAffordanceView() {
134 return reinterpret_cast<views::View*>(
135 GetLongPressAffordance()->view_.get());
138 // Overridden from AshTestBase:
139 virtual void SetUp() OVERRIDE {
140 CommandLine::ForCurrentProcess()->AppendSwitch(
141 ash::switches::kAshEnableAdvancedGestures);
142 if (!docked_enabled_) {
143 CommandLine::ForCurrentProcess()->AppendSwitch(
144 ash::switches::kAshDisableDockedWindows);
146 test::AshTestBase::SetUp();
147 // Enable brightness key.
148 test::DisplayManagerTestApi(Shell::GetInstance()->display_manager()).
149 SetFirstDisplayAsInternalDisplay();
153 // true if docked windows are enabled with a flag.
154 bool docked_enabled_;
156 DISALLOW_COPY_AND_ASSIGN(SystemGestureEventFilterTest);
159 ui::GestureEvent* CreateGesture(ui::EventType type,
165 return new ui::GestureEvent(type, x, y, 0,
166 base::TimeDelta::FromMilliseconds(base::Time::Now().ToDoubleT() * 1000),
167 ui::GestureEventDetails(type, delta_x, delta_y), 1 << touch_id);
170 TEST_P(SystemGestureEventFilterTest, LongPressAffordanceStateOnCaptureLoss) {
171 aura::Window* root_window = Shell::GetPrimaryRootWindow();
173 aura::test::TestWindowDelegate delegate;
174 scoped_ptr<aura::Window> window0(
175 aura::test::CreateTestWindowWithDelegate(
176 &delegate, 9, gfx::Rect(0, 0, 100, 100), root_window));
177 scoped_ptr<aura::Window> window1(
178 aura::test::CreateTestWindowWithDelegate(
179 &delegate, 10, gfx::Rect(0, 0, 100, 50), window0.get()));
180 scoped_ptr<aura::Window> window2(
181 aura::test::CreateTestWindowWithDelegate(
182 &delegate, 11, gfx::Rect(0, 50, 100, 50), window0.get()));
184 const int kTouchId = 5;
186 // Capture first window.
187 window1->SetCapture();
188 EXPECT_TRUE(window1->HasCapture());
190 // Send touch event to first window.
191 ui::TouchEvent press(ui::ET_TOUCH_PRESSED,
194 ui::EventTimeForNow());
195 ui::EventDispatchDetails details =
196 root_window->GetDispatcher()->OnEventFromSource(&press);
197 ASSERT_FALSE(details.dispatcher_destroyed);
198 EXPECT_TRUE(window1->HasCapture());
200 base::OneShotTimer<internal::LongPressAffordanceHandler>* timer =
201 GetLongPressAffordanceTimer();
202 EXPECT_TRUE(timer->IsRunning());
203 EXPECT_EQ(window1, GetLongPressAffordanceTarget());
205 // Force timeout so that the affordance animation can start.
206 timer->user_task().Run();
208 EXPECT_TRUE(GetLongPressAffordance()->is_animating());
211 window2->SetCapture();
212 EXPECT_TRUE(window2->HasCapture());
214 EXPECT_TRUE(GetLongPressAffordance()->is_animating());
215 EXPECT_EQ(window1, GetLongPressAffordanceTarget());
217 // Animate to completion.
218 GetLongPressAffordance()->End(); // end grow animation.
219 // Force timeout to start shrink animation.
220 EXPECT_TRUE(timer->IsRunning());
221 timer->user_task().Run();
223 EXPECT_TRUE(GetLongPressAffordance()->is_animating());
224 GetLongPressAffordance()->End(); // end shrink animation.
226 // Check if state has reset.
227 EXPECT_EQ(NULL, GetLongPressAffordanceTarget());
228 EXPECT_EQ(NULL, GetLongPressAffordanceView());
231 TEST_P(SystemGestureEventFilterTest, MultiFingerSwipeGestures) {
232 aura::Window* root_window = Shell::GetPrimaryRootWindow();
233 views::Widget* toplevel = views::Widget::CreateWindowWithContextAndBounds(
234 new ResizableWidgetDelegate, root_window, gfx::Rect(0, 0, 600, 600));
237 const int kSteps = 15;
238 const int kTouchPoints = 4;
239 gfx::Point points[kTouchPoints] = {
240 gfx::Point(250, 250),
241 gfx::Point(250, 350),
242 gfx::Point(350, 250),
246 aura::test::EventGenerator generator(root_window,
247 toplevel->GetNativeWindow());
249 // Swipe down to minimize.
250 generator.GestureMultiFingerScroll(kTouchPoints, points, 15, kSteps, 0, 150);
252 wm::WindowState* toplevel_state =
253 wm::GetWindowState(toplevel->GetNativeWindow());
254 EXPECT_TRUE(toplevel_state->IsMinimized());
258 // Swipe up to maximize.
259 generator.GestureMultiFingerScroll(kTouchPoints, points, 15, kSteps, 0, -150);
260 EXPECT_TRUE(toplevel_state->IsMaximized());
264 // Swipe right to snap.
265 gfx::Rect normal_bounds = toplevel->GetWindowBoundsInScreen();
266 generator.GestureMultiFingerScroll(kTouchPoints, points, 15, kSteps, 150, 0);
267 gfx::Rect right_tile_bounds = toplevel->GetWindowBoundsInScreen();
268 EXPECT_NE(normal_bounds.ToString(), right_tile_bounds.ToString());
270 // Swipe left to snap.
271 gfx::Point left_points[kTouchPoints];
272 for (int i = 0; i < kTouchPoints; ++i) {
273 left_points[i] = points[i];
274 left_points[i].Offset(right_tile_bounds.x(), right_tile_bounds.y());
276 generator.GestureMultiFingerScroll(kTouchPoints, left_points, 15, kSteps,
278 gfx::Rect left_tile_bounds = toplevel->GetWindowBoundsInScreen();
279 EXPECT_NE(normal_bounds.ToString(), left_tile_bounds.ToString());
280 EXPECT_NE(right_tile_bounds.ToString(), left_tile_bounds.ToString());
282 // Swipe right again.
283 generator.GestureMultiFingerScroll(kTouchPoints, points, 15, kSteps, 150, 0);
284 gfx::Rect current_bounds = toplevel->GetWindowBoundsInScreen();
285 EXPECT_NE(current_bounds.ToString(), left_tile_bounds.ToString());
286 EXPECT_EQ(current_bounds.ToString(), right_tile_bounds.ToString());
289 TEST_P(SystemGestureEventFilterTest, TwoFingerDrag) {
290 gfx::Rect bounds(0, 0, 600, 600);
291 aura::Window* root_window = Shell::GetPrimaryRootWindow();
292 views::Widget* toplevel = views::Widget::CreateWindowWithContextAndBounds(
293 new ResizableWidgetDelegate, root_window, bounds);
296 const int kSteps = 15;
297 const int kTouchPoints = 2;
298 gfx::Point points[kTouchPoints] = {
299 gfx::Point(250, 250),
300 gfx::Point(350, 350),
303 aura::test::EventGenerator generator(root_window,
304 toplevel->GetNativeWindow());
306 wm::WindowState* toplevel_state =
307 wm::GetWindowState(toplevel->GetNativeWindow());
308 // Swipe down to minimize.
309 generator.GestureMultiFingerScroll(kTouchPoints, points, 15, kSteps, 0, 150);
310 EXPECT_TRUE(toplevel_state->IsMinimized());
313 toplevel->GetNativeWindow()->SetBounds(bounds);
315 // Swipe up to maximize.
316 generator.GestureMultiFingerScroll(kTouchPoints, points, 15, kSteps, 0, -150);
317 EXPECT_TRUE(toplevel_state->IsMaximized());
320 toplevel->GetNativeWindow()->SetBounds(bounds);
322 // Swipe right to snap.
323 gfx::Rect normal_bounds = toplevel->GetWindowBoundsInScreen();
324 generator.GestureMultiFingerScroll(kTouchPoints, points, 15, kSteps, 150, 0);
325 gfx::Rect right_tile_bounds = toplevel->GetWindowBoundsInScreen();
326 EXPECT_NE(normal_bounds.ToString(), right_tile_bounds.ToString());
328 // Swipe left to snap.
329 gfx::Point left_points[kTouchPoints];
330 for (int i = 0; i < kTouchPoints; ++i) {
331 left_points[i] = points[i];
332 left_points[i].Offset(right_tile_bounds.x(), right_tile_bounds.y());
334 generator.GestureMultiFingerScroll(kTouchPoints, left_points, 15, kSteps,
336 gfx::Rect left_tile_bounds = toplevel->GetWindowBoundsInScreen();
337 EXPECT_NE(normal_bounds.ToString(), left_tile_bounds.ToString());
338 EXPECT_NE(right_tile_bounds.ToString(), left_tile_bounds.ToString());
340 // Swipe right again.
341 generator.GestureMultiFingerScroll(kTouchPoints, points, 15, kSteps, 150, 0);
342 gfx::Rect current_bounds = toplevel->GetWindowBoundsInScreen();
343 EXPECT_NE(current_bounds.ToString(), left_tile_bounds.ToString());
344 EXPECT_EQ(current_bounds.ToString(), right_tile_bounds.ToString());
347 TEST_P(SystemGestureEventFilterTest, TwoFingerDragTwoWindows) {
348 aura::Window* root_window = Shell::GetPrimaryRootWindow();
349 ui::GestureConfiguration::set_max_separation_for_gesture_touches_in_pixels(0);
350 views::Widget* first = views::Widget::CreateWindowWithContextAndBounds(
351 new ResizableWidgetDelegate, root_window, gfx::Rect(10, 0, 50, 100));
353 views::Widget* second = views::Widget::CreateWindowWithContextAndBounds(
354 new ResizableWidgetDelegate, root_window, gfx::Rect(100, 0, 100, 100));
357 // Start a two-finger drag on |first|, and then try to use another two-finger
358 // drag to move |second|. The attempt to move |second| should fail.
359 const gfx::Rect& first_bounds = first->GetWindowBoundsInScreen();
360 const gfx::Rect& second_bounds = second->GetWindowBoundsInScreen();
361 const int kSteps = 15;
362 const int kTouchPoints = 4;
363 gfx::Point points[kTouchPoints] = {
364 first_bounds.origin() + gfx::Vector2d(5, 5),
365 first_bounds.origin() + gfx::Vector2d(30, 10),
366 second_bounds.origin() + gfx::Vector2d(5, 5),
367 second_bounds.origin() + gfx::Vector2d(40, 20)
370 aura::test::EventGenerator generator(root_window);
371 // Do not drag too fast to avoid fling.
372 generator.GestureMultiFingerScroll(kTouchPoints, points,
375 EXPECT_NE(first_bounds.ToString(),
376 first->GetWindowBoundsInScreen().ToString());
377 EXPECT_EQ(second_bounds.ToString(),
378 second->GetWindowBoundsInScreen().ToString());
381 TEST_P(SystemGestureEventFilterTest, WindowsWithMaxSizeDontSnap) {
382 gfx::Rect bounds(250, 150, 100, 100);
383 aura::Window* root_window = Shell::GetPrimaryRootWindow();
384 views::Widget* toplevel = views::Widget::CreateWindowWithContextAndBounds(
385 new MaxSizeWidgetDelegate, root_window, bounds);
388 const int kSteps = 15;
389 const int kTouchPoints = 2;
390 gfx::Point points[kTouchPoints] = {
391 gfx::Point(bounds.x() + 10, bounds.y() + 30),
392 gfx::Point(bounds.x() + 30, bounds.y() + 20),
395 aura::test::EventGenerator generator(root_window,
396 toplevel->GetNativeWindow());
398 // Swipe down to minimize.
399 generator.GestureMultiFingerScroll(kTouchPoints, points, 15, kSteps, 0, 150);
400 wm::WindowState* toplevel_state =
401 wm::GetWindowState(toplevel->GetNativeWindow());
402 EXPECT_TRUE(toplevel_state->IsMinimized());
405 toplevel->GetNativeWindow()->SetBounds(bounds);
407 // Check that swiping up doesn't maximize.
408 generator.GestureMultiFingerScroll(kTouchPoints, points, 15, kSteps, 0, -150);
409 EXPECT_FALSE(toplevel_state->IsMaximized());
412 toplevel->GetNativeWindow()->SetBounds(bounds);
414 // Check that swiping right doesn't snap.
415 gfx::Rect normal_bounds = toplevel->GetWindowBoundsInScreen();
416 generator.GestureMultiFingerScroll(kTouchPoints, points, 15, kSteps, 150, 0);
417 normal_bounds.set_x(normal_bounds.x() + 150);
418 EXPECT_EQ(normal_bounds.ToString(),
419 toplevel->GetWindowBoundsInScreen().ToString());
421 toplevel->GetNativeWindow()->SetBounds(bounds);
423 // Check that swiping left doesn't snap.
424 normal_bounds = toplevel->GetWindowBoundsInScreen();
425 generator.GestureMultiFingerScroll(kTouchPoints, points, 15, kSteps, -150, 0);
426 normal_bounds.set_x(normal_bounds.x() - 150);
427 EXPECT_EQ(normal_bounds.ToString(),
428 toplevel->GetWindowBoundsInScreen().ToString());
430 toplevel->GetNativeWindow()->SetBounds(bounds);
432 // Swipe right again, make sure the window still doesn't snap.
433 normal_bounds = toplevel->GetWindowBoundsInScreen();
434 normal_bounds.set_x(normal_bounds.x() + 150);
435 generator.GestureMultiFingerScroll(kTouchPoints, points, 15, kSteps, 150, 0);
436 EXPECT_EQ(normal_bounds.ToString(),
437 toplevel->GetWindowBoundsInScreen().ToString());
440 TEST_P(SystemGestureEventFilterTest, TwoFingerDragEdge) {
441 gfx::Rect bounds(0, 0, 100, 100);
442 aura::Window* root_window = Shell::GetPrimaryRootWindow();
443 views::Widget* toplevel = views::Widget::CreateWindowWithContextAndBounds(
444 new ResizableWidgetDelegate, root_window, bounds);
447 const int kSteps = 15;
448 const int kTouchPoints = 2;
449 gfx::Point points[kTouchPoints] = {
450 gfx::Point(30, 20), // Caption
451 gfx::Point(0, 40), // Left edge
454 EXPECT_EQ(HTLEFT, toplevel->GetNativeWindow()->delegate()->
455 GetNonClientComponent(points[1]));
457 aura::test::EventGenerator generator(root_window,
458 toplevel->GetNativeWindow());
460 bounds = toplevel->GetNativeWindow()->bounds();
461 // Swipe down. Nothing should happen.
462 generator.GestureMultiFingerScroll(kTouchPoints, points, 15, kSteps, 0, 150);
463 EXPECT_EQ(bounds.ToString(),
464 toplevel->GetNativeWindow()->bounds().ToString());
467 // We do not allow resizing a window via multiple edges simultaneously. Test
468 // that the behavior is reasonable if a user attempts to resize a window via
470 TEST_P(SystemGestureEventFilterTest,
471 TwoFingerAttemptResizeLeftAndRightEdgesSimultaneously) {
472 gfx::Rect initial_bounds(0, 0, 400, 400);
473 views::Widget* toplevel =
474 views::Widget::CreateWindowWithContextAndBounds(
475 new ResizableWidgetDelegate, CurrentContext(), initial_bounds);
478 const int kSteps = 15;
479 const int kTouchPoints = 2;
480 gfx::Point points[kTouchPoints] = {
481 gfx::Point(0, 40), // Left edge
482 gfx::Point(399, 40), // Right edge
484 int delays[kTouchPoints] = {0, 120};
486 EXPECT_EQ(HTLEFT, toplevel->GetNonClientComponent(points[0]));
487 EXPECT_EQ(HTRIGHT, toplevel->GetNonClientComponent(points[1]));
489 GetEventGenerator().GestureMultiFingerScrollWithDelays(
490 kTouchPoints, points, delays, 15, kSteps, 0, 40);
492 // The window bounds should not have changed because neither of the fingers
493 // moved horizontally.
494 EXPECT_EQ(initial_bounds.ToString(),
495 toplevel->GetNativeWindow()->bounds().ToString());
498 TEST_P(SystemGestureEventFilterTest, TwoFingerDragDelayed) {
499 gfx::Rect bounds(0, 0, 100, 100);
500 aura::Window* root_window = Shell::GetPrimaryRootWindow();
501 views::Widget* toplevel = views::Widget::CreateWindowWithContextAndBounds(
502 new ResizableWidgetDelegate, root_window, bounds);
505 const int kSteps = 15;
506 const int kTouchPoints = 2;
507 gfx::Point points[kTouchPoints] = {
508 gfx::Point(30, 20), // Caption
509 gfx::Point(34, 20), // Caption
511 int delays[kTouchPoints] = {0, 120};
513 EXPECT_EQ(HTCAPTION, toplevel->GetNativeWindow()->delegate()->
514 GetNonClientComponent(points[0]));
515 EXPECT_EQ(HTCAPTION, toplevel->GetNativeWindow()->delegate()->
516 GetNonClientComponent(points[1]));
518 aura::test::EventGenerator generator(root_window,
519 toplevel->GetNativeWindow());
521 bounds = toplevel->GetNativeWindow()->bounds();
522 // Swipe right and down starting with one finger.
523 // Add another finger after 120ms and continue dragging.
524 // The window should move and the drag should be determined by the center
525 // point between the fingers.
526 generator.GestureMultiFingerScrollWithDelays(
527 kTouchPoints, points, delays, 15, kSteps, 150, 150);
528 bounds += gfx::Vector2d(150 + (points[1].x() - points[0].x()) / 2, 150);
529 EXPECT_EQ(bounds.ToString(),
530 toplevel->GetNativeWindow()->bounds().ToString());
533 TEST_P(SystemGestureEventFilterTest, ThreeFingerGestureStopsDrag) {
534 gfx::Rect bounds(0, 0, 100, 100);
535 aura::Window* root_window = Shell::GetPrimaryRootWindow();
536 views::Widget* toplevel = views::Widget::CreateWindowWithContextAndBounds(
537 new ResizableWidgetDelegate, root_window, bounds);
540 const int kSteps = 10;
541 const int kTouchPoints = 3;
542 gfx::Point points[kTouchPoints] = {
543 gfx::Point(30, 20), // Caption
544 gfx::Point(34, 20), // Caption
545 gfx::Point(38, 20), // Caption
547 int delays[kTouchPoints] = {0, 0, 120};
549 EXPECT_EQ(HTCAPTION, toplevel->GetNativeWindow()->delegate()->
550 GetNonClientComponent(points[0]));
551 EXPECT_EQ(HTCAPTION, toplevel->GetNativeWindow()->delegate()->
552 GetNonClientComponent(points[1]));
554 aura::test::EventGenerator generator(root_window,
555 toplevel->GetNativeWindow());
557 bounds = toplevel->GetNativeWindow()->bounds();
558 // Swipe right and down starting with two fingers.
559 // Add third finger after 120ms and continue dragging.
560 // The window should start moving but stop when the 3rd finger touches down.
561 const int kEventSeparation = 15;
562 generator.GestureMultiFingerScrollWithDelays(
563 kTouchPoints, points, delays, kEventSeparation, kSteps, 150, 150);
564 int expected_drag = 150 / kSteps * 120 / kEventSeparation;
565 bounds += gfx::Vector2d(expected_drag, expected_drag);
566 EXPECT_EQ(bounds.ToString(),
567 toplevel->GetNativeWindow()->bounds().ToString());
570 TEST_P(SystemGestureEventFilterTest, DragLeftNearEdgeSnaps) {
571 gfx::Rect bounds(200, 150, 400, 100);
572 aura::Window* root_window = Shell::GetPrimaryRootWindow();
573 views::Widget* toplevel = views::Widget::CreateWindowWithContextAndBounds(
574 new ResizableWidgetDelegate, root_window, bounds);
577 const int kSteps = 15;
578 const int kTouchPoints = 2;
579 gfx::Point points[kTouchPoints] = {
580 gfx::Point(bounds.x() + bounds.width() / 2, bounds.y() + 5),
581 gfx::Point(bounds.x() + bounds.width() / 2, bounds.y() + 5),
583 aura::test::EventGenerator generator(root_window,
584 toplevel->GetNativeWindow());
586 // Check that dragging left snaps before reaching the screen edge.
587 gfx::Rect work_area =
588 Shell::GetScreen()->GetDisplayNearestWindow(root_window).work_area();
589 int drag_x = work_area.x() + 20 - points[0].x();
590 generator.GestureMultiFingerScroll(
591 kTouchPoints, points, 120, kSteps, drag_x, 0);
593 internal::SnapSizer snap_sizer(
594 wm::GetWindowState(toplevel->GetNativeWindow()),
596 internal::SnapSizer::LEFT_EDGE,
597 internal::SnapSizer::OTHER_INPUT);
598 gfx::Rect expected_bounds(snap_sizer.target_bounds());
599 EXPECT_EQ(expected_bounds.ToString(),
600 toplevel->GetWindowBoundsInScreen().ToString());
603 TEST_P(SystemGestureEventFilterTest, DragRightNearEdgeSnaps) {
604 gfx::Rect bounds(200, 150, 400, 100);
605 aura::Window* root_window = Shell::GetPrimaryRootWindow();
606 views::Widget* toplevel = views::Widget::CreateWindowWithContextAndBounds(
607 new ResizableWidgetDelegate, root_window, bounds);
610 const int kSteps = 15;
611 const int kTouchPoints = 2;
612 gfx::Point points[kTouchPoints] = {
613 gfx::Point(bounds.x() + bounds.width() / 2, bounds.y() + 5),
614 gfx::Point(bounds.x() + bounds.width() / 2, bounds.y() + 5),
616 aura::test::EventGenerator generator(root_window,
617 toplevel->GetNativeWindow());
619 // Check that dragging right snaps before reaching the screen edge.
620 gfx::Rect work_area =
621 Shell::GetScreen()->GetDisplayNearestWindow(root_window).work_area();
622 int drag_x = work_area.right() - 20 - points[0].x();
623 generator.GestureMultiFingerScroll(
624 kTouchPoints, points, 120, kSteps, drag_x, 0);
625 internal::SnapSizer snap_sizer(
626 wm::GetWindowState(toplevel->GetNativeWindow()),
628 internal::SnapSizer::RIGHT_EDGE,
629 internal::SnapSizer::OTHER_INPUT);
630 gfx::Rect expected_bounds(snap_sizer.target_bounds());
631 EXPECT_EQ(expected_bounds.ToString(),
632 toplevel->GetWindowBoundsInScreen().ToString());
635 // Tests that the window manager does not consume gesture events targetted to
636 // windows of type WINDOW_TYPE_CONTROL. This is important because the web
637 // contents are often (but not always) of type WINDOW_TYPE_CONTROL.
638 TEST_P(SystemGestureEventFilterTest,
639 ControlWindowGetsMultiFingerGestureEvents) {
640 scoped_ptr<aura::Window> parent(
641 CreateTestWindowInShellWithBounds(gfx::Rect(100, 100)));
643 aura::test::EventCountDelegate delegate;
644 delegate.set_window_component(HTCLIENT);
645 scoped_ptr<aura::Window> child(new aura::Window(&delegate));
646 child->SetType(ui::wm::WINDOW_TYPE_CONTROL);
647 child->Init(aura::WINDOW_LAYER_TEXTURED);
648 parent->AddChild(child.get());
649 child->SetBounds(gfx::Rect(100, 100));
652 aura::test::TestEventHandler event_handler;
653 aura::Env::GetInstance()->PrependPreTargetHandler(&event_handler);
655 GetEventGenerator().MoveMouseTo(0, 0);
656 for (int i = 1; i <= 3; ++i)
657 GetEventGenerator().PressTouchId(i);
658 for (int i = 1; i <= 3; ++i)
659 GetEventGenerator().ReleaseTouchId(i);
660 EXPECT_EQ(event_handler.num_gesture_events(),
661 delegate.GetGestureCountAndReset());
663 aura::Env::GetInstance()->RemovePreTargetHandler(&event_handler);
666 // Tests run twice - with docked windows disabled or enabled.
667 INSTANTIATE_TEST_CASE_P(DockedWindowsDisabledOrEnabled,
668 SystemGestureEventFilterTest,