win: fix ScreenWin::GetDisplayNearestPoint implementation
[chromium-blink-merge.git] / ui / touch_selection / touch_handle_unittest.cc
blobb266fdb9b497467314026348a78c49cb767baa65
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.
5 #include "ui/touch_selection/touch_handle.h"
7 #include "testing/gtest/include/gtest/gtest.h"
8 #include "ui/events/test/motion_event_test_utils.h"
9 #include "ui/gfx/geometry/rect_f.h"
11 using ui::test::MockMotionEvent;
13 namespace ui {
14 namespace {
16 const int kDefaultTapTimeoutMs = 200;
17 const float kDefaultTapSlop = 10.f;
18 const float kDefaultDrawableSize = 10.f;
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;
34 class MockTouchHandleDrawable : public TouchHandleDrawable {
35 public:
36 explicit MockTouchHandleDrawable(MockDrawableData* data) : data_(data) {}
37 ~MockTouchHandleDrawable() override {}
39 void SetEnabled(bool enabled) override { data_->enabled = enabled; }
41 void SetOrientation(TouchHandleOrientation orientation) override {
42 data_->orientation = orientation;
45 void SetAlpha(float alpha) override {
46 data_->alpha = alpha;
47 data_->visible = alpha > 0;
50 void SetFocus(const gfx::PointF& position) override {
51 // Anchor focus to the top left of the rect (regardless of orientation).
52 data_->rect.set_origin(position);
55 gfx::RectF GetVisibleBounds() const override {
56 return data_->rect;
59 private:
60 MockDrawableData* data_;
63 } // namespace
65 class TouchHandleTest : public testing::Test, public TouchHandleClient {
66 public:
67 TouchHandleTest()
68 : dragging_(false),
69 dragged_(false),
70 tapped_(false),
71 needs_animate_(false) {}
73 ~TouchHandleTest() override {}
75 // TouchHandleClient implementation.
76 void OnHandleDragBegin(const TouchHandle& handle) override {
77 dragging_ = true;
80 void OnHandleDragUpdate(const TouchHandle& handle,
81 const gfx::PointF& new_position) override {
82 dragged_ = true;
83 drag_position_ = new_position;
86 void OnHandleDragEnd(const TouchHandle& handle) override {
87 dragging_ = false;
90 void OnHandleTapped(const TouchHandle& handle) override { tapped_ = true; }
92 void SetNeedsAnimate() override { needs_animate_ = true; }
94 scoped_ptr<TouchHandleDrawable> CreateDrawable() override {
95 return scoped_ptr<TouchHandleDrawable>(
96 new MockTouchHandleDrawable(&drawable_data_));
99 base::TimeDelta GetTapTimeout() const override {
100 return base::TimeDelta::FromMilliseconds(kDefaultTapTimeoutMs);
103 float GetTapSlop() const override { return kDefaultTapSlop; }
105 void Animate(TouchHandle& handle) {
106 needs_animate_ = false;
107 base::TimeTicks now = base::TimeTicks::Now();
108 while (handle.Animate(now))
109 now += base::TimeDelta::FromMilliseconds(16);
112 bool GetAndResetHandleDragged() {
113 bool dragged = dragged_;
114 dragged_ = false;
115 return dragged;
118 bool GetAndResetHandleTapped() {
119 bool tapped = tapped_;
120 tapped_ = false;
121 return tapped;
124 bool GetAndResetNeedsAnimate() {
125 bool needs_animate = needs_animate_;
126 needs_animate_ = false;
127 return needs_animate;
130 bool IsDragging() const { return dragging_; }
131 const gfx::PointF& DragPosition() const { return drag_position_; }
132 bool NeedsAnimate() const { return needs_animate_; }
134 const MockDrawableData& drawable() { return drawable_data_; }
136 private:
137 gfx::PointF drag_position_;
138 bool dragging_;
139 bool dragged_;
140 bool tapped_;
141 bool needs_animate_;
143 MockDrawableData drawable_data_;
146 TEST_F(TouchHandleTest, Visibility) {
147 TouchHandle handle(this, TOUCH_HANDLE_CENTER);
148 EXPECT_FALSE(drawable().visible);
150 handle.SetVisible(true, TouchHandle::ANIMATION_NONE);
151 EXPECT_TRUE(drawable().visible);
152 EXPECT_EQ(1.f, drawable().alpha);
154 handle.SetVisible(false, TouchHandle::ANIMATION_NONE);
155 EXPECT_FALSE(drawable().visible);
157 handle.SetVisible(true, TouchHandle::ANIMATION_NONE);
158 EXPECT_TRUE(drawable().visible);
159 EXPECT_EQ(1.f, drawable().alpha);
162 TEST_F(TouchHandleTest, VisibilityAnimation) {
163 TouchHandle handle(this, TOUCH_HANDLE_CENTER);
164 ASSERT_FALSE(NeedsAnimate());
165 ASSERT_FALSE(drawable().visible);
166 ASSERT_EQ(0.f, drawable().alpha);
168 handle.SetVisible(true, TouchHandle::ANIMATION_SMOOTH);
169 EXPECT_TRUE(NeedsAnimate());
170 EXPECT_FALSE(drawable().visible);
171 EXPECT_EQ(0.f, drawable().alpha);
173 Animate(handle);
174 EXPECT_TRUE(drawable().visible);
175 EXPECT_EQ(1.f, drawable().alpha);
177 ASSERT_FALSE(NeedsAnimate());
178 handle.SetVisible(false, TouchHandle::ANIMATION_SMOOTH);
179 EXPECT_TRUE(NeedsAnimate());
180 EXPECT_TRUE(drawable().visible);
181 EXPECT_EQ(1.f, drawable().alpha);
183 Animate(handle);
184 EXPECT_FALSE(drawable().visible);
185 EXPECT_EQ(0.f, drawable().alpha);
187 handle.SetVisible(true, TouchHandle::ANIMATION_NONE);
188 EXPECT_EQ(1.f, drawable().alpha);
189 EXPECT_FALSE(GetAndResetNeedsAnimate());
190 handle.SetVisible(false, TouchHandle::ANIMATION_SMOOTH);
191 EXPECT_EQ(1.f, drawable().alpha);
192 EXPECT_TRUE(GetAndResetNeedsAnimate());
193 handle.SetVisible(true, TouchHandle::ANIMATION_SMOOTH);
194 EXPECT_EQ(1.f, drawable().alpha);
195 EXPECT_FALSE(GetAndResetNeedsAnimate());
198 TEST_F(TouchHandleTest, Orientation) {
199 TouchHandle handle(this, TOUCH_HANDLE_CENTER);
200 EXPECT_EQ(TOUCH_HANDLE_CENTER, drawable().orientation);
202 handle.SetOrientation(TOUCH_HANDLE_LEFT);
203 EXPECT_EQ(TOUCH_HANDLE_LEFT, drawable().orientation);
205 handle.SetOrientation(TOUCH_HANDLE_RIGHT);
206 EXPECT_EQ(TOUCH_HANDLE_RIGHT, drawable().orientation);
208 handle.SetOrientation(TOUCH_HANDLE_CENTER);
209 EXPECT_EQ(TOUCH_HANDLE_CENTER, drawable().orientation);
212 TEST_F(TouchHandleTest, Position) {
213 TouchHandle handle(this, TOUCH_HANDLE_CENTER);
214 handle.SetVisible(true, TouchHandle::ANIMATION_NONE);
216 gfx::PointF position;
217 EXPECT_EQ(gfx::PointF(), drawable().rect.origin());
219 position = gfx::PointF(7.3f, -3.7f);
220 handle.SetPosition(position);
221 EXPECT_EQ(position, drawable().rect.origin());
223 position = gfx::PointF(-7.3f, 3.7f);
224 handle.SetPosition(position);
225 EXPECT_EQ(position, drawable().rect.origin());
228 TEST_F(TouchHandleTest, PositionNotUpdatedWhileFadingOrInvisible) {
229 TouchHandle handle(this, TOUCH_HANDLE_CENTER);
231 handle.SetVisible(true, TouchHandle::ANIMATION_NONE);
232 ASSERT_TRUE(drawable().visible);
233 ASSERT_FALSE(NeedsAnimate());
235 gfx::PointF old_position(7.3f, -3.7f);
236 handle.SetPosition(old_position);
237 ASSERT_EQ(old_position, drawable().rect.origin());
239 handle.SetVisible(false, TouchHandle::ANIMATION_SMOOTH);
240 ASSERT_TRUE(NeedsAnimate());
242 gfx::PointF new_position(3.7f, -3.7f);
243 handle.SetPosition(new_position);
244 EXPECT_EQ(old_position, drawable().rect.origin());
245 EXPECT_TRUE(NeedsAnimate());
247 // While the handle is fading, the new position should not take affect.
248 base::TimeTicks now = base::TimeTicks::Now();
249 while (handle.Animate(now)) {
250 EXPECT_EQ(old_position, drawable().rect.origin());
251 now += base::TimeDelta::FromMilliseconds(16);
254 // Even after the animation terminates, the new position will not be pushed.
255 EXPECT_EQ(old_position, drawable().rect.origin());
257 // As soon as the handle becomes visible, the new position will be pushed.
258 handle.SetVisible(true, TouchHandle::ANIMATION_SMOOTH);
259 EXPECT_EQ(new_position, drawable().rect.origin());
262 TEST_F(TouchHandleTest, Enabled) {
263 // A newly created handle defaults to enabled.
264 TouchHandle handle(this, TOUCH_HANDLE_CENTER);
265 EXPECT_TRUE(drawable().enabled);
267 handle.SetVisible(true, TouchHandle::ANIMATION_SMOOTH);
268 EXPECT_TRUE(GetAndResetNeedsAnimate());
269 EXPECT_EQ(0.f, drawable().alpha);
270 handle.SetEnabled(false);
271 EXPECT_FALSE(drawable().enabled);
273 // Dragging should not be allowed while the handle is disabled.
274 base::TimeTicks event_time = base::TimeTicks::Now();
275 const float kOffset = kDefaultDrawableSize / 2.f;
276 MockMotionEvent event(
277 MockMotionEvent::ACTION_DOWN, event_time, kOffset, kOffset);
278 EXPECT_FALSE(handle.WillHandleTouchEvent(event));
280 // Disabling mid-animation should cancel the animation.
281 handle.SetEnabled(true);
282 handle.SetVisible(false, TouchHandle::ANIMATION_SMOOTH);
283 EXPECT_TRUE(drawable().visible);
284 EXPECT_TRUE(GetAndResetNeedsAnimate());
285 handle.SetEnabled(false);
286 EXPECT_FALSE(drawable().enabled);
287 EXPECT_FALSE(drawable().visible);
288 EXPECT_FALSE(handle.Animate(base::TimeTicks::Now()));
290 // Disabling mid-drag should cancel the drag.
291 handle.SetEnabled(true);
292 handle.SetVisible(true, TouchHandle::ANIMATION_NONE);
293 EXPECT_TRUE(handle.WillHandleTouchEvent(event));
294 EXPECT_TRUE(IsDragging());
295 handle.SetEnabled(false);
296 EXPECT_FALSE(IsDragging());
297 EXPECT_FALSE(handle.WillHandleTouchEvent(event));
300 TEST_F(TouchHandleTest, Drag) {
301 TouchHandle handle(this, TOUCH_HANDLE_CENTER);
303 base::TimeTicks event_time = base::TimeTicks::Now();
304 const float kOffset = kDefaultDrawableSize / 2.f;
306 // The handle must be visible to trigger drag.
307 MockMotionEvent event(
308 MockMotionEvent::ACTION_DOWN, event_time, kOffset, kOffset);
309 EXPECT_FALSE(handle.WillHandleTouchEvent(event));
310 EXPECT_FALSE(IsDragging());
311 handle.SetVisible(true, TouchHandle::ANIMATION_NONE);
313 // ACTION_DOWN must fall within the drawable region to trigger drag.
314 event = MockMotionEvent(MockMotionEvent::ACTION_DOWN, event_time, 50, 50);
315 EXPECT_FALSE(handle.WillHandleTouchEvent(event));
316 EXPECT_FALSE(IsDragging());
318 // Only ACTION_DOWN will trigger drag.
319 event = MockMotionEvent(
320 MockMotionEvent::ACTION_MOVE, event_time, kOffset, kOffset);
321 EXPECT_FALSE(handle.WillHandleTouchEvent(event));
322 EXPECT_FALSE(IsDragging());
324 // Start the drag.
325 event = MockMotionEvent(
326 MockMotionEvent::ACTION_DOWN, event_time, kOffset, kOffset);
327 EXPECT_TRUE(handle.WillHandleTouchEvent(event));
328 EXPECT_TRUE(IsDragging());
330 event = MockMotionEvent(
331 MockMotionEvent::ACTION_MOVE, event_time, kOffset + 10, kOffset + 15);
332 EXPECT_TRUE(handle.WillHandleTouchEvent(event));
333 EXPECT_TRUE(GetAndResetHandleDragged());
334 EXPECT_TRUE(IsDragging());
335 EXPECT_EQ(gfx::PointF(10, 15), DragPosition());
337 event = MockMotionEvent(
338 MockMotionEvent::ACTION_MOVE, event_time, kOffset - 10, kOffset - 15);
339 EXPECT_TRUE(handle.WillHandleTouchEvent(event));
340 EXPECT_TRUE(GetAndResetHandleDragged());
341 EXPECT_TRUE(IsDragging());
342 EXPECT_EQ(gfx::PointF(-10, -15), DragPosition());
344 event = MockMotionEvent(MockMotionEvent::ACTION_UP);
345 EXPECT_TRUE(handle.WillHandleTouchEvent(event));
346 EXPECT_FALSE(GetAndResetHandleDragged());
347 EXPECT_FALSE(IsDragging());
349 // Non-ACTION_DOWN events after the drag has terminated should not be handled.
350 event = MockMotionEvent(MockMotionEvent::ACTION_CANCEL);
351 EXPECT_FALSE(handle.WillHandleTouchEvent(event));
354 TEST_F(TouchHandleTest, DragDefersOrientationChange) {
355 TouchHandle handle(this, TOUCH_HANDLE_RIGHT);
356 ASSERT_EQ(drawable().orientation, TOUCH_HANDLE_RIGHT);
357 handle.SetVisible(true, TouchHandle::ANIMATION_NONE);
359 MockMotionEvent event(MockMotionEvent::ACTION_DOWN);
360 EXPECT_TRUE(handle.WillHandleTouchEvent(event));
361 EXPECT_TRUE(IsDragging());
363 // Orientation changes will be deferred until the drag ends.
364 handle.SetOrientation(TOUCH_HANDLE_LEFT);
365 EXPECT_EQ(TOUCH_HANDLE_RIGHT, drawable().orientation);
367 event = MockMotionEvent(MockMotionEvent::ACTION_MOVE);
368 EXPECT_TRUE(handle.WillHandleTouchEvent(event));
369 EXPECT_TRUE(GetAndResetHandleDragged());
370 EXPECT_TRUE(IsDragging());
371 EXPECT_EQ(TOUCH_HANDLE_RIGHT, drawable().orientation);
373 event = MockMotionEvent(MockMotionEvent::ACTION_UP);
374 EXPECT_TRUE(handle.WillHandleTouchEvent(event));
375 EXPECT_FALSE(GetAndResetHandleDragged());
376 EXPECT_FALSE(IsDragging());
377 EXPECT_EQ(TOUCH_HANDLE_LEFT, drawable().orientation);
380 TEST_F(TouchHandleTest, DragDefersFade) {
381 TouchHandle handle(this, TOUCH_HANDLE_CENTER);
382 handle.SetVisible(true, TouchHandle::ANIMATION_NONE);
384 MockMotionEvent event(MockMotionEvent::ACTION_DOWN);
385 EXPECT_TRUE(handle.WillHandleTouchEvent(event));
386 EXPECT_TRUE(IsDragging());
388 // Fade will be deferred until the drag ends.
389 handle.SetVisible(false, TouchHandle::ANIMATION_SMOOTH);
390 EXPECT_FALSE(NeedsAnimate());
391 EXPECT_TRUE(drawable().visible);
392 EXPECT_EQ(1.f, drawable().alpha);
394 event = MockMotionEvent(MockMotionEvent::ACTION_MOVE);
395 EXPECT_TRUE(handle.WillHandleTouchEvent(event));
396 EXPECT_FALSE(NeedsAnimate());
397 EXPECT_TRUE(drawable().visible);
399 event = MockMotionEvent(MockMotionEvent::ACTION_UP);
400 EXPECT_TRUE(handle.WillHandleTouchEvent(event));
401 EXPECT_FALSE(IsDragging());
402 EXPECT_TRUE(NeedsAnimate());
404 Animate(handle);
405 EXPECT_FALSE(drawable().visible);
406 EXPECT_EQ(0.f, drawable().alpha);
409 TEST_F(TouchHandleTest, DragTargettingUsesTouchSize) {
410 TouchHandle handle(this, TOUCH_HANDLE_CENTER);
411 handle.SetVisible(true, TouchHandle::ANIMATION_NONE);
413 base::TimeTicks event_time = base::TimeTicks::Now();
414 const float kTouchSize = 24.f;
415 const float kOffset = kDefaultDrawableSize + kTouchSize / 2.001f;
417 MockMotionEvent event(
418 MockMotionEvent::ACTION_DOWN, event_time, kOffset, 0);
419 event.SetTouchMajor(0.f);
420 EXPECT_FALSE(handle.WillHandleTouchEvent(event));
421 EXPECT_FALSE(IsDragging());
423 event.SetTouchMajor(kTouchSize / 2.f);
424 EXPECT_FALSE(handle.WillHandleTouchEvent(event));
425 EXPECT_FALSE(IsDragging());
427 event.SetTouchMajor(kTouchSize);
428 EXPECT_TRUE(handle.WillHandleTouchEvent(event));
429 EXPECT_TRUE(IsDragging());
431 event.SetTouchMajor(kTouchSize * 2.f);
432 EXPECT_TRUE(handle.WillHandleTouchEvent(event));
433 EXPECT_TRUE(IsDragging());
435 // The touch hit test region should be circular.
436 event = MockMotionEvent(
437 MockMotionEvent::ACTION_DOWN, event_time, kOffset, kOffset);
438 event.SetTouchMajor(kTouchSize);
439 EXPECT_FALSE(handle.WillHandleTouchEvent(event));
440 EXPECT_FALSE(IsDragging());
442 event.SetTouchMajor(kTouchSize * std::sqrt(2.f) - 0.1f);
443 EXPECT_FALSE(handle.WillHandleTouchEvent(event));
444 EXPECT_FALSE(IsDragging());
446 event.SetTouchMajor(kTouchSize * std::sqrt(2.f) + 0.1f);
447 EXPECT_TRUE(handle.WillHandleTouchEvent(event));
448 EXPECT_TRUE(IsDragging());
450 // Ensure a touch size of 0 can still register a hit.
451 event = MockMotionEvent(MockMotionEvent::ACTION_DOWN,
452 event_time,
453 kDefaultDrawableSize / 2.f,
454 kDefaultDrawableSize / 2.f);
455 event.SetTouchMajor(0);
456 EXPECT_TRUE(handle.WillHandleTouchEvent(event));
457 EXPECT_TRUE(IsDragging());
460 TEST_F(TouchHandleTest, Tap) {
461 TouchHandle handle(this, TOUCH_HANDLE_CENTER);
462 handle.SetVisible(true, TouchHandle::ANIMATION_NONE);
464 base::TimeTicks event_time = base::TimeTicks::Now();
466 // ACTION_CANCEL shouldn't trigger a tap.
467 MockMotionEvent event(MockMotionEvent::ACTION_DOWN, event_time, 0, 0);
468 EXPECT_TRUE(handle.WillHandleTouchEvent(event));
469 event_time += base::TimeDelta::FromMilliseconds(50);
470 event = MockMotionEvent(MockMotionEvent::ACTION_CANCEL, event_time, 0, 0);
471 EXPECT_TRUE(handle.WillHandleTouchEvent(event));
472 EXPECT_FALSE(GetAndResetHandleTapped());
474 // Long press shouldn't trigger a tap.
475 event = MockMotionEvent(MockMotionEvent::ACTION_DOWN, event_time, 0, 0);
476 EXPECT_TRUE(handle.WillHandleTouchEvent(event));
477 event_time += 2 * GetTapTimeout();
478 event = MockMotionEvent(MockMotionEvent::ACTION_UP, event_time, 0, 0);
479 EXPECT_TRUE(handle.WillHandleTouchEvent(event));
480 EXPECT_FALSE(GetAndResetHandleTapped());
482 // Only a brief tap within the slop region should trigger a tap.
483 event = MockMotionEvent(MockMotionEvent::ACTION_DOWN, event_time, 0, 0);
484 EXPECT_TRUE(handle.WillHandleTouchEvent(event));
485 event_time += GetTapTimeout() / 2;
486 event = MockMotionEvent(
487 MockMotionEvent::ACTION_MOVE, event_time, kDefaultTapSlop / 2.f, 0);
488 EXPECT_TRUE(handle.WillHandleTouchEvent(event));
489 event = MockMotionEvent(
490 MockMotionEvent::ACTION_UP, event_time, kDefaultTapSlop / 2.f, 0);
491 EXPECT_TRUE(handle.WillHandleTouchEvent(event));
492 EXPECT_TRUE(GetAndResetHandleTapped());
494 // Moving beyond the slop region shouldn't trigger a tap.
495 event = MockMotionEvent(MockMotionEvent::ACTION_DOWN, event_time, 0, 0);
496 EXPECT_TRUE(handle.WillHandleTouchEvent(event));
497 event_time += GetTapTimeout() / 2;
498 event = MockMotionEvent(
499 MockMotionEvent::ACTION_MOVE, event_time, kDefaultTapSlop * 2.f, 0);
500 EXPECT_TRUE(handle.WillHandleTouchEvent(event));
501 event = MockMotionEvent(
502 MockMotionEvent::ACTION_UP, event_time, kDefaultTapSlop * 2.f, 0);
503 EXPECT_TRUE(handle.WillHandleTouchEvent(event));
504 EXPECT_FALSE(GetAndResetHandleTapped());
507 } // namespace ui