OLD | NEW |
---|---|
(Empty) | |
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 float kDefaultDrawableSize = 10.f; | |
17 | |
18 struct MockDrawableData { | |
19 MockDrawableData() | |
20 : orientation(TOUCH_HANDLE_ORIENTATION_UNDEFINED), | |
21 alpha(0.f), | |
22 enabled(false), | |
23 visible(false), | |
24 rect(0, 0, kDefaultDrawableSize, kDefaultDrawableSize) {} | |
25 TouchHandleOrientation orientation; | |
26 float alpha; | |
27 bool enabled; | |
28 bool visible; | |
29 gfx::RectF rect; | |
30 }; | |
31 | |
32 class MockTouchHandleDrawable : public TouchHandleDrawable { | |
33 public: | |
34 explicit MockTouchHandleDrawable(MockDrawableData* data) : data_(data) {} | |
35 virtual ~MockTouchHandleDrawable() {} | |
36 | |
37 virtual void SetEnabled(bool enabled) OVERRIDE { | |
38 data_->enabled = enabled; | |
39 } | |
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 ContainsPoint(const gfx::PointF& point) const OVERRIDE { | |
55 return data_->rect.Contains(point); | |
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 void Animate(TouchHandle& handle) { | |
101 needs_animate_ = false; | |
102 base::TimeTicks now = base::TimeTicks::Now(); | |
103 while (handle.Animate(now)) | |
104 now += base::TimeDelta::FromMilliseconds(16); | |
105 } | |
106 | |
107 bool GetAndResetHandleDragged() { | |
108 bool dragged = dragged_; | |
109 dragged_ = false; | |
110 return dragged; | |
111 } | |
112 | |
113 bool GetAndResetHandleTapped() { | |
114 bool tapped = tapped_; | |
115 tapped_ = false; | |
116 return tapped; | |
117 } | |
118 | |
119 bool GetAndResetNeedsAnimate() { | |
120 bool needs_animate = needs_animate_; | |
121 needs_animate_ = false; | |
122 return needs_animate; | |
123 } | |
124 | |
125 bool IsDragging() const { return dragging_; } | |
126 const gfx::PointF& DragPosition() const { return drag_position_; } | |
127 bool NeedsAnimate() const { return needs_animate_; } | |
128 | |
129 const MockDrawableData& drawable() { return drawable_data_; } | |
130 | |
131 private: | |
132 gfx::PointF drag_position_; | |
133 bool dragging_; | |
134 bool dragged_; | |
135 bool tapped_; | |
136 bool needs_animate_; | |
137 | |
138 MockDrawableData drawable_data_; | |
139 }; | |
140 | |
141 TEST_F(TouchHandleTest, Visibility) { | |
142 TouchHandle handle(this, TOUCH_HANDLE_CENTER); | |
143 EXPECT_FALSE(drawable().visible); | |
144 | |
145 handle.SetVisible(true, TouchHandle::ANIMATION_NONE); | |
146 EXPECT_TRUE(drawable().visible); | |
147 EXPECT_EQ(1.f, drawable().alpha); | |
148 | |
149 handle.SetVisible(false, TouchHandle::ANIMATION_NONE); | |
150 EXPECT_FALSE(drawable().visible); | |
151 | |
152 handle.SetVisible(true, TouchHandle::ANIMATION_NONE); | |
153 EXPECT_TRUE(drawable().visible); | |
154 EXPECT_EQ(1.f, drawable().alpha); | |
155 } | |
156 | |
157 TEST_F(TouchHandleTest, VisibilityAnimation) { | |
158 TouchHandle handle(this, TOUCH_HANDLE_CENTER); | |
159 ASSERT_FALSE(NeedsAnimate()); | |
160 ASSERT_FALSE(drawable().visible); | |
161 ASSERT_EQ(0.f, drawable().alpha); | |
162 | |
163 handle.SetVisible(true, TouchHandle::ANIMATION_SMOOTH); | |
164 EXPECT_TRUE(NeedsAnimate()); | |
165 EXPECT_TRUE(drawable().visible); | |
166 EXPECT_EQ(0.f, drawable().alpha); | |
167 | |
168 Animate(handle); | |
169 EXPECT_TRUE(drawable().visible); | |
170 EXPECT_EQ(1.f, drawable().alpha); | |
171 | |
172 ASSERT_FALSE(NeedsAnimate()); | |
173 handle.SetVisible(false, TouchHandle::ANIMATION_SMOOTH); | |
174 EXPECT_TRUE(NeedsAnimate()); | |
175 EXPECT_TRUE(drawable().visible); | |
176 EXPECT_EQ(1.f, drawable().alpha); | |
177 | |
178 Animate(handle); | |
179 EXPECT_FALSE(drawable().visible); | |
180 EXPECT_EQ(0.f, drawable().alpha); | |
181 } | |
182 | |
183 TEST_F(TouchHandleTest, Orientation) { | |
184 TouchHandle handle(this, TOUCH_HANDLE_CENTER); | |
185 EXPECT_EQ(TOUCH_HANDLE_CENTER, drawable().orientation); | |
186 | |
187 handle.SetOrientation(TOUCH_HANDLE_LEFT); | |
188 EXPECT_EQ(TOUCH_HANDLE_LEFT, drawable().orientation); | |
189 | |
190 handle.SetOrientation(TOUCH_HANDLE_RIGHT); | |
191 EXPECT_EQ(TOUCH_HANDLE_RIGHT, drawable().orientation); | |
192 | |
193 handle.SetOrientation(TOUCH_HANDLE_CENTER); | |
194 EXPECT_EQ(TOUCH_HANDLE_CENTER, drawable().orientation); | |
195 } | |
196 | |
197 TEST_F(TouchHandleTest, Position) { | |
198 TouchHandle handle(this, TOUCH_HANDLE_CENTER); | |
199 handle.SetVisible(true, TouchHandle::ANIMATION_NONE); | |
200 | |
201 gfx::PointF position; | |
202 EXPECT_EQ(gfx::PointF(), drawable().rect.origin()); | |
203 | |
204 position = gfx::PointF(7.3, -3.7); | |
205 handle.SetPosition(position); | |
206 EXPECT_EQ(position, drawable().rect.origin()); | |
207 | |
208 position = gfx::PointF(-7.3, 3.7); | |
209 handle.SetPosition(position); | |
210 EXPECT_EQ(position, drawable().rect.origin()); | |
211 } | |
212 | |
213 TEST_F(TouchHandleTest, PositionNotUpdatedWhileFadingOrInvisible) { | |
214 TouchHandle handle(this, TOUCH_HANDLE_CENTER); | |
215 | |
216 handle.SetVisible(true, TouchHandle::ANIMATION_NONE); | |
217 ASSERT_TRUE(drawable().visible); | |
218 ASSERT_FALSE(NeedsAnimate()); | |
219 | |
220 gfx::PointF old_position(7.3, -3.7); | |
221 handle.SetPosition(old_position); | |
222 ASSERT_EQ(old_position, drawable().rect.origin()); | |
223 | |
224 handle.SetVisible(false, TouchHandle::ANIMATION_SMOOTH); | |
225 ASSERT_TRUE(NeedsAnimate()); | |
226 | |
227 gfx::PointF new_position(3.7, -3.7); | |
228 handle.SetPosition(new_position); | |
229 EXPECT_EQ(old_position, drawable().rect.origin()); | |
230 EXPECT_TRUE(NeedsAnimate()); | |
231 | |
232 // While the handle is fading, the new position should not take affect. | |
233 base::TimeTicks now = base::TimeTicks::Now(); | |
234 while (handle.Animate(now)) { | |
235 EXPECT_EQ(old_position, drawable().rect.origin()); | |
236 now += base::TimeDelta::FromMilliseconds(16); | |
237 } | |
238 | |
239 // Even after the animation terminates, the new position will not be pushed. | |
240 EXPECT_EQ(old_position, drawable().rect.origin()); | |
241 | |
242 // As soon as the handle becomes visible, the new position will be pushed. | |
243 handle.SetVisible(true, TouchHandle::ANIMATION_SMOOTH); | |
244 EXPECT_EQ(new_position, drawable().rect.origin()); | |
245 } | |
246 | |
247 TEST_F(TouchHandleTest, Enabled) { | |
248 // A newly created handle defaults to enabled. | |
249 TouchHandle handle(this, TOUCH_HANDLE_CENTER); | |
250 EXPECT_TRUE(drawable().enabled); | |
251 | |
252 handle.SetEnabled(false); | |
253 EXPECT_FALSE(drawable().enabled); | |
254 | |
255 // Animation should not be triggered while the handle is disabled. | |
256 handle.SetVisible(true, TouchHandle::ANIMATION_SMOOTH); | |
257 EXPECT_FALSE(NeedsAnimate()); | |
258 | |
259 // Dragging should not be allowed while the handle is disabled. | |
260 base::TimeTicks event_time = base::TimeTicks::Now(); | |
261 const float kOffset = kDefaultDrawableSize / 2.f; | |
262 MockMotionEvent event( | |
263 MockMotionEvent::ACTION_DOWN, event_time, kOffset, kOffset); | |
264 EXPECT_FALSE(handle.WillHandleTouchEvent(event)); | |
265 | |
266 // Disabling mid-animation should cancel the animation. | |
267 handle.SetEnabled(true); | |
268 handle.SetVisible(false, TouchHandle::ANIMATION_SMOOTH); | |
269 EXPECT_TRUE(drawable().visible); | |
270 EXPECT_TRUE(GetAndResetNeedsAnimate()); | |
271 handle.SetEnabled(false); | |
272 EXPECT_FALSE(drawable().enabled); | |
273 EXPECT_FALSE(drawable().visible); | |
274 EXPECT_FALSE(handle.Animate(base::TimeTicks::Now())); | |
275 | |
276 // Diabling mid-drag shoudl cancel the drag. | |
cjhopman
2014/07/14 18:23:52
s/Diabling/Disabling
s/shoudl/should
jdduke (slow)
2014/07/15 15:44:24
Done.
| |
277 handle.SetEnabled(true); | |
278 handle.SetVisible(true, TouchHandle::ANIMATION_NONE); | |
279 EXPECT_TRUE(handle.WillHandleTouchEvent(event)); | |
280 EXPECT_TRUE(IsDragging()); | |
281 handle.SetEnabled(false); | |
282 EXPECT_FALSE(IsDragging()); | |
283 EXPECT_FALSE(handle.WillHandleTouchEvent(event)); | |
284 } | |
285 | |
286 TEST_F(TouchHandleTest, Drag) { | |
287 TouchHandle handle(this, TOUCH_HANDLE_CENTER); | |
288 | |
289 base::TimeTicks event_time = base::TimeTicks::Now(); | |
290 const float kOffset = kDefaultDrawableSize / 2.f; | |
291 | |
292 // The handle must be visible to trigger drag. | |
293 MockMotionEvent event( | |
294 MockMotionEvent::ACTION_DOWN, event_time, kOffset, kOffset); | |
295 EXPECT_FALSE(handle.WillHandleTouchEvent(event)); | |
296 EXPECT_FALSE(IsDragging()); | |
297 handle.SetVisible(true, TouchHandle::ANIMATION_NONE); | |
298 | |
299 // ACTION_DOWN must fall within the drawable region to trigger drag. | |
300 event = MockMotionEvent(MockMotionEvent::ACTION_DOWN, event_time, 50, 50); | |
301 EXPECT_FALSE(handle.WillHandleTouchEvent(event)); | |
302 EXPECT_FALSE(IsDragging()); | |
303 | |
304 // Only ACTION_DOWN will trigger drag. | |
305 event = MockMotionEvent( | |
306 MockMotionEvent::ACTION_MOVE, event_time, kOffset, kOffset); | |
307 EXPECT_FALSE(handle.WillHandleTouchEvent(event)); | |
308 EXPECT_FALSE(IsDragging()); | |
309 | |
310 // Start the drag. | |
311 event = MockMotionEvent( | |
312 MockMotionEvent::ACTION_DOWN, event_time, kOffset, kOffset); | |
313 EXPECT_TRUE(handle.WillHandleTouchEvent(event)); | |
314 EXPECT_TRUE(IsDragging()); | |
315 | |
316 event = MockMotionEvent( | |
317 MockMotionEvent::ACTION_MOVE, event_time, kOffset + 10, kOffset + 15); | |
318 EXPECT_TRUE(handle.WillHandleTouchEvent(event)); | |
319 EXPECT_TRUE(GetAndResetHandleDragged()); | |
320 EXPECT_TRUE(IsDragging()); | |
321 EXPECT_EQ(gfx::PointF(10, 15), DragPosition()); | |
322 | |
323 event = MockMotionEvent( | |
324 MockMotionEvent::ACTION_MOVE, event_time, kOffset - 10, kOffset - 15); | |
325 EXPECT_TRUE(handle.WillHandleTouchEvent(event)); | |
326 EXPECT_TRUE(GetAndResetHandleDragged()); | |
327 EXPECT_TRUE(IsDragging()); | |
328 EXPECT_EQ(gfx::PointF(-10, -15), DragPosition()); | |
329 | |
330 event = MockMotionEvent(MockMotionEvent::ACTION_UP); | |
331 EXPECT_TRUE(handle.WillHandleTouchEvent(event)); | |
332 EXPECT_FALSE(GetAndResetHandleDragged()); | |
333 EXPECT_FALSE(IsDragging()); | |
334 | |
335 // Non-ACTION_DOWN events after the drag has terminated should not be handled. | |
336 event = MockMotionEvent(MockMotionEvent::ACTION_CANCEL); | |
337 EXPECT_FALSE(handle.WillHandleTouchEvent(event)); | |
338 } | |
339 | |
340 TEST_F(TouchHandleTest, DragDefersOrientationChange) { | |
341 TouchHandle handle(this, TOUCH_HANDLE_RIGHT); | |
342 ASSERT_EQ(drawable().orientation, TOUCH_HANDLE_RIGHT); | |
343 handle.SetVisible(true, TouchHandle::ANIMATION_NONE); | |
344 | |
345 MockMotionEvent event(MockMotionEvent::ACTION_DOWN); | |
346 EXPECT_TRUE(handle.WillHandleTouchEvent(event)); | |
347 EXPECT_TRUE(IsDragging()); | |
348 | |
349 // Orientation changes will be deferred until the drag ends. | |
350 handle.SetOrientation(TOUCH_HANDLE_LEFT); | |
351 EXPECT_EQ(TOUCH_HANDLE_RIGHT, drawable().orientation); | |
352 | |
353 event = MockMotionEvent(MockMotionEvent::ACTION_MOVE); | |
354 EXPECT_TRUE(handle.WillHandleTouchEvent(event)); | |
355 EXPECT_TRUE(GetAndResetHandleDragged()); | |
356 EXPECT_TRUE(IsDragging()); | |
357 EXPECT_EQ(TOUCH_HANDLE_RIGHT, drawable().orientation); | |
358 | |
359 event = MockMotionEvent(MockMotionEvent::ACTION_UP); | |
360 EXPECT_TRUE(handle.WillHandleTouchEvent(event)); | |
361 EXPECT_FALSE(GetAndResetHandleDragged()); | |
362 EXPECT_FALSE(IsDragging()); | |
363 EXPECT_EQ(TOUCH_HANDLE_LEFT, drawable().orientation); | |
364 } | |
365 | |
366 TEST_F(TouchHandleTest, DragDefersFade) { | |
367 TouchHandle handle(this, TOUCH_HANDLE_CENTER); | |
368 handle.SetVisible(true, TouchHandle::ANIMATION_NONE); | |
369 | |
370 MockMotionEvent event(MockMotionEvent::ACTION_DOWN); | |
371 EXPECT_TRUE(handle.WillHandleTouchEvent(event)); | |
372 EXPECT_TRUE(IsDragging()); | |
373 | |
374 // Fade will be deferred until the drag ends. | |
375 handle.SetVisible(false, TouchHandle::ANIMATION_SMOOTH); | |
376 EXPECT_FALSE(NeedsAnimate()); | |
377 EXPECT_TRUE(drawable().visible); | |
378 EXPECT_EQ(1.f, drawable().alpha); | |
379 | |
380 event = MockMotionEvent(MockMotionEvent::ACTION_MOVE); | |
381 EXPECT_TRUE(handle.WillHandleTouchEvent(event)); | |
382 EXPECT_FALSE(NeedsAnimate()); | |
383 EXPECT_TRUE(drawable().visible); | |
384 | |
385 event = MockMotionEvent(MockMotionEvent::ACTION_UP); | |
386 EXPECT_TRUE(handle.WillHandleTouchEvent(event)); | |
387 EXPECT_FALSE(IsDragging()); | |
388 EXPECT_TRUE(NeedsAnimate()); | |
389 | |
390 Animate(handle); | |
391 EXPECT_FALSE(drawable().visible); | |
392 EXPECT_EQ(0.f, drawable().alpha); | |
393 } | |
394 | |
395 TEST_F(TouchHandleTest, Tap) { | |
396 TouchHandle handle(this, TOUCH_HANDLE_CENTER); | |
397 handle.SetVisible(true, TouchHandle::ANIMATION_NONE); | |
398 | |
399 base::TimeTicks event_time = base::TimeTicks::Now(); | |
400 | |
401 // ACTION_CANCEL shouldn't trigger a tap. | |
402 MockMotionEvent event(MockMotionEvent::ACTION_DOWN, event_time, 0, 0); | |
403 EXPECT_TRUE(handle.WillHandleTouchEvent(event)); | |
404 event_time += base::TimeDelta::FromMilliseconds(50); | |
405 event = MockMotionEvent(MockMotionEvent::ACTION_CANCEL, event_time, 0, 0); | |
406 EXPECT_TRUE(handle.WillHandleTouchEvent(event)); | |
407 EXPECT_FALSE(GetAndResetHandleTapped()); | |
408 | |
409 // Long press shouldn't trigger a tap. | |
410 event = MockMotionEvent(MockMotionEvent::ACTION_DOWN, event_time, 0, 0); | |
411 EXPECT_TRUE(handle.WillHandleTouchEvent(event)); | |
412 event_time += base::TimeDelta::FromMilliseconds(500); | |
413 event = MockMotionEvent(MockMotionEvent::ACTION_UP, event_time, 0, 0); | |
414 EXPECT_TRUE(handle.WillHandleTouchEvent(event)); | |
415 EXPECT_FALSE(GetAndResetHandleTapped()); | |
416 | |
417 // Only a brief tap should trigger a tap. | |
418 event = MockMotionEvent(MockMotionEvent::ACTION_DOWN, event_time, 0, 0); | |
419 EXPECT_TRUE(handle.WillHandleTouchEvent(event)); | |
420 event_time += base::TimeDelta::FromMilliseconds(50); | |
421 event = MockMotionEvent(MockMotionEvent::ACTION_UP, event_time, 0, 0); | |
422 EXPECT_TRUE(handle.WillHandleTouchEvent(event)); | |
423 EXPECT_TRUE(GetAndResetHandleTapped()); | |
424 } | |
425 | |
426 } // namespace content | |
OLD | NEW |