Chromium Code Reviews| Index: content/browser/renderer_host/input/touch_handle_unittest.cc |
| diff --git a/content/browser/renderer_host/input/touch_handle_unittest.cc b/content/browser/renderer_host/input/touch_handle_unittest.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..0005b169f4cdc6884c3382d0f53c5b0887de4ac2 |
| --- /dev/null |
| +++ b/content/browser/renderer_host/input/touch_handle_unittest.cc |
| @@ -0,0 +1,382 @@ |
| +// Copyright 2014 The Chromium Authors. All rights reserved. |
| +// Use of this source code is governed by a BSD-style license that can be |
| +// found in the LICENSE file. |
| + |
| +#include "content/browser/renderer_host/input/touch_handle.h" |
| + |
| +#include "testing/gtest/include/gtest/gtest.h" |
| +#include "ui/events/test/mock_motion_event.h" |
| +#include "ui/gfx/geometry/rect_f.h" |
| + |
| +using ui::test::MockMotionEvent; |
| + |
| +namespace content { |
| +namespace { |
| + |
| +const float kDefaultDrawableSize = 10.f; |
| + |
| +struct MockDrawableData { |
| + MockDrawableData() |
| + : orientation(TOUCH_HANDLE_ORIENTATION_UNDEFINED), |
| + alpha(0.f), |
| + visible(false), |
| + rect(0, 0, kDefaultDrawableSize, kDefaultDrawableSize) {} |
| + TouchHandleOrientation orientation; |
| + float alpha; |
| + bool visible; |
| + gfx::RectF rect; |
| +}; |
| + |
| +class MockTouchHandleDrawable : public TouchHandleDrawable { |
| + public: |
| + explicit MockTouchHandleDrawable(MockDrawableData& data) : data_(data) {} |
|
cjhopman
2014/07/09 22:29:12
This should be a pointer, not a reference
jdduke (slow)
2014/07/10 02:08:39
Done.
|
| + virtual ~MockTouchHandleDrawable() {} |
| + |
| + virtual void SetOrientation(TouchHandleOrientation orientation) OVERRIDE { |
| + data_.orientation = orientation; |
| + } |
| + |
| + virtual void SetAlpha(float alpha) OVERRIDE { data_.alpha = alpha; } |
| + |
| + virtual void SetFocus(const gfx::PointF& position) OVERRIDE { |
| + // Anchor focus to the top left of the rect (regardless of orientation). |
| + data_.rect.set_origin(position); |
| + } |
| + |
| + virtual void SetVisible(bool visible) OVERRIDE { data_.visible = visible; } |
| + |
| + virtual bool ContainsPoint(const gfx::PointF& point) const OVERRIDE { |
| + return data_.rect.Contains(point); |
| + } |
| + |
| + private: |
| + MockDrawableData& data_; |
| +}; |
| + |
| +} // namespace |
| + |
| +class TouchHandleTest : public testing::Test, public TouchHandleClient { |
| + public: |
| + TouchHandleTest() |
| + : dragging_(false), |
| + dragged_(false), |
| + tapped_(false), |
| + needs_animate_(false) {} |
| + |
| + virtual ~TouchHandleTest() {} |
| + |
| + // TouchHandleClient implementation. |
| + virtual void OnHandleDragBegin(const TouchHandle& handle) OVERRIDE { |
| + dragging_ = true; |
| + } |
| + |
| + virtual void OnHandleDragUpdate(const TouchHandle& handle, |
| + const gfx::PointF& new_position) OVERRIDE { |
| + dragged_ = true; |
| + drag_position_ = new_position; |
| + } |
| + |
| + virtual void OnHandleDragEnd(const TouchHandle& handle) OVERRIDE { |
| + dragging_ = false; |
| + } |
| + |
| + virtual void OnHandleTapped(const TouchHandle& handle) OVERRIDE { |
| + tapped_ = true; |
| + } |
| + |
| + virtual void SetNeedsAnimate() OVERRIDE { needs_animate_ = true; } |
| + |
| + virtual scoped_ptr<TouchHandleDrawable> CreateDrawable() OVERRIDE { |
| + return scoped_ptr<TouchHandleDrawable>( |
| + new MockTouchHandleDrawable(drawable_data_)); |
| + } |
| + |
| + void Animate(TouchHandle& handle) { |
| + needs_animate_ = false; |
| + base::TimeTicks now = base::TimeTicks::Now(); |
| + while (handle.Animate(now)) |
| + now += base::TimeDelta::FromMilliseconds(16); |
| + } |
| + |
| + bool GetAndResetHandleDragged() { |
| + bool dragged = dragged_; |
| + dragged_ = false; |
| + return dragged; |
| + } |
| + |
| + bool GetAndResetHandleTapped() { |
| + bool tapped = tapped_; |
| + tapped_ = false; |
| + return tapped; |
| + } |
| + |
| + bool IsDragging() const { return dragging_; } |
| + const gfx::PointF& DragPosition() const { return drag_position_; } |
| + bool NeedsAnimate() const { return needs_animate_; } |
| + |
| + const MockDrawableData& drawable() { return drawable_data_; } |
| + |
| + private: |
| + gfx::PointF drag_position_; |
| + bool dragging_; |
| + bool dragged_; |
| + bool tapped_; |
| + bool needs_animate_; |
| + |
| + MockDrawableData drawable_data_; |
| +}; |
| + |
| +TEST_F(TouchHandleTest, Visibility) { |
| + TouchHandle handle(this, TOUCH_HANDLE_CENTER); |
| + EXPECT_FALSE(drawable().visible); |
| + |
| + handle.SetVisible(true, TouchHandle::ANIMATION_NONE); |
| + EXPECT_TRUE(drawable().visible); |
| + EXPECT_EQ(1.f, drawable().alpha); |
| + |
| + handle.SetVisible(false, TouchHandle::ANIMATION_NONE); |
| + EXPECT_FALSE(drawable().visible); |
| + |
| + handle.SetVisible(true, TouchHandle::ANIMATION_NONE); |
| + EXPECT_TRUE(drawable().visible); |
| + EXPECT_EQ(1.f, drawable().alpha); |
| +} |
| + |
| +TEST_F(TouchHandleTest, VisibilityAnimation) { |
| + TouchHandle handle(this, TOUCH_HANDLE_CENTER); |
| + ASSERT_FALSE(NeedsAnimate()); |
| + ASSERT_FALSE(drawable().visible); |
| + ASSERT_EQ(0.f, drawable().alpha); |
| + |
| + handle.SetVisible(true, TouchHandle::ANIMATION_SMOOTH); |
| + EXPECT_TRUE(NeedsAnimate()); |
| + EXPECT_TRUE(drawable().visible); |
| + EXPECT_EQ(0.f, drawable().alpha); |
| + |
| + Animate(handle); |
| + EXPECT_TRUE(drawable().visible); |
| + EXPECT_EQ(1.f, drawable().alpha); |
| + |
| + ASSERT_FALSE(NeedsAnimate()); |
| + handle.SetVisible(false, TouchHandle::ANIMATION_SMOOTH); |
| + EXPECT_TRUE(NeedsAnimate()); |
| + EXPECT_TRUE(drawable().visible); |
| + EXPECT_EQ(1.f, drawable().alpha); |
| + |
| + Animate(handle); |
| + EXPECT_FALSE(drawable().visible); |
| + EXPECT_EQ(0.f, drawable().alpha); |
| +} |
| + |
| +TEST_F(TouchHandleTest, Orientation) { |
| + TouchHandle handle(this, TOUCH_HANDLE_CENTER); |
| + EXPECT_EQ(TOUCH_HANDLE_CENTER, drawable().orientation); |
| + |
| + handle.SetOrientation(TOUCH_HANDLE_LEFT); |
| + EXPECT_EQ(TOUCH_HANDLE_LEFT, drawable().orientation); |
| + |
| + handle.SetOrientation(TOUCH_HANDLE_RIGHT); |
| + EXPECT_EQ(TOUCH_HANDLE_RIGHT, drawable().orientation); |
| + |
| + handle.SetOrientation(TOUCH_HANDLE_CENTER); |
| + EXPECT_EQ(TOUCH_HANDLE_CENTER, drawable().orientation); |
| +} |
| + |
| +TEST_F(TouchHandleTest, Position) { |
| + TouchHandle handle(this, TOUCH_HANDLE_CENTER); |
| + |
| + gfx::PointF position; |
| + EXPECT_EQ(gfx::PointF(), drawable().rect.origin()); |
| + |
| + position = gfx::PointF(7.3, -3.7); |
| + handle.SetPosition(position); |
| + EXPECT_EQ(position, drawable().rect.origin()); |
| + |
| + position = gfx::PointF(-7.3, 3.7); |
| + handle.SetPosition(position); |
| + EXPECT_EQ(position, drawable().rect.origin()); |
| +} |
| + |
| +TEST_F(TouchHandleTest, PositionNotUpdatedWhileFading) { |
| + TouchHandle handle(this, TOUCH_HANDLE_CENTER); |
| + |
| + handle.SetVisible(true, TouchHandle::ANIMATION_NONE); |
| + ASSERT_TRUE(drawable().visible); |
| + ASSERT_FALSE(NeedsAnimate()); |
| + |
| + gfx::PointF visible_position(7.3, -3.7); |
| + handle.SetPosition(visible_position); |
| + ASSERT_EQ(visible_position, drawable().rect.origin()); |
| + |
| + handle.SetVisible(false, TouchHandle::ANIMATION_SMOOTH); |
| + ASSERT_TRUE(NeedsAnimate()); |
| + |
| + gfx::PointF invisible_position(3.7, -3.7); |
| + handle.SetPosition(invisible_position); |
| + EXPECT_NE(invisible_position, drawable().rect.origin()); |
| + EXPECT_EQ(visible_position, drawable().rect.origin()); |
| + EXPECT_TRUE(NeedsAnimate()); |
| + |
| + // While the handle is fading, the new position should not take affect. |
| + base::TimeTicks now = base::TimeTicks::Now(); |
| + while (handle.Animate(now)) { |
| + EXPECT_NE(invisible_position, drawable().rect.origin()); |
| + EXPECT_EQ(visible_position, drawable().rect.origin()); |
| + now += base::TimeDelta::FromMilliseconds(16); |
| + } |
| + |
| + // Only after the animation terminates will the position be pushed. |
| + EXPECT_EQ(invisible_position, drawable().rect.origin()); |
| +} |
| + |
| +TEST_F(TouchHandleTest, Hide) { |
| + TouchHandle handle(this, TOUCH_HANDLE_CENTER); |
| + |
| + handle.SetVisible(true, TouchHandle::ANIMATION_NONE); |
| + EXPECT_TRUE(drawable().visible); |
| + |
| + handle.Hide(); |
| + EXPECT_FALSE(drawable().visible); |
| +} |
| + |
| +TEST_F(TouchHandleTest, Drag) { |
| + TouchHandle handle(this, TOUCH_HANDLE_CENTER); |
| + |
| + base::TimeTicks event_time = base::TimeTicks::Now(); |
| + const float kOffset = kDefaultDrawableSize / 2.f; |
| + |
| + // The handle must be visible to trigger drag. |
| + MockMotionEvent event( |
| + MockMotionEvent::ACTION_DOWN, event_time, kOffset, kOffset); |
| + EXPECT_FALSE(handle.WillHandleTouchEvent(event)); |
| + EXPECT_FALSE(IsDragging()); |
| + handle.SetVisible(true, TouchHandle::ANIMATION_NONE); |
| + |
| + // ACTION_DOWN must fall within the drawable region to trigger drag. |
| + event = MockMotionEvent(MockMotionEvent::ACTION_DOWN, event_time, 50, 50); |
| + EXPECT_FALSE(handle.WillHandleTouchEvent(event)); |
| + EXPECT_FALSE(IsDragging()); |
| + |
| + // Only ACTION_DOWN will trigger drag. |
| + event = MockMotionEvent( |
| + MockMotionEvent::ACTION_MOVE, event_time, kOffset, kOffset); |
| + EXPECT_FALSE(handle.WillHandleTouchEvent(event)); |
| + EXPECT_FALSE(IsDragging()); |
| + |
| + // Start the drag. |
| + event = MockMotionEvent( |
| + MockMotionEvent::ACTION_DOWN, event_time, kOffset, kOffset); |
| + EXPECT_TRUE(handle.WillHandleTouchEvent(event)); |
| + EXPECT_TRUE(IsDragging()); |
| + |
| + event = MockMotionEvent( |
| + MockMotionEvent::ACTION_MOVE, event_time, kOffset + 10, kOffset + 15); |
| + EXPECT_TRUE(handle.WillHandleTouchEvent(event)); |
| + EXPECT_TRUE(GetAndResetHandleDragged()); |
| + EXPECT_TRUE(IsDragging()); |
| + EXPECT_EQ(gfx::PointF(10, 15), DragPosition()); |
| + |
| + event = MockMotionEvent( |
| + MockMotionEvent::ACTION_MOVE, event_time, kOffset - 10, kOffset - 15); |
| + EXPECT_TRUE(handle.WillHandleTouchEvent(event)); |
| + EXPECT_TRUE(GetAndResetHandleDragged()); |
| + EXPECT_TRUE(IsDragging()); |
| + EXPECT_EQ(gfx::PointF(-10, -15), DragPosition()); |
| + |
| + event = MockMotionEvent(MockMotionEvent::ACTION_UP); |
| + EXPECT_TRUE(handle.WillHandleTouchEvent(event)); |
| + EXPECT_FALSE(GetAndResetHandleDragged()); |
| + EXPECT_FALSE(IsDragging()); |
| + |
| + // Non-ACTION_DOWN events after the drag has terminated should not be handled. |
| + event = MockMotionEvent(MockMotionEvent::ACTION_CANCEL); |
| + EXPECT_FALSE(handle.WillHandleTouchEvent(event)); |
| +} |
| + |
| +TEST_F(TouchHandleTest, DragDefersOrientationChange) { |
| + TouchHandle handle(this, TOUCH_HANDLE_RIGHT); |
| + ASSERT_EQ(drawable().orientation, TOUCH_HANDLE_RIGHT); |
| + handle.SetVisible(true, TouchHandle::ANIMATION_NONE); |
| + |
| + MockMotionEvent event(MockMotionEvent::ACTION_DOWN); |
| + EXPECT_TRUE(handle.WillHandleTouchEvent(event)); |
| + EXPECT_TRUE(IsDragging()); |
| + |
| + // Orientation changes will be deferred until the drag ends. |
| + handle.SetOrientation(TOUCH_HANDLE_LEFT); |
| + EXPECT_EQ(TOUCH_HANDLE_RIGHT, drawable().orientation); |
| + |
| + event = MockMotionEvent(MockMotionEvent::ACTION_MOVE); |
| + EXPECT_TRUE(handle.WillHandleTouchEvent(event)); |
| + EXPECT_TRUE(GetAndResetHandleDragged()); |
| + EXPECT_TRUE(IsDragging()); |
| + EXPECT_EQ(TOUCH_HANDLE_RIGHT, drawable().orientation); |
| + |
| + event = MockMotionEvent(MockMotionEvent::ACTION_UP); |
| + EXPECT_TRUE(handle.WillHandleTouchEvent(event)); |
| + EXPECT_FALSE(GetAndResetHandleDragged()); |
| + EXPECT_FALSE(IsDragging()); |
| + EXPECT_EQ(TOUCH_HANDLE_LEFT, drawable().orientation); |
| +} |
| + |
| +TEST_F(TouchHandleTest, DragDefersFade) { |
| + TouchHandle handle(this, TOUCH_HANDLE_CENTER); |
| + handle.SetVisible(true, TouchHandle::ANIMATION_NONE); |
| + |
| + MockMotionEvent event(MockMotionEvent::ACTION_DOWN); |
| + EXPECT_TRUE(handle.WillHandleTouchEvent(event)); |
| + EXPECT_TRUE(IsDragging()); |
| + |
| + // Fade will be deferred until the drag ends. |
| + handle.SetVisible(false, TouchHandle::ANIMATION_SMOOTH); |
| + EXPECT_FALSE(NeedsAnimate()); |
| + EXPECT_TRUE(drawable().visible); |
| + EXPECT_EQ(1.f, drawable().alpha); |
| + |
| + event = MockMotionEvent(MockMotionEvent::ACTION_MOVE); |
| + EXPECT_TRUE(handle.WillHandleTouchEvent(event)); |
| + EXPECT_FALSE(NeedsAnimate()); |
| + EXPECT_TRUE(drawable().visible); |
| + |
| + event = MockMotionEvent(MockMotionEvent::ACTION_UP); |
| + EXPECT_TRUE(handle.WillHandleTouchEvent(event)); |
| + EXPECT_FALSE(IsDragging()); |
| + EXPECT_TRUE(NeedsAnimate()); |
| + |
| + Animate(handle); |
| + EXPECT_FALSE(drawable().visible); |
| + EXPECT_EQ(0.f, drawable().alpha); |
| +} |
| + |
| +TEST_F(TouchHandleTest, Tap) { |
| + TouchHandle handle(this, TOUCH_HANDLE_CENTER); |
| + handle.SetVisible(true, TouchHandle::ANIMATION_NONE); |
| + |
| + base::TimeTicks event_time = base::TimeTicks::Now(); |
| + |
| + // ACTION_CANCEL shouldn't trigger a tap. |
| + MockMotionEvent event(MockMotionEvent::ACTION_DOWN, event_time, 0, 0); |
| + EXPECT_TRUE(handle.WillHandleTouchEvent(event)); |
| + event_time += base::TimeDelta::FromMilliseconds(50); |
| + event = MockMotionEvent(MockMotionEvent::ACTION_CANCEL, event_time, 0, 0); |
| + EXPECT_TRUE(handle.WillHandleTouchEvent(event)); |
| + EXPECT_FALSE(GetAndResetHandleTapped()); |
| + |
| + // Long press shouldn't trigger a tap. |
| + event = MockMotionEvent(MockMotionEvent::ACTION_DOWN, event_time, 0, 0); |
| + EXPECT_TRUE(handle.WillHandleTouchEvent(event)); |
| + event_time += base::TimeDelta::FromMilliseconds(500); |
| + event = MockMotionEvent(MockMotionEvent::ACTION_UP, event_time, 0, 0); |
| + EXPECT_TRUE(handle.WillHandleTouchEvent(event)); |
| + EXPECT_FALSE(GetAndResetHandleTapped()); |
| + |
| + // Only a brief tap should trigger a tap. |
| + event = MockMotionEvent(MockMotionEvent::ACTION_DOWN, event_time, 0, 0); |
| + EXPECT_TRUE(handle.WillHandleTouchEvent(event)); |
| + event_time += base::TimeDelta::FromMilliseconds(50); |
| + event = MockMotionEvent(MockMotionEvent::ACTION_UP, event_time, 0, 0); |
| + EXPECT_TRUE(handle.WillHandleTouchEvent(event)); |
| + EXPECT_TRUE(GetAndResetHandleTapped()); |
| +} |
| + |
| +} // namespace content |