blob: 0e9c63fce6a7af162090586c3e938731b3329c9a [file] [log] [blame]
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001// 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.
4
5#include "ash/wm/system_gesture_event_filter.h"
6
Torne (Richard Coles)cedac222014-06-03 10:58:34 +01007#include <vector>
8
Torne (Richard Coles)58218062012-11-14 11:43:16 +00009#include "ash/accelerators/accelerator_controller.h"
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000010#include "ash/display/display_manager.h"
Torne (Richard Coles)5d1f7b12014-02-21 12:16:55 +000011#include "ash/shelf/shelf.h"
Torne (Richard Coles)f2477e02013-11-28 11:55:43 +000012#include "ash/shelf/shelf_model.h"
Torne (Richard Coles)58218062012-11-14 11:43:16 +000013#include "ash/shell.h"
Torne (Richard Coles)58218062012-11-14 11:43:16 +000014#include "ash/system/tray/system_tray_delegate.h"
15#include "ash/test/ash_test_base.h"
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000016#include "ash/test/display_manager_test_api.h"
17#include "ash/test/shell_test_api.h"
Torne (Richard Coles)a3f6a492013-12-18 16:25:09 +000018#include "ash/test/test_shelf_delegate.h"
Torne (Richard Coles)58218062012-11-14 11:43:16 +000019#include "ash/wm/gestures/long_press_affordance_handler.h"
Torne (Richard Coles)68043e12013-09-26 13:24:57 +010020#include "ash/wm/window_state.h"
Torne (Richard Coles)58218062012-11-14 11:43:16 +000021#include "ash/wm/window_util.h"
Ben Murdocheb525c52013-07-10 11:40:50 +010022#include "base/time/time.h"
23#include "base/timer/timer.h"
Torne (Richard Coles)5d1f7b12014-02-21 12:16:55 +000024#include "ui/aura/env.h"
Torne (Richard Coles)58218062012-11-14 11:43:16 +000025#include "ui/aura/test/event_generator.h"
Torne (Richard Coles)5d1f7b12014-02-21 12:16:55 +000026#include "ui/aura/test/test_window_delegate.h"
Torne (Richard Coles)58218062012-11-14 11:43:16 +000027#include "ui/aura/test/test_windows.h"
Torne (Richard Coles)a1401312014-03-18 10:20:56 +000028#include "ui/aura/window_event_dispatcher.h"
Torne (Richard Coles)58218062012-11-14 11:43:16 +000029#include "ui/base/hit_test.h"
Torne (Richard Coles)d0247b12013-09-19 22:36:51 +010030#include "ui/events/event.h"
Torne (Richard Coles)5d1f7b12014-02-21 12:16:55 +000031#include "ui/events/event_handler.h"
Torne (Richard Coles)d0247b12013-09-19 22:36:51 +010032#include "ui/events/event_utils.h"
Torne (Richard Coles)68043e12013-09-26 13:24:57 +010033#include "ui/events/gestures/gesture_configuration.h"
Torne (Richard Coles)23730a62014-03-21 14:25:57 +000034#include "ui/events/test/test_event_handler.h"
Torne (Richard Coles)58218062012-11-14 11:43:16 +000035#include "ui/gfx/screen.h"
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000036#include "ui/gfx/size.h"
Torne (Richard Coles)cedac222014-06-03 10:58:34 +010037#include "ui/views/widget/widget.h"
Torne (Richard Coles)58218062012-11-14 11:43:16 +000038#include "ui/views/widget/widget_delegate.h"
Torne (Richard Coles)cedac222014-06-03 10:58:34 +010039#include "ui/views/window/non_client_view.h"
40#include "ui/views/window/window_button_order_provider.h"
Torne (Richard Coles)58218062012-11-14 11:43:16 +000041
42namespace ash {
43namespace test {
44
45namespace {
46
Torne (Richard Coles)58218062012-11-14 11:43:16 +000047class ResizableWidgetDelegate : public views::WidgetDelegateView {
48 public:
49 ResizableWidgetDelegate() {}
50 virtual ~ResizableWidgetDelegate() {}
51
52 private:
53 virtual bool CanResize() const OVERRIDE { return true; }
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000054 virtual bool CanMaximize() const OVERRIDE { return true; }
Torne (Richard Coles)58218062012-11-14 11:43:16 +000055 virtual void DeleteDelegate() OVERRIDE { delete this; }
56
57 DISALLOW_COPY_AND_ASSIGN(ResizableWidgetDelegate);
58};
59
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000060// Support class for testing windows with a maximum size.
61class MaxSizeNCFV : public views::NonClientFrameView {
62 public:
63 MaxSizeNCFV() {}
64 private:
Torne (Richard Coles)cedac222014-06-03 10:58:34 +010065 virtual gfx::Size GetMaximumSize() const OVERRIDE {
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000066 return gfx::Size(200, 200);
67 }
68 virtual gfx::Rect GetBoundsForClientView() const OVERRIDE {
69 return gfx::Rect();
70 };
71
72 virtual gfx::Rect GetWindowBoundsForClientBounds(
73 const gfx::Rect& client_bounds) const OVERRIDE {
74 return gfx::Rect();
75 };
76
77 // This function must ask the ClientView to do a hittest. We don't do this in
78 // the parent NonClientView because that makes it more difficult to calculate
79 // hittests for regions that are partially obscured by the ClientView, e.g.
80 // HTSYSMENU.
81 virtual int NonClientHitTest(const gfx::Point& point) OVERRIDE {
82 return HTNOWHERE;
83 }
84 virtual void GetWindowMask(const gfx::Size& size,
85 gfx::Path* window_mask) OVERRIDE {}
86 virtual void ResetWindowControls() OVERRIDE {}
87 virtual void UpdateWindowIcon() OVERRIDE {}
88 virtual void UpdateWindowTitle() OVERRIDE {}
89
90 DISALLOW_COPY_AND_ASSIGN(MaxSizeNCFV);
91};
92
93class MaxSizeWidgetDelegate : public views::WidgetDelegateView {
94 public:
95 MaxSizeWidgetDelegate() {}
96 virtual ~MaxSizeWidgetDelegate() {}
97
98 private:
99 virtual bool CanResize() const OVERRIDE { return true; }
100 virtual bool CanMaximize() const OVERRIDE { return false; }
101 virtual void DeleteDelegate() OVERRIDE { delete this; }
102 virtual views::NonClientFrameView* CreateNonClientFrameView(
103 views::Widget* widget) OVERRIDE {
104 return new MaxSizeNCFV;
105 }
106
107 DISALLOW_COPY_AND_ASSIGN(MaxSizeWidgetDelegate);
108};
109
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000110} // namespace
111
Torne (Richard Coles)cedac222014-06-03 10:58:34 +0100112class SystemGestureEventFilterTest : public AshTestBase {
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000113 public:
Torne (Richard Coles)cedac222014-06-03 10:58:34 +0100114 SystemGestureEventFilterTest() : AshTestBase() {}
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000115 virtual ~SystemGestureEventFilterTest() {}
116
Ben Murdochc5cede92014-04-10 11:22:14 +0100117 LongPressAffordanceHandler* GetLongPressAffordance() {
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000118 ShellTestApi shell_test(Shell::GetInstance());
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000119 return shell_test.system_gesture_event_filter()->
120 long_press_affordance_.get();
121 }
122
Ben Murdochc5cede92014-04-10 11:22:14 +0100123 base::OneShotTimer<LongPressAffordanceHandler>*
124 GetLongPressAffordanceTimer() {
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000125 return &GetLongPressAffordance()->timer_;
126 }
127
Torne (Richard Coles)f2477e02013-11-28 11:55:43 +0000128 aura::Window* GetLongPressAffordanceTarget() {
129 return GetLongPressAffordance()->tap_down_target_;
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000130 }
131
132 views::View* GetLongPressAffordanceView() {
133 return reinterpret_cast<views::View*>(
134 GetLongPressAffordance()->view_.get());
135 }
136
137 // Overridden from AshTestBase:
138 virtual void SetUp() OVERRIDE {
Torne (Richard Coles)cedac222014-06-03 10:58:34 +0100139 // TODO(jonross): TwoFingerDragDelayed() and ThreeFingerGestureStopsDrag()
140 // both use hardcoded touch points, assuming that they target empty header
141 // space. Window control order now reflects configuration files and can
142 // change. The tests should be improved to dynamically decide touch points.
143 // To address this we specify the originally expected window control
144 // positions to be consistent across tests.
145 std::vector<views::FrameButton> leading;
146 std::vector<views::FrameButton> trailing;
147 trailing.push_back(views::FRAME_BUTTON_MINIMIZE);
148 trailing.push_back(views::FRAME_BUTTON_MAXIMIZE);
149 trailing.push_back(views::FRAME_BUTTON_CLOSE);
150 views::WindowButtonOrderProvider::GetInstance()->
151 SetWindowButtonOrder(leading, trailing);
152
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000153 test::AshTestBase::SetUp();
154 // Enable brightness key.
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000155 test::DisplayManagerTestApi(Shell::GetInstance()->display_manager()).
156 SetFirstDisplayAsInternalDisplay();
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000157 }
158
159 private:
160 DISALLOW_COPY_AND_ASSIGN(SystemGestureEventFilterTest);
161};
162
163ui::GestureEvent* CreateGesture(ui::EventType type,
164 int x,
165 int y,
166 float delta_x,
167 float delta_y,
168 int touch_id) {
169 return new ui::GestureEvent(type, x, y, 0,
170 base::TimeDelta::FromMilliseconds(base::Time::Now().ToDoubleT() * 1000),
171 ui::GestureEventDetails(type, delta_x, delta_y), 1 << touch_id);
172}
173
Torne (Richard Coles)cedac222014-06-03 10:58:34 +0100174TEST_F(SystemGestureEventFilterTest, LongPressAffordanceStateOnCaptureLoss) {
Torne (Richard Coles)1e9bf3e2013-10-31 11:16:26 +0000175 aura::Window* root_window = Shell::GetPrimaryRootWindow();
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000176
177 aura::test::TestWindowDelegate delegate;
178 scoped_ptr<aura::Window> window0(
179 aura::test::CreateTestWindowWithDelegate(
180 &delegate, 9, gfx::Rect(0, 0, 100, 100), root_window));
181 scoped_ptr<aura::Window> window1(
182 aura::test::CreateTestWindowWithDelegate(
183 &delegate, 10, gfx::Rect(0, 0, 100, 50), window0.get()));
184 scoped_ptr<aura::Window> window2(
185 aura::test::CreateTestWindowWithDelegate(
186 &delegate, 11, gfx::Rect(0, 50, 100, 50), window0.get()));
187
188 const int kTouchId = 5;
189
190 // Capture first window.
191 window1->SetCapture();
192 EXPECT_TRUE(window1->HasCapture());
193
194 // Send touch event to first window.
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000195 ui::TouchEvent press(ui::ET_TOUCH_PRESSED,
196 gfx::Point(10, 10),
197 kTouchId,
198 ui::EventTimeForNow());
Torne (Richard Coles)5d1f7b12014-02-21 12:16:55 +0000199 ui::EventDispatchDetails details =
Torne (Richard Coles)a1401312014-03-18 10:20:56 +0000200 root_window->GetHost()->dispatcher()->OnEventFromSource(&press);
Torne (Richard Coles)5d1f7b12014-02-21 12:16:55 +0000201 ASSERT_FALSE(details.dispatcher_destroyed);
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000202 EXPECT_TRUE(window1->HasCapture());
203
Ben Murdochc5cede92014-04-10 11:22:14 +0100204 base::OneShotTimer<LongPressAffordanceHandler>* timer =
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000205 GetLongPressAffordanceTimer();
206 EXPECT_TRUE(timer->IsRunning());
Torne (Richard Coles)f2477e02013-11-28 11:55:43 +0000207 EXPECT_EQ(window1, GetLongPressAffordanceTarget());
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000208
209 // Force timeout so that the affordance animation can start.
210 timer->user_task().Run();
211 timer->Stop();
212 EXPECT_TRUE(GetLongPressAffordance()->is_animating());
213
214 // Change capture.
215 window2->SetCapture();
216 EXPECT_TRUE(window2->HasCapture());
217
218 EXPECT_TRUE(GetLongPressAffordance()->is_animating());
Torne (Richard Coles)f2477e02013-11-28 11:55:43 +0000219 EXPECT_EQ(window1, GetLongPressAffordanceTarget());
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000220
221 // Animate to completion.
222 GetLongPressAffordance()->End(); // end grow animation.
223 // Force timeout to start shrink animation.
224 EXPECT_TRUE(timer->IsRunning());
225 timer->user_task().Run();
226 timer->Stop();
227 EXPECT_TRUE(GetLongPressAffordance()->is_animating());
228 GetLongPressAffordance()->End(); // end shrink animation.
229
230 // Check if state has reset.
Torne (Richard Coles)f2477e02013-11-28 11:55:43 +0000231 EXPECT_EQ(NULL, GetLongPressAffordanceTarget());
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000232 EXPECT_EQ(NULL, GetLongPressAffordanceView());
233}
234
Torne (Richard Coles)cedac222014-06-03 10:58:34 +0100235TEST_F(SystemGestureEventFilterTest, TwoFingerDrag) {
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100236 gfx::Rect bounds(0, 0, 600, 600);
Torne (Richard Coles)1e9bf3e2013-10-31 11:16:26 +0000237 aura::Window* root_window = Shell::GetPrimaryRootWindow();
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000238 views::Widget* toplevel = views::Widget::CreateWindowWithContextAndBounds(
239 new ResizableWidgetDelegate, root_window, bounds);
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000240 toplevel->Show();
241
242 const int kSteps = 15;
243 const int kTouchPoints = 2;
244 gfx::Point points[kTouchPoints] = {
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100245 gfx::Point(250, 250),
246 gfx::Point(350, 350),
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000247 };
248
249 aura::test::EventGenerator generator(root_window,
250 toplevel->GetNativeWindow());
251
Torne (Richard Coles)68043e12013-09-26 13:24:57 +0100252 wm::WindowState* toplevel_state =
253 wm::GetWindowState(toplevel->GetNativeWindow());
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000254 // Swipe down to minimize.
255 generator.GestureMultiFingerScroll(kTouchPoints, points, 15, kSteps, 0, 150);
Torne (Richard Coles)68043e12013-09-26 13:24:57 +0100256 EXPECT_TRUE(toplevel_state->IsMinimized());
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000257
258 toplevel->Restore();
259 toplevel->GetNativeWindow()->SetBounds(bounds);
260
261 // Swipe up to maximize.
262 generator.GestureMultiFingerScroll(kTouchPoints, points, 15, kSteps, 0, -150);
Torne (Richard Coles)68043e12013-09-26 13:24:57 +0100263 EXPECT_TRUE(toplevel_state->IsMaximized());
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000264
265 toplevel->Restore();
266 toplevel->GetNativeWindow()->SetBounds(bounds);
267
268 // Swipe right to snap.
269 gfx::Rect normal_bounds = toplevel->GetWindowBoundsInScreen();
270 generator.GestureMultiFingerScroll(kTouchPoints, points, 15, kSteps, 150, 0);
271 gfx::Rect right_tile_bounds = toplevel->GetWindowBoundsInScreen();
272 EXPECT_NE(normal_bounds.ToString(), right_tile_bounds.ToString());
273
274 // Swipe left to snap.
275 gfx::Point left_points[kTouchPoints];
276 for (int i = 0; i < kTouchPoints; ++i) {
277 left_points[i] = points[i];
278 left_points[i].Offset(right_tile_bounds.x(), right_tile_bounds.y());
279 }
280 generator.GestureMultiFingerScroll(kTouchPoints, left_points, 15, kSteps,
281 -150, 0);
282 gfx::Rect left_tile_bounds = toplevel->GetWindowBoundsInScreen();
283 EXPECT_NE(normal_bounds.ToString(), left_tile_bounds.ToString());
284 EXPECT_NE(right_tile_bounds.ToString(), left_tile_bounds.ToString());
285
286 // Swipe right again.
287 generator.GestureMultiFingerScroll(kTouchPoints, points, 15, kSteps, 150, 0);
288 gfx::Rect current_bounds = toplevel->GetWindowBoundsInScreen();
289 EXPECT_NE(current_bounds.ToString(), left_tile_bounds.ToString());
290 EXPECT_EQ(current_bounds.ToString(), right_tile_bounds.ToString());
291}
292
Torne (Richard Coles)cedac222014-06-03 10:58:34 +0100293TEST_F(SystemGestureEventFilterTest, TwoFingerDragTwoWindows) {
Torne (Richard Coles)1e9bf3e2013-10-31 11:16:26 +0000294 aura::Window* root_window = Shell::GetPrimaryRootWindow();
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000295 ui::GestureConfiguration::set_max_separation_for_gesture_touches_in_pixels(0);
296 views::Widget* first = views::Widget::CreateWindowWithContextAndBounds(
Torne (Richard Coles)5d1f7b12014-02-21 12:16:55 +0000297 new ResizableWidgetDelegate, root_window, gfx::Rect(10, 0, 50, 100));
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000298 first->Show();
299 views::Widget* second = views::Widget::CreateWindowWithContextAndBounds(
300 new ResizableWidgetDelegate, root_window, gfx::Rect(100, 0, 100, 100));
301 second->Show();
302
303 // Start a two-finger drag on |first|, and then try to use another two-finger
304 // drag to move |second|. The attempt to move |second| should fail.
305 const gfx::Rect& first_bounds = first->GetWindowBoundsInScreen();
306 const gfx::Rect& second_bounds = second->GetWindowBoundsInScreen();
307 const int kSteps = 15;
308 const int kTouchPoints = 4;
309 gfx::Point points[kTouchPoints] = {
310 first_bounds.origin() + gfx::Vector2d(5, 5),
311 first_bounds.origin() + gfx::Vector2d(30, 10),
312 second_bounds.origin() + gfx::Vector2d(5, 5),
313 second_bounds.origin() + gfx::Vector2d(40, 20)
314 };
315
316 aura::test::EventGenerator generator(root_window);
Torne (Richard Coles)1e9bf3e2013-10-31 11:16:26 +0000317 // Do not drag too fast to avoid fling.
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000318 generator.GestureMultiFingerScroll(kTouchPoints, points,
Torne (Richard Coles)1e9bf3e2013-10-31 11:16:26 +0000319 50, kSteps, 0, 150);
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000320
321 EXPECT_NE(first_bounds.ToString(),
322 first->GetWindowBoundsInScreen().ToString());
323 EXPECT_EQ(second_bounds.ToString(),
324 second->GetWindowBoundsInScreen().ToString());
325}
326
Torne (Richard Coles)cedac222014-06-03 10:58:34 +0100327TEST_F(SystemGestureEventFilterTest, WindowsWithMaxSizeDontSnap) {
Torne (Richard Coles)f2477e02013-11-28 11:55:43 +0000328 gfx::Rect bounds(250, 150, 100, 100);
Torne (Richard Coles)1e9bf3e2013-10-31 11:16:26 +0000329 aura::Window* root_window = Shell::GetPrimaryRootWindow();
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000330 views::Widget* toplevel = views::Widget::CreateWindowWithContextAndBounds(
331 new MaxSizeWidgetDelegate, root_window, bounds);
332 toplevel->Show();
333
334 const int kSteps = 15;
335 const int kTouchPoints = 2;
336 gfx::Point points[kTouchPoints] = {
Torne (Richard Coles)f2477e02013-11-28 11:55:43 +0000337 gfx::Point(bounds.x() + 10, bounds.y() + 30),
338 gfx::Point(bounds.x() + 30, bounds.y() + 20),
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000339 };
340
341 aura::test::EventGenerator generator(root_window,
342 toplevel->GetNativeWindow());
343
344 // Swipe down to minimize.
345 generator.GestureMultiFingerScroll(kTouchPoints, points, 15, kSteps, 0, 150);
Torne (Richard Coles)68043e12013-09-26 13:24:57 +0100346 wm::WindowState* toplevel_state =
347 wm::GetWindowState(toplevel->GetNativeWindow());
348 EXPECT_TRUE(toplevel_state->IsMinimized());
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000349
350 toplevel->Restore();
351 toplevel->GetNativeWindow()->SetBounds(bounds);
352
353 // Check that swiping up doesn't maximize.
354 generator.GestureMultiFingerScroll(kTouchPoints, points, 15, kSteps, 0, -150);
Torne (Richard Coles)68043e12013-09-26 13:24:57 +0100355 EXPECT_FALSE(toplevel_state->IsMaximized());
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000356
357 toplevel->Restore();
358 toplevel->GetNativeWindow()->SetBounds(bounds);
359
360 // Check that swiping right doesn't snap.
361 gfx::Rect normal_bounds = toplevel->GetWindowBoundsInScreen();
362 generator.GestureMultiFingerScroll(kTouchPoints, points, 15, kSteps, 150, 0);
363 normal_bounds.set_x(normal_bounds.x() + 150);
364 EXPECT_EQ(normal_bounds.ToString(),
365 toplevel->GetWindowBoundsInScreen().ToString());
366
367 toplevel->GetNativeWindow()->SetBounds(bounds);
368
369 // Check that swiping left doesn't snap.
370 normal_bounds = toplevel->GetWindowBoundsInScreen();
371 generator.GestureMultiFingerScroll(kTouchPoints, points, 15, kSteps, -150, 0);
372 normal_bounds.set_x(normal_bounds.x() - 150);
373 EXPECT_EQ(normal_bounds.ToString(),
374 toplevel->GetWindowBoundsInScreen().ToString());
375
376 toplevel->GetNativeWindow()->SetBounds(bounds);
377
378 // Swipe right again, make sure the window still doesn't snap.
379 normal_bounds = toplevel->GetWindowBoundsInScreen();
380 normal_bounds.set_x(normal_bounds.x() + 150);
381 generator.GestureMultiFingerScroll(kTouchPoints, points, 15, kSteps, 150, 0);
382 EXPECT_EQ(normal_bounds.ToString(),
383 toplevel->GetWindowBoundsInScreen().ToString());
384}
385
Torne (Richard Coles)f8ee7882014-06-20 14:52:04 +0100386TEST_F(SystemGestureEventFilterTest, DISABLED_TwoFingerDragEdge) {
387 gfx::Rect bounds(0, 0, 200, 100);
Torne (Richard Coles)1e9bf3e2013-10-31 11:16:26 +0000388 aura::Window* root_window = Shell::GetPrimaryRootWindow();
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000389 views::Widget* toplevel = views::Widget::CreateWindowWithContextAndBounds(
390 new ResizableWidgetDelegate, root_window, bounds);
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000391 toplevel->Show();
392
393 const int kSteps = 15;
394 const int kTouchPoints = 2;
395 gfx::Point points[kTouchPoints] = {
396 gfx::Point(30, 20), // Caption
397 gfx::Point(0, 40), // Left edge
398 };
399
Torne (Richard Coles)f8ee7882014-06-20 14:52:04 +0100400 EXPECT_EQ(HTCAPTION, toplevel->GetNativeWindow()->delegate()->
401 GetNonClientComponent(points[0]));
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000402 EXPECT_EQ(HTLEFT, toplevel->GetNativeWindow()->delegate()->
403 GetNonClientComponent(points[1]));
404
405 aura::test::EventGenerator generator(root_window,
406 toplevel->GetNativeWindow());
407
408 bounds = toplevel->GetNativeWindow()->bounds();
409 // Swipe down. Nothing should happen.
410 generator.GestureMultiFingerScroll(kTouchPoints, points, 15, kSteps, 0, 150);
411 EXPECT_EQ(bounds.ToString(),
412 toplevel->GetNativeWindow()->bounds().ToString());
413}
414
Torne (Richard Coles)5d1f7b12014-02-21 12:16:55 +0000415// We do not allow resizing a window via multiple edges simultaneously. Test
416// that the behavior is reasonable if a user attempts to resize a window via
417// several edges.
Torne (Richard Coles)cedac222014-06-03 10:58:34 +0100418TEST_F(SystemGestureEventFilterTest,
Torne (Richard Coles)5d1f7b12014-02-21 12:16:55 +0000419 TwoFingerAttemptResizeLeftAndRightEdgesSimultaneously) {
420 gfx::Rect initial_bounds(0, 0, 400, 400);
421 views::Widget* toplevel =
422 views::Widget::CreateWindowWithContextAndBounds(
423 new ResizableWidgetDelegate, CurrentContext(), initial_bounds);
424 toplevel->Show();
425
426 const int kSteps = 15;
427 const int kTouchPoints = 2;
428 gfx::Point points[kTouchPoints] = {
429 gfx::Point(0, 40), // Left edge
430 gfx::Point(399, 40), // Right edge
431 };
432 int delays[kTouchPoints] = {0, 120};
433
434 EXPECT_EQ(HTLEFT, toplevel->GetNonClientComponent(points[0]));
435 EXPECT_EQ(HTRIGHT, toplevel->GetNonClientComponent(points[1]));
436
437 GetEventGenerator().GestureMultiFingerScrollWithDelays(
438 kTouchPoints, points, delays, 15, kSteps, 0, 40);
439
440 // The window bounds should not have changed because neither of the fingers
441 // moved horizontally.
442 EXPECT_EQ(initial_bounds.ToString(),
443 toplevel->GetNativeWindow()->bounds().ToString());
444}
445
Torne (Richard Coles)cedac222014-06-03 10:58:34 +0100446TEST_F(SystemGestureEventFilterTest, TwoFingerDragDelayed) {
447 gfx::Rect bounds(0, 0, 200, 100);
Torne (Richard Coles)1e9bf3e2013-10-31 11:16:26 +0000448 aura::Window* root_window = Shell::GetPrimaryRootWindow();
449 views::Widget* toplevel = views::Widget::CreateWindowWithContextAndBounds(
450 new ResizableWidgetDelegate, root_window, bounds);
451 toplevel->Show();
452
453 const int kSteps = 15;
454 const int kTouchPoints = 2;
455 gfx::Point points[kTouchPoints] = {
456 gfx::Point(30, 20), // Caption
457 gfx::Point(34, 20), // Caption
458 };
459 int delays[kTouchPoints] = {0, 120};
460
461 EXPECT_EQ(HTCAPTION, toplevel->GetNativeWindow()->delegate()->
462 GetNonClientComponent(points[0]));
463 EXPECT_EQ(HTCAPTION, toplevel->GetNativeWindow()->delegate()->
464 GetNonClientComponent(points[1]));
465
466 aura::test::EventGenerator generator(root_window,
467 toplevel->GetNativeWindow());
468
469 bounds = toplevel->GetNativeWindow()->bounds();
470 // Swipe right and down starting with one finger.
471 // Add another finger after 120ms and continue dragging.
472 // The window should move and the drag should be determined by the center
473 // point between the fingers.
474 generator.GestureMultiFingerScrollWithDelays(
475 kTouchPoints, points, delays, 15, kSteps, 150, 150);
476 bounds += gfx::Vector2d(150 + (points[1].x() - points[0].x()) / 2, 150);
477 EXPECT_EQ(bounds.ToString(),
478 toplevel->GetNativeWindow()->bounds().ToString());
479}
480
Torne (Richard Coles)cedac222014-06-03 10:58:34 +0100481TEST_F(SystemGestureEventFilterTest, ThreeFingerGestureStopsDrag) {
482 gfx::Rect bounds(0, 0, 200, 100);
Torne (Richard Coles)1e9bf3e2013-10-31 11:16:26 +0000483 aura::Window* root_window = Shell::GetPrimaryRootWindow();
484 views::Widget* toplevel = views::Widget::CreateWindowWithContextAndBounds(
485 new ResizableWidgetDelegate, root_window, bounds);
486 toplevel->Show();
487
488 const int kSteps = 10;
489 const int kTouchPoints = 3;
490 gfx::Point points[kTouchPoints] = {
491 gfx::Point(30, 20), // Caption
492 gfx::Point(34, 20), // Caption
493 gfx::Point(38, 20), // Caption
494 };
495 int delays[kTouchPoints] = {0, 0, 120};
496
497 EXPECT_EQ(HTCAPTION, toplevel->GetNativeWindow()->delegate()->
498 GetNonClientComponent(points[0]));
499 EXPECT_EQ(HTCAPTION, toplevel->GetNativeWindow()->delegate()->
500 GetNonClientComponent(points[1]));
501
502 aura::test::EventGenerator generator(root_window,
503 toplevel->GetNativeWindow());
504
505 bounds = toplevel->GetNativeWindow()->bounds();
506 // Swipe right and down starting with two fingers.
507 // Add third finger after 120ms and continue dragging.
508 // The window should start moving but stop when the 3rd finger touches down.
509 const int kEventSeparation = 15;
510 generator.GestureMultiFingerScrollWithDelays(
511 kTouchPoints, points, delays, kEventSeparation, kSteps, 150, 150);
512 int expected_drag = 150 / kSteps * 120 / kEventSeparation;
513 bounds += gfx::Vector2d(expected_drag, expected_drag);
514 EXPECT_EQ(bounds.ToString(),
515 toplevel->GetNativeWindow()->bounds().ToString());
516}
517
Torne (Richard Coles)cedac222014-06-03 10:58:34 +0100518TEST_F(SystemGestureEventFilterTest, DragLeftNearEdgeSnaps) {
Torne (Richard Coles)f2477e02013-11-28 11:55:43 +0000519 gfx::Rect bounds(200, 150, 400, 100);
520 aura::Window* root_window = Shell::GetPrimaryRootWindow();
521 views::Widget* toplevel = views::Widget::CreateWindowWithContextAndBounds(
522 new ResizableWidgetDelegate, root_window, bounds);
523 toplevel->Show();
524
525 const int kSteps = 15;
526 const int kTouchPoints = 2;
527 gfx::Point points[kTouchPoints] = {
528 gfx::Point(bounds.x() + bounds.width() / 2, bounds.y() + 5),
529 gfx::Point(bounds.x() + bounds.width() / 2, bounds.y() + 5),
530 };
Torne (Richard Coles)a1401312014-03-18 10:20:56 +0000531 aura::Window* toplevel_window = toplevel->GetNativeWindow();
532 aura::test::EventGenerator generator(root_window, toplevel_window);
Torne (Richard Coles)f2477e02013-11-28 11:55:43 +0000533
534 // Check that dragging left snaps before reaching the screen edge.
535 gfx::Rect work_area =
536 Shell::GetScreen()->GetDisplayNearestWindow(root_window).work_area();
537 int drag_x = work_area.x() + 20 - points[0].x();
538 generator.GestureMultiFingerScroll(
539 kTouchPoints, points, 120, kSteps, drag_x, 0);
540
Torne (Richard Coles)a1401312014-03-18 10:20:56 +0000541 EXPECT_EQ(wm::GetDefaultLeftSnappedWindowBoundsInParent(
542 toplevel_window).ToString(),
543 toplevel_window->bounds().ToString());
Torne (Richard Coles)f2477e02013-11-28 11:55:43 +0000544}
545
Torne (Richard Coles)cedac222014-06-03 10:58:34 +0100546TEST_F(SystemGestureEventFilterTest, DragRightNearEdgeSnaps) {
Torne (Richard Coles)f2477e02013-11-28 11:55:43 +0000547 gfx::Rect bounds(200, 150, 400, 100);
548 aura::Window* root_window = Shell::GetPrimaryRootWindow();
549 views::Widget* toplevel = views::Widget::CreateWindowWithContextAndBounds(
550 new ResizableWidgetDelegate, root_window, bounds);
551 toplevel->Show();
552
553 const int kSteps = 15;
554 const int kTouchPoints = 2;
555 gfx::Point points[kTouchPoints] = {
556 gfx::Point(bounds.x() + bounds.width() / 2, bounds.y() + 5),
557 gfx::Point(bounds.x() + bounds.width() / 2, bounds.y() + 5),
558 };
Torne (Richard Coles)a1401312014-03-18 10:20:56 +0000559 aura::Window* toplevel_window = toplevel->GetNativeWindow();
560 aura::test::EventGenerator generator(root_window, toplevel_window);
Torne (Richard Coles)f2477e02013-11-28 11:55:43 +0000561
562 // Check that dragging right snaps before reaching the screen edge.
563 gfx::Rect work_area =
564 Shell::GetScreen()->GetDisplayNearestWindow(root_window).work_area();
565 int drag_x = work_area.right() - 20 - points[0].x();
566 generator.GestureMultiFingerScroll(
567 kTouchPoints, points, 120, kSteps, drag_x, 0);
Torne (Richard Coles)a1401312014-03-18 10:20:56 +0000568 EXPECT_EQ(wm::GetDefaultRightSnappedWindowBoundsInParent(
569 toplevel_window).ToString(),
570 toplevel_window->bounds().ToString());
Torne (Richard Coles)f2477e02013-11-28 11:55:43 +0000571}
572
Torne (Richard Coles)cedac222014-06-03 10:58:34 +0100573// Tests that the window manager does not consume gesture events targeted to
Torne (Richard Coles)5d1f7b12014-02-21 12:16:55 +0000574// windows of type WINDOW_TYPE_CONTROL. This is important because the web
575// contents are often (but not always) of type WINDOW_TYPE_CONTROL.
Torne (Richard Coles)cedac222014-06-03 10:58:34 +0100576TEST_F(SystemGestureEventFilterTest,
Torne (Richard Coles)5d1f7b12014-02-21 12:16:55 +0000577 ControlWindowGetsMultiFingerGestureEvents) {
578 scoped_ptr<aura::Window> parent(
579 CreateTestWindowInShellWithBounds(gfx::Rect(100, 100)));
580
581 aura::test::EventCountDelegate delegate;
582 delegate.set_window_component(HTCLIENT);
583 scoped_ptr<aura::Window> child(new aura::Window(&delegate));
584 child->SetType(ui::wm::WINDOW_TYPE_CONTROL);
585 child->Init(aura::WINDOW_LAYER_TEXTURED);
586 parent->AddChild(child.get());
587 child->SetBounds(gfx::Rect(100, 100));
588 child->Show();
589
Torne (Richard Coles)23730a62014-03-21 14:25:57 +0000590 ui::test::TestEventHandler event_handler;
Torne (Richard Coles)5d1f7b12014-02-21 12:16:55 +0000591 aura::Env::GetInstance()->PrependPreTargetHandler(&event_handler);
592
593 GetEventGenerator().MoveMouseTo(0, 0);
594 for (int i = 1; i <= 3; ++i)
595 GetEventGenerator().PressTouchId(i);
596 for (int i = 1; i <= 3; ++i)
597 GetEventGenerator().ReleaseTouchId(i);
598 EXPECT_EQ(event_handler.num_gesture_events(),
599 delegate.GetGestureCountAndReset());
600
601 aura::Env::GetInstance()->RemovePreTargetHandler(&event_handler);
602}
603
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000604} // namespace test
605} // namespace ash