Drive: Add BatchableRequest subclass.
[chromium-blink-merge.git] / ui / touch_selection / touch_handle_unittest.cc
blobe86c3d3881b245953f17aa8621166e934718b1dc
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"
10 #include "ui/touch_selection/touch_handle_orientation.h"
12 using ui::test::MockMotionEvent;
14 namespace ui {
15 namespace {
17 const int kDefaultTapTimeoutMs = 200;
18 const float kDefaultTapSlop = 10.f;
19 const float kDefaultDrawableSize = 10.f;
21 struct MockDrawableData {
22 MockDrawableData()
23 : orientation(TouchHandleOrientation::UNDEFINED),
24 alpha(0.f),
25 enabled(false),
26 visible(false),
27 rect(0, 0, kDefaultDrawableSize, kDefaultDrawableSize) {}
28 TouchHandleOrientation orientation;
29 float alpha;
30 bool enabled;
31 bool visible;
32 gfx::RectF rect;
35 class MockTouchHandleDrawable : public TouchHandleDrawable {
36 public:
37 explicit MockTouchHandleDrawable(MockDrawableData* data) : data_(data) {}
38 ~MockTouchHandleDrawable() override {}
40 void SetEnabled(bool enabled) override { data_->enabled = enabled; }
42 void SetOrientation(TouchHandleOrientation orientation) override {
43 data_->orientation = orientation;
46 void SetAlpha(float alpha) override {
47 data_->alpha = alpha;
48 data_->visible = alpha > 0;
51 void SetFocus(const gfx::PointF& position) override {
52 // Anchor focus to the top left of the rect (regardless of orientation).
53 data_->rect.set_origin(position);
56 gfx::RectF GetVisibleBounds() const override {
57 return data_->rect;
60 private:
61 MockDrawableData* data_;
64 } // namespace
66 class TouchHandleTest : public testing::Test, public TouchHandleClient {
67 public:
68 TouchHandleTest()
69 : dragging_(false),
70 dragged_(false),
71 tapped_(false),
72 needs_animate_(false) {}
74 ~TouchHandleTest() override {}
76 // TouchHandleClient implementation.
77 void OnHandleDragBegin(const TouchHandle& handle) override {
78 dragging_ = true;
81 void OnHandleDragUpdate(const TouchHandle& handle,
82 const gfx::PointF& new_position) override {
83 dragged_ = true;
84 drag_position_ = new_position;
87 void OnHandleDragEnd(const TouchHandle& handle) override {
88 dragging_ = false;
91 void OnHandleTapped(const TouchHandle& handle) override { tapped_ = true; }
93 void SetNeedsAnimate() override { needs_animate_ = true; }
95 scoped_ptr<TouchHandleDrawable> CreateDrawable() override {
96 return make_scoped_ptr(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, TouchHandleOrientation::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, TouchHandleOrientation::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, TouchHandleOrientation::CENTER);
200 EXPECT_EQ(TouchHandleOrientation::CENTER, drawable().orientation);
202 handle.SetOrientation(TouchHandleOrientation::LEFT);
203 EXPECT_EQ(TouchHandleOrientation::LEFT, drawable().orientation);
205 handle.SetOrientation(TouchHandleOrientation::RIGHT);
206 EXPECT_EQ(TouchHandleOrientation::RIGHT, drawable().orientation);
208 handle.SetOrientation(TouchHandleOrientation::CENTER);
209 EXPECT_EQ(TouchHandleOrientation::CENTER, drawable().orientation);
212 TEST_F(TouchHandleTest, Position) {
213 TouchHandle handle(this, TouchHandleOrientation::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, TouchHandleOrientation::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, TouchHandleOrientation::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, TouchHandleOrientation::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, TouchHandleOrientation::RIGHT);
356 ASSERT_EQ(drawable().orientation, TouchHandleOrientation::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(TouchHandleOrientation::LEFT);
365 EXPECT_EQ(TouchHandleOrientation::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(TouchHandleOrientation::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(TouchHandleOrientation::LEFT, drawable().orientation);
380 TEST_F(TouchHandleTest, DragDefersFade) {
381 TouchHandle handle(this, TouchHandleOrientation::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, TouchHandleOrientation::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, TouchHandleOrientation::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