velocity_tracker_unittest.cc revision a1401311d1ab56c4ed0a474bd38c108f75cb0cd9
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 "base/basictypes.h" 6#include "base/logging.h" 7#include "base/memory/scoped_ptr.h" 8#include "base/time/time.h" 9#include "testing/gtest/include/gtest/gtest.h" 10#include "ui/events/gesture_detection/mock_motion_event.h" 11#include "ui/events/gesture_detection/velocity_tracker_state.h" 12#include "ui/gfx/geometry/point_f.h" 13#include "ui/gfx/geometry/vector2d_f.h" 14 15using base::TimeDelta; 16using base::TimeTicks; 17 18namespace ui { 19namespace { 20 21const TimeDelta kTenMillis = TimeDelta::FromMilliseconds(10); 22const TimeDelta kOneSecond = TimeDelta::FromSeconds(1); 23const float kEpsilson = .01f; 24 25const char* GetStrategyName(VelocityTracker::Strategy strategy) { 26 switch (strategy) { 27 case VelocityTracker::LSQ1: return "LSQ1"; 28 case VelocityTracker::LSQ2: return "LSQ2"; 29 case VelocityTracker::LSQ3: return "LSQ3"; 30 case VelocityTracker::WLSQ2_DELTA: return "WLSQ2_DELTA"; 31 case VelocityTracker::WLSQ2_CENTRAL: return "WLSQ2_CENTRAL"; 32 case VelocityTracker::WLSQ2_RECENT: return "WLSQ2_RECENT"; 33 case VelocityTracker::INT1: return "INT1"; 34 case VelocityTracker::INT2: return "INT2"; 35 }; 36 NOTREACHED() << "Invalid strategy"; 37 return ""; 38} 39 40} // namespace 41 42class VelocityTrackerTest : public testing::Test { 43 public: 44 VelocityTrackerTest() {} 45 virtual ~VelocityTrackerTest() {} 46 47 protected: 48 static MockMotionEvent Sample(MotionEvent::Action action, 49 gfx::PointF p0, 50 TimeTicks t0, 51 gfx::Vector2dF v, 52 TimeDelta dt) { 53 const gfx::PointF p = p0 + ScaleVector2d(v, dt.InSecondsF()); 54 return MockMotionEvent(action, t0 + dt, p.x(), p.y()); 55 } 56 57 static void ApplyMovementSequence(VelocityTrackerState* state, 58 gfx::PointF p0, 59 gfx::Vector2dF v, 60 TimeTicks t0, 61 TimeDelta t, 62 size_t samples) { 63 EXPECT_TRUE(!!samples); 64 if (!samples) 65 return; 66 const base::TimeDelta dt = t / samples; 67 state->AddMovement(Sample(MotionEvent::ACTION_DOWN, p0, t0, v, dt * 0)); 68 ApplyMovement(state, p0, v, t0, t, samples); 69 state->AddMovement(Sample(MotionEvent::ACTION_UP, p0, t0, v, t)); 70 } 71 72 static void ApplyMovement(VelocityTrackerState* state, 73 gfx::PointF p0, 74 gfx::Vector2dF v, 75 TimeTicks t0, 76 TimeDelta t, 77 size_t samples) { 78 EXPECT_TRUE(!!samples); 79 if (!samples) 80 return; 81 const base::TimeDelta dt = t / samples; 82 for (size_t i = 0; i < samples; ++i) 83 state->AddMovement(Sample(MotionEvent::ACTION_MOVE, p0, t0, v, dt * i)); 84 } 85}; 86 87TEST_F(VelocityTrackerTest, Basic) { 88 const gfx::PointF p0(0, 0); 89 const gfx::Vector2dF v(0, 500); 90 const size_t samples = 60; 91 92 for (int i = 0; i <= VelocityTracker::STRATEGY_MAX; ++i) { 93 VelocityTracker::Strategy strategy = 94 static_cast<VelocityTracker::Strategy>(i); 95 96 SCOPED_TRACE(GetStrategyName(strategy)); 97 VelocityTrackerState state(strategy); 98 99 // Default state should report zero velocity. 100 EXPECT_EQ(0, state.GetXVelocity(0)); 101 EXPECT_EQ(0, state.GetYVelocity(0)); 102 103 // Sample a constant velocity sequence. 104 ApplyMovementSequence(&state, p0, v, TimeTicks::Now(), kOneSecond, samples); 105 106 // The computed velocity should match that of the input. 107 state.ComputeCurrentVelocity(1000, 20000); 108 EXPECT_NEAR(v.x(), state.GetXVelocity(0), kEpsilson * v.x()); 109 EXPECT_NEAR(v.y(), state.GetYVelocity(0), kEpsilson * v.y()); 110 111 // A pointer ID of -1 should report the velocity of the active pointer. 112 EXPECT_NEAR(v.x(), state.GetXVelocity(-1), kEpsilson * v.x()); 113 EXPECT_NEAR(v.y(), state.GetYVelocity(-1), kEpsilson * v.y()); 114 115 // Invalid pointer ID's should report zero velocity. 116 EXPECT_EQ(0, state.GetXVelocity(1)); 117 EXPECT_EQ(0, state.GetYVelocity(1)); 118 EXPECT_EQ(0, state.GetXVelocity(7)); 119 EXPECT_EQ(0, state.GetYVelocity(7)); 120 } 121} 122 123TEST_F(VelocityTrackerTest, MaxVelocity) { 124 const gfx::PointF p0(0, 0); 125 const gfx::Vector2dF v(-50000, 50000); 126 const size_t samples = 3; 127 const base::TimeDelta dt = kTenMillis * 2; 128 129 VelocityTrackerState state; 130 ApplyMovementSequence(&state, p0, v, TimeTicks::Now(), dt, samples); 131 132 // The computed velocity should be restricted to the provided maximum. 133 state.ComputeCurrentVelocity(1000, 100); 134 EXPECT_NEAR(-100, state.GetXVelocity(0), kEpsilson); 135 EXPECT_NEAR(100, state.GetYVelocity(0), kEpsilson); 136 137 state.ComputeCurrentVelocity(1000, 1000); 138 EXPECT_NEAR(-1000, state.GetXVelocity(0), kEpsilson); 139 EXPECT_NEAR(1000, state.GetYVelocity(0), kEpsilson); 140} 141 142TEST_F(VelocityTrackerTest, VaryingVelocity) { 143 const gfx::PointF p0(0, 0); 144 const gfx::Vector2dF vFast(0, 500); 145 const gfx::Vector2dF vSlow = ScaleVector2d(vFast, 0.5f); 146 const size_t samples = 12; 147 148 for (int i = 0; i <= VelocityTracker::STRATEGY_MAX; ++i) { 149 VelocityTracker::Strategy strategy = 150 static_cast<VelocityTracker::Strategy>(i); 151 152 SCOPED_TRACE(GetStrategyName(strategy)); 153 VelocityTrackerState state(strategy); 154 155 base::TimeTicks t0 = base::TimeTicks::Now(); 156 base::TimeDelta dt = kTenMillis * 10; 157 state.AddMovement( 158 Sample(MotionEvent::ACTION_DOWN, p0, t0, vFast, base::TimeDelta())); 159 160 // Apply some fast movement and compute the velocity. 161 gfx::PointF pCurr = p0; 162 base::TimeTicks tCurr = t0; 163 ApplyMovement(&state, pCurr, vFast, tCurr, dt, samples); 164 state.ComputeCurrentVelocity(1000, 20000); 165 float vOldY = state.GetYVelocity(0); 166 167 // Apply some slow movement. 168 pCurr += ScaleVector2d(vFast, dt.InSecondsF()); 169 tCurr += dt; 170 ApplyMovement(&state, pCurr, vSlow, tCurr, dt, samples); 171 172 // The computed velocity should have decreased. 173 state.ComputeCurrentVelocity(1000, 20000); 174 float vCurrentY = state.GetYVelocity(0); 175 EXPECT_GT(vFast.y(), vCurrentY); 176 EXPECT_GT(vOldY, vCurrentY); 177 vOldY = vCurrentY; 178 179 // Apply some additional fast movement. 180 pCurr += ScaleVector2d(vSlow, dt.InSecondsF()); 181 tCurr += dt; 182 ApplyMovement(&state, pCurr, vFast, tCurr, dt, samples); 183 184 // The computed velocity should have increased. 185 state.ComputeCurrentVelocity(1000, 20000); 186 vCurrentY = state.GetYVelocity(0); 187 EXPECT_LT(vSlow.y(), vCurrentY); 188 EXPECT_LT(vOldY, vCurrentY); 189 } 190} 191 192 193} // namespace ui 194