Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / content / browser / renderer_host / input / touch_handle_unittest.cc
1 // Copyright 2014 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 "content/browser/renderer_host/input/touch_handle.h"
6
7 #include "testing/gtest/include/gtest/gtest.h"
8 #include "ui/events/test/mock_motion_event.h"
9 #include "ui/gfx/geometry/rect_f.h"
10
11 using ui::test::MockMotionEvent;
12
13 namespace content {
14 namespace {
15
16 const int kDefaultTapTimeoutMs = 200;
17 const float kDefaultTapSlop = 10.f;
18 const float kDefaultDrawableSize = 10.f;
19
20 struct MockDrawableData {
21   MockDrawableData()
22       : orientation(TOUCH_HANDLE_ORIENTATION_UNDEFINED),
23         alpha(0.f),
24         enabled(false),
25         visible(false),
26         rect(0, 0, kDefaultDrawableSize, kDefaultDrawableSize) {}
27   TouchHandleOrientation orientation;
28   float alpha;
29   bool enabled;
30   bool visible;
31   gfx::RectF rect;
32 };
33
34 class MockTouchHandleDrawable : public TouchHandleDrawable {
35  public:
36   explicit MockTouchHandleDrawable(MockDrawableData* data) : data_(data) {}
37   virtual ~MockTouchHandleDrawable() {}
38
39   virtual void SetEnabled(bool enabled) OVERRIDE { data_->enabled = enabled; }
40
41   virtual void SetOrientation(TouchHandleOrientation orientation) OVERRIDE {
42     data_->orientation = orientation;
43   }
44
45   virtual void SetAlpha(float alpha) OVERRIDE { data_->alpha = alpha; }
46
47   virtual void SetFocus(const gfx::PointF& position) OVERRIDE {
48     // Anchor focus to the top left of the rect (regardless of orientation).
49     data_->rect.set_origin(position);
50   }
51
52   virtual void SetVisible(bool visible) OVERRIDE { data_->visible = visible; }
53
54   virtual bool IntersectsWith(const gfx::RectF& rect) const OVERRIDE {
55     return data_->rect.Intersects(rect);
56   }
57
58  private:
59   MockDrawableData* data_;
60 };
61
62 }  // namespace
63
64 class TouchHandleTest : public testing::Test, public TouchHandleClient {
65  public:
66   TouchHandleTest()
67       : dragging_(false),
68         dragged_(false),
69         tapped_(false),
70         needs_animate_(false) {}
71
72   virtual ~TouchHandleTest() {}
73
74   // TouchHandleClient implementation.
75   virtual void OnHandleDragBegin(const TouchHandle& handle) OVERRIDE {
76     dragging_ = true;
77   }
78
79   virtual void OnHandleDragUpdate(const TouchHandle& handle,
80                                   const gfx::PointF& new_position) OVERRIDE {
81     dragged_ = true;
82     drag_position_ = new_position;
83   }
84
85   virtual void OnHandleDragEnd(const TouchHandle& handle) OVERRIDE {
86     dragging_ = false;
87   }
88
89   virtual void OnHandleTapped(const TouchHandle& handle) OVERRIDE {
90     tapped_ = true;
91   }
92
93   virtual void SetNeedsAnimate() OVERRIDE { needs_animate_ = true; }
94
95   virtual scoped_ptr<TouchHandleDrawable> CreateDrawable() OVERRIDE {
96     return scoped_ptr<TouchHandleDrawable>(
97         new MockTouchHandleDrawable(&drawable_data_));
98   }
99
100   virtual base::TimeDelta GetTapTimeout() const OVERRIDE {
101     return base::TimeDelta::FromMilliseconds(kDefaultTapTimeoutMs);
102   }
103
104   virtual float GetTapSlop() const OVERRIDE { return kDefaultTapSlop; }
105
106   void Animate(TouchHandle& handle) {
107     needs_animate_ = false;
108     base::TimeTicks now = base::TimeTicks::Now();
109     while (handle.Animate(now))
110       now += base::TimeDelta::FromMilliseconds(16);
111   }
112
113   bool GetAndResetHandleDragged() {
114     bool dragged = dragged_;
115     dragged_ = false;
116     return dragged;
117   }
118
119   bool GetAndResetHandleTapped() {
120     bool tapped = tapped_;
121     tapped_ = false;
122     return tapped;
123   }
124
125   bool GetAndResetNeedsAnimate() {
126     bool needs_animate = needs_animate_;
127     needs_animate_ = false;
128     return needs_animate;
129   }
130
131   bool IsDragging() const { return dragging_; }
132   const gfx::PointF& DragPosition() const { return drag_position_; }
133   bool NeedsAnimate() const { return needs_animate_; }
134
135   const MockDrawableData& drawable() { return drawable_data_; }
136
137  private:
138   gfx::PointF drag_position_;
139   bool dragging_;
140   bool dragged_;
141   bool tapped_;
142   bool needs_animate_;
143
144   MockDrawableData drawable_data_;
145 };
146
147 TEST_F(TouchHandleTest, Visibility) {
148   TouchHandle handle(this, TOUCH_HANDLE_CENTER);
149   EXPECT_FALSE(drawable().visible);
150
151   handle.SetVisible(true, TouchHandle::ANIMATION_NONE);
152   EXPECT_TRUE(drawable().visible);
153   EXPECT_EQ(1.f, drawable().alpha);
154
155   handle.SetVisible(false, TouchHandle::ANIMATION_NONE);
156   EXPECT_FALSE(drawable().visible);
157
158   handle.SetVisible(true, TouchHandle::ANIMATION_NONE);
159   EXPECT_TRUE(drawable().visible);
160   EXPECT_EQ(1.f, drawable().alpha);
161 }
162
163 TEST_F(TouchHandleTest, VisibilityAnimation) {
164   TouchHandle handle(this, TOUCH_HANDLE_CENTER);
165   ASSERT_FALSE(NeedsAnimate());
166   ASSERT_FALSE(drawable().visible);
167   ASSERT_EQ(0.f, drawable().alpha);
168
169   handle.SetVisible(true, TouchHandle::ANIMATION_SMOOTH);
170   EXPECT_TRUE(NeedsAnimate());
171   EXPECT_TRUE(drawable().visible);
172   EXPECT_EQ(0.f, drawable().alpha);
173
174   Animate(handle);
175   EXPECT_TRUE(drawable().visible);
176   EXPECT_EQ(1.f, drawable().alpha);
177
178   ASSERT_FALSE(NeedsAnimate());
179   handle.SetVisible(false, TouchHandle::ANIMATION_SMOOTH);
180   EXPECT_TRUE(NeedsAnimate());
181   EXPECT_TRUE(drawable().visible);
182   EXPECT_EQ(1.f, drawable().alpha);
183
184   Animate(handle);
185   EXPECT_FALSE(drawable().visible);
186   EXPECT_EQ(0.f, drawable().alpha);
187
188   handle.SetVisible(true, TouchHandle::ANIMATION_NONE);
189   EXPECT_EQ(1.f, drawable().alpha);
190   EXPECT_FALSE(GetAndResetNeedsAnimate());
191   handle.SetVisible(false, TouchHandle::ANIMATION_SMOOTH);
192   EXPECT_EQ(1.f, drawable().alpha);
193   EXPECT_TRUE(GetAndResetNeedsAnimate());
194   handle.SetVisible(true, TouchHandle::ANIMATION_SMOOTH);
195   EXPECT_EQ(1.f, drawable().alpha);
196   EXPECT_FALSE(GetAndResetNeedsAnimate());
197 }
198
199 TEST_F(TouchHandleTest, Orientation) {
200   TouchHandle handle(this, TOUCH_HANDLE_CENTER);
201   EXPECT_EQ(TOUCH_HANDLE_CENTER, drawable().orientation);
202
203   handle.SetOrientation(TOUCH_HANDLE_LEFT);
204   EXPECT_EQ(TOUCH_HANDLE_LEFT, drawable().orientation);
205
206   handle.SetOrientation(TOUCH_HANDLE_RIGHT);
207   EXPECT_EQ(TOUCH_HANDLE_RIGHT, drawable().orientation);
208
209   handle.SetOrientation(TOUCH_HANDLE_CENTER);
210   EXPECT_EQ(TOUCH_HANDLE_CENTER, drawable().orientation);
211 }
212
213 TEST_F(TouchHandleTest, Position) {
214   TouchHandle handle(this, TOUCH_HANDLE_CENTER);
215   handle.SetVisible(true, TouchHandle::ANIMATION_NONE);
216
217   gfx::PointF position;
218   EXPECT_EQ(gfx::PointF(), drawable().rect.origin());
219
220   position = gfx::PointF(7.3f, -3.7f);
221   handle.SetPosition(position);
222   EXPECT_EQ(position, drawable().rect.origin());
223
224   position = gfx::PointF(-7.3f, 3.7f);
225   handle.SetPosition(position);
226   EXPECT_EQ(position, drawable().rect.origin());
227 }
228
229 TEST_F(TouchHandleTest, PositionNotUpdatedWhileFadingOrInvisible) {
230   TouchHandle handle(this, TOUCH_HANDLE_CENTER);
231
232   handle.SetVisible(true, TouchHandle::ANIMATION_NONE);
233   ASSERT_TRUE(drawable().visible);
234   ASSERT_FALSE(NeedsAnimate());
235
236   gfx::PointF old_position(7.3f, -3.7f);
237   handle.SetPosition(old_position);
238   ASSERT_EQ(old_position, drawable().rect.origin());
239
240   handle.SetVisible(false, TouchHandle::ANIMATION_SMOOTH);
241   ASSERT_TRUE(NeedsAnimate());
242
243   gfx::PointF new_position(3.7f, -3.7f);
244   handle.SetPosition(new_position);
245   EXPECT_EQ(old_position, drawable().rect.origin());
246   EXPECT_TRUE(NeedsAnimate());
247
248   // While the handle is fading, the new position should not take affect.
249   base::TimeTicks now = base::TimeTicks::Now();
250   while (handle.Animate(now)) {
251     EXPECT_EQ(old_position, drawable().rect.origin());
252     now += base::TimeDelta::FromMilliseconds(16);
253   }
254
255   // Even after the animation terminates, the new position will not be pushed.
256   EXPECT_EQ(old_position, drawable().rect.origin());
257
258   // As soon as the handle becomes visible, the new position will be pushed.
259   handle.SetVisible(true, TouchHandle::ANIMATION_SMOOTH);
260   EXPECT_EQ(new_position, drawable().rect.origin());
261 }
262
263 TEST_F(TouchHandleTest, Enabled) {
264   // A newly created handle defaults to enabled.
265   TouchHandle handle(this, TOUCH_HANDLE_CENTER);
266   EXPECT_TRUE(drawable().enabled);
267
268   handle.SetVisible(true, TouchHandle::ANIMATION_SMOOTH);
269   EXPECT_TRUE(GetAndResetNeedsAnimate());
270   EXPECT_EQ(0.f, drawable().alpha);
271   handle.SetEnabled(false);
272   EXPECT_FALSE(drawable().enabled);
273
274   // Dragging should not be allowed while the handle is disabled.
275   base::TimeTicks event_time = base::TimeTicks::Now();
276   const float kOffset = kDefaultDrawableSize / 2.f;
277   MockMotionEvent event(
278       MockMotionEvent::ACTION_DOWN, event_time, kOffset, kOffset);
279   EXPECT_FALSE(handle.WillHandleTouchEvent(event));
280
281   // Disabling mid-animation should cancel the animation.
282   handle.SetEnabled(true);
283   handle.SetVisible(false, TouchHandle::ANIMATION_SMOOTH);
284   EXPECT_TRUE(drawable().visible);
285   EXPECT_TRUE(GetAndResetNeedsAnimate());
286   handle.SetEnabled(false);
287   EXPECT_FALSE(drawable().enabled);
288   EXPECT_FALSE(drawable().visible);
289   EXPECT_FALSE(handle.Animate(base::TimeTicks::Now()));
290
291   // Disabling mid-drag should cancel the drag.
292   handle.SetEnabled(true);
293   handle.SetVisible(true, TouchHandle::ANIMATION_NONE);
294   EXPECT_TRUE(handle.WillHandleTouchEvent(event));
295   EXPECT_TRUE(IsDragging());
296   handle.SetEnabled(false);
297   EXPECT_FALSE(IsDragging());
298   EXPECT_FALSE(handle.WillHandleTouchEvent(event));
299 }
300
301 TEST_F(TouchHandleTest, Drag) {
302   TouchHandle handle(this, TOUCH_HANDLE_CENTER);
303
304   base::TimeTicks event_time = base::TimeTicks::Now();
305   const float kOffset = kDefaultDrawableSize / 2.f;
306
307   // The handle must be visible to trigger drag.
308   MockMotionEvent event(
309       MockMotionEvent::ACTION_DOWN, event_time, kOffset, kOffset);
310   EXPECT_FALSE(handle.WillHandleTouchEvent(event));
311   EXPECT_FALSE(IsDragging());
312   handle.SetVisible(true, TouchHandle::ANIMATION_NONE);
313
314   // ACTION_DOWN must fall within the drawable region to trigger drag.
315   event = MockMotionEvent(MockMotionEvent::ACTION_DOWN, event_time, 50, 50);
316   EXPECT_FALSE(handle.WillHandleTouchEvent(event));
317   EXPECT_FALSE(IsDragging());
318
319   // Only ACTION_DOWN will trigger drag.
320   event = MockMotionEvent(
321       MockMotionEvent::ACTION_MOVE, event_time, kOffset, kOffset);
322   EXPECT_FALSE(handle.WillHandleTouchEvent(event));
323   EXPECT_FALSE(IsDragging());
324
325   // Start the drag.
326   event = MockMotionEvent(
327       MockMotionEvent::ACTION_DOWN, event_time, kOffset, kOffset);
328   EXPECT_TRUE(handle.WillHandleTouchEvent(event));
329   EXPECT_TRUE(IsDragging());
330
331   event = MockMotionEvent(
332       MockMotionEvent::ACTION_MOVE, event_time, kOffset + 10, kOffset + 15);
333   EXPECT_TRUE(handle.WillHandleTouchEvent(event));
334   EXPECT_TRUE(GetAndResetHandleDragged());
335   EXPECT_TRUE(IsDragging());
336   EXPECT_EQ(gfx::PointF(10, 15), DragPosition());
337
338   event = MockMotionEvent(
339       MockMotionEvent::ACTION_MOVE, event_time, kOffset - 10, kOffset - 15);
340   EXPECT_TRUE(handle.WillHandleTouchEvent(event));
341   EXPECT_TRUE(GetAndResetHandleDragged());
342   EXPECT_TRUE(IsDragging());
343   EXPECT_EQ(gfx::PointF(-10, -15), DragPosition());
344
345   event = MockMotionEvent(MockMotionEvent::ACTION_UP);
346   EXPECT_TRUE(handle.WillHandleTouchEvent(event));
347   EXPECT_FALSE(GetAndResetHandleDragged());
348   EXPECT_FALSE(IsDragging());
349
350   // Non-ACTION_DOWN events after the drag has terminated should not be handled.
351   event = MockMotionEvent(MockMotionEvent::ACTION_CANCEL);
352   EXPECT_FALSE(handle.WillHandleTouchEvent(event));
353 }
354
355 TEST_F(TouchHandleTest, DragDefersOrientationChange) {
356   TouchHandle handle(this, TOUCH_HANDLE_RIGHT);
357   ASSERT_EQ(drawable().orientation, TOUCH_HANDLE_RIGHT);
358   handle.SetVisible(true, TouchHandle::ANIMATION_NONE);
359
360   MockMotionEvent event(MockMotionEvent::ACTION_DOWN);
361   EXPECT_TRUE(handle.WillHandleTouchEvent(event));
362   EXPECT_TRUE(IsDragging());
363
364   // Orientation changes will be deferred until the drag ends.
365   handle.SetOrientation(TOUCH_HANDLE_LEFT);
366   EXPECT_EQ(TOUCH_HANDLE_RIGHT, drawable().orientation);
367
368   event = MockMotionEvent(MockMotionEvent::ACTION_MOVE);
369   EXPECT_TRUE(handle.WillHandleTouchEvent(event));
370   EXPECT_TRUE(GetAndResetHandleDragged());
371   EXPECT_TRUE(IsDragging());
372   EXPECT_EQ(TOUCH_HANDLE_RIGHT, drawable().orientation);
373
374   event = MockMotionEvent(MockMotionEvent::ACTION_UP);
375   EXPECT_TRUE(handle.WillHandleTouchEvent(event));
376   EXPECT_FALSE(GetAndResetHandleDragged());
377   EXPECT_FALSE(IsDragging());
378   EXPECT_EQ(TOUCH_HANDLE_LEFT, drawable().orientation);
379 }
380
381 TEST_F(TouchHandleTest, DragDefersFade) {
382   TouchHandle handle(this, TOUCH_HANDLE_CENTER);
383   handle.SetVisible(true, TouchHandle::ANIMATION_NONE);
384
385   MockMotionEvent event(MockMotionEvent::ACTION_DOWN);
386   EXPECT_TRUE(handle.WillHandleTouchEvent(event));
387   EXPECT_TRUE(IsDragging());
388
389   // Fade will be deferred until the drag ends.
390   handle.SetVisible(false, TouchHandle::ANIMATION_SMOOTH);
391   EXPECT_FALSE(NeedsAnimate());
392   EXPECT_TRUE(drawable().visible);
393   EXPECT_EQ(1.f, drawable().alpha);
394
395   event = MockMotionEvent(MockMotionEvent::ACTION_MOVE);
396   EXPECT_TRUE(handle.WillHandleTouchEvent(event));
397   EXPECT_FALSE(NeedsAnimate());
398   EXPECT_TRUE(drawable().visible);
399
400   event = MockMotionEvent(MockMotionEvent::ACTION_UP);
401   EXPECT_TRUE(handle.WillHandleTouchEvent(event));
402   EXPECT_FALSE(IsDragging());
403   EXPECT_TRUE(NeedsAnimate());
404
405   Animate(handle);
406   EXPECT_FALSE(drawable().visible);
407   EXPECT_EQ(0.f, drawable().alpha);
408 }
409
410 TEST_F(TouchHandleTest, DragTargettingUsesTouchSize) {
411   TouchHandle handle(this, TOUCH_HANDLE_CENTER);
412   handle.SetVisible(true, TouchHandle::ANIMATION_NONE);
413
414   base::TimeTicks event_time = base::TimeTicks::Now();
415   const float kTouchSize = 24.f;
416   const float kOffset = kDefaultDrawableSize + kTouchSize / 2.001f;
417
418   MockMotionEvent event(
419       MockMotionEvent::ACTION_DOWN, event_time, kOffset, kOffset);
420   event.SetTouchMajor(0.f);
421   EXPECT_FALSE(handle.WillHandleTouchEvent(event));
422   EXPECT_FALSE(IsDragging());
423
424   event.SetTouchMajor(kTouchSize / 2.f);
425   EXPECT_FALSE(handle.WillHandleTouchEvent(event));
426   EXPECT_FALSE(IsDragging());
427
428   event.SetTouchMajor(kTouchSize);
429   EXPECT_TRUE(handle.WillHandleTouchEvent(event));
430   EXPECT_TRUE(IsDragging());
431
432   event.SetTouchMajor(kTouchSize * 2.f);
433   EXPECT_TRUE(handle.WillHandleTouchEvent(event));
434   EXPECT_TRUE(IsDragging());
435
436   // Ensure a touch size of 0 can still register a hit.
437   event = MockMotionEvent(MockMotionEvent::ACTION_DOWN,
438                           event_time,
439                           kDefaultDrawableSize / 2.f,
440                           kDefaultDrawableSize / 2.f);
441   event.SetTouchMajor(0);
442   EXPECT_TRUE(handle.WillHandleTouchEvent(event));
443   EXPECT_TRUE(IsDragging());
444 }
445
446 TEST_F(TouchHandleTest, Tap) {
447   TouchHandle handle(this, TOUCH_HANDLE_CENTER);
448   handle.SetVisible(true, TouchHandle::ANIMATION_NONE);
449
450   base::TimeTicks event_time = base::TimeTicks::Now();
451
452   // ACTION_CANCEL shouldn't trigger a tap.
453   MockMotionEvent event(MockMotionEvent::ACTION_DOWN, event_time, 0, 0);
454   EXPECT_TRUE(handle.WillHandleTouchEvent(event));
455   event_time += base::TimeDelta::FromMilliseconds(50);
456   event = MockMotionEvent(MockMotionEvent::ACTION_CANCEL, event_time, 0, 0);
457   EXPECT_TRUE(handle.WillHandleTouchEvent(event));
458   EXPECT_FALSE(GetAndResetHandleTapped());
459
460   // Long press shouldn't trigger a tap.
461   event = MockMotionEvent(MockMotionEvent::ACTION_DOWN, event_time, 0, 0);
462   EXPECT_TRUE(handle.WillHandleTouchEvent(event));
463   event_time += 2 * GetTapTimeout();
464   event = MockMotionEvent(MockMotionEvent::ACTION_UP, event_time, 0, 0);
465   EXPECT_TRUE(handle.WillHandleTouchEvent(event));
466   EXPECT_FALSE(GetAndResetHandleTapped());
467
468   // Only a brief tap within the slop region should trigger a tap.
469   event = MockMotionEvent(MockMotionEvent::ACTION_DOWN, event_time, 0, 0);
470   EXPECT_TRUE(handle.WillHandleTouchEvent(event));
471   event_time += GetTapTimeout() / 2;
472   event = MockMotionEvent(
473       MockMotionEvent::ACTION_MOVE, event_time, kDefaultTapSlop / 2.f, 0);
474   EXPECT_TRUE(handle.WillHandleTouchEvent(event));
475   event = MockMotionEvent(
476       MockMotionEvent::ACTION_UP, event_time, kDefaultTapSlop / 2.f, 0);
477   EXPECT_TRUE(handle.WillHandleTouchEvent(event));
478   EXPECT_TRUE(GetAndResetHandleTapped());
479
480   // Moving beyond the slop region shouldn't trigger a tap.
481   event = MockMotionEvent(MockMotionEvent::ACTION_DOWN, event_time, 0, 0);
482   EXPECT_TRUE(handle.WillHandleTouchEvent(event));
483   event_time += GetTapTimeout() / 2;
484   event = MockMotionEvent(
485       MockMotionEvent::ACTION_MOVE, event_time, kDefaultTapSlop * 2.f, 0);
486   EXPECT_TRUE(handle.WillHandleTouchEvent(event));
487   event = MockMotionEvent(
488       MockMotionEvent::ACTION_UP, event_time, kDefaultTapSlop * 2.f, 0);
489   EXPECT_TRUE(handle.WillHandleTouchEvent(event));
490   EXPECT_FALSE(GetAndResetHandleTapped());
491 }
492
493 }  // namespace content