1 /* 2 * Copyright (C) 2012 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #ifndef _LIBINPUT_VELOCITY_TRACKER_H 18 #define _LIBINPUT_VELOCITY_TRACKER_H 19 20 #include <input/Input.h> 21 #include <utils/BitSet.h> 22 #include <utils/Timers.h> 23 24 namespace android { 25 26 class VelocityTrackerStrategy; 27 28 /* 29 * Calculates the velocity of pointer movements over time. 30 */ 31 class VelocityTracker { 32 public: 33 enum class Strategy : int32_t { 34 DEFAULT = -1, 35 MIN = 0, 36 IMPULSE = 0, 37 LSQ1 = 1, 38 LSQ2 = 2, 39 LSQ3 = 3, 40 WLSQ2_DELTA = 4, 41 WLSQ2_CENTRAL = 5, 42 WLSQ2_RECENT = 6, 43 INT1 = 7, 44 INT2 = 8, 45 LEGACY = 9, 46 MAX = LEGACY, 47 }; 48 49 struct Position { 50 float x, y; 51 }; 52 53 struct Estimator { 54 static const size_t MAX_DEGREE = 4; 55 56 // Estimator time base. 57 nsecs_t time; 58 59 // Polynomial coefficients describing motion in X and Y. 60 float xCoeff[MAX_DEGREE + 1], yCoeff[MAX_DEGREE + 1]; 61 62 // Polynomial degree (number of coefficients), or zero if no information is 63 // available. 64 uint32_t degree; 65 66 // Confidence (coefficient of determination), between 0 (no fit) and 1 (perfect fit). 67 float confidence; 68 clearEstimator69 inline void clear() { 70 time = 0; 71 degree = 0; 72 confidence = 0; 73 for (size_t i = 0; i <= MAX_DEGREE; i++) { 74 xCoeff[i] = 0; 75 yCoeff[i] = 0; 76 } 77 } 78 }; 79 80 // Creates a velocity tracker using the specified strategy. 81 // If strategy is not provided, uses the default strategy for the platform. 82 VelocityTracker(const Strategy strategy = Strategy::DEFAULT); 83 84 ~VelocityTracker(); 85 86 // Resets the velocity tracker state. 87 void clear(); 88 89 // Resets the velocity tracker state for specific pointers. 90 // Call this method when some pointers have changed and may be reusing 91 // an id that was assigned to a different pointer earlier. 92 void clearPointers(BitSet32 idBits); 93 94 // Adds movement information for a set of pointers. 95 // The idBits bitfield specifies the pointer ids of the pointers whose positions 96 // are included in the movement. 97 // The positions array contains position information for each pointer in order by 98 // increasing id. Its size should be equal to the number of one bits in idBits. 99 void addMovement(nsecs_t eventTime, BitSet32 idBits, const std::vector<Position>& positions); 100 101 // Adds movement information for all pointers in a MotionEvent, including historical samples. 102 void addMovement(const MotionEvent* event); 103 104 // Gets the velocity of the specified pointer id in position units per second. 105 // Returns false and sets the velocity components to zero if there is 106 // insufficient movement information for the pointer. 107 bool getVelocity(uint32_t id, float* outVx, float* outVy) const; 108 109 // Gets an estimator for the recent movements of the specified pointer id. 110 // Returns false and clears the estimator if there is no information available 111 // about the pointer. 112 bool getEstimator(uint32_t id, Estimator* outEstimator) const; 113 114 // Gets the active pointer id, or -1 if none. getActivePointerId()115 inline int32_t getActivePointerId() const { return mActivePointerId; } 116 117 // Gets a bitset containing all pointer ids from the most recent movement. getCurrentPointerIdBits()118 inline BitSet32 getCurrentPointerIdBits() const { return mCurrentPointerIdBits; } 119 120 private: 121 // The default velocity tracker strategy. 122 // Although other strategies are available for testing and comparison purposes, 123 // this is the strategy that applications will actually use. Be very careful 124 // when adjusting the default strategy because it can dramatically affect 125 // (often in a bad way) the user experience. 126 static const Strategy DEFAULT_STRATEGY = Strategy::LSQ2; 127 128 nsecs_t mLastEventTime; 129 BitSet32 mCurrentPointerIdBits; 130 int32_t mActivePointerId; 131 std::unique_ptr<VelocityTrackerStrategy> mStrategy; 132 133 bool configureStrategy(const Strategy strategy); 134 135 static std::unique_ptr<VelocityTrackerStrategy> createStrategy(const Strategy strategy); 136 }; 137 138 139 /* 140 * Implements a particular velocity tracker algorithm. 141 */ 142 class VelocityTrackerStrategy { 143 protected: VelocityTrackerStrategy()144 VelocityTrackerStrategy() { } 145 146 public: ~VelocityTrackerStrategy()147 virtual ~VelocityTrackerStrategy() { } 148 149 virtual void clear() = 0; 150 virtual void clearPointers(BitSet32 idBits) = 0; 151 virtual void addMovement(nsecs_t eventTime, BitSet32 idBits, 152 const std::vector<VelocityTracker::Position>& positions) = 0; 153 virtual bool getEstimator(uint32_t id, VelocityTracker::Estimator* outEstimator) const = 0; 154 }; 155 156 157 /* 158 * Velocity tracker algorithm based on least-squares linear regression. 159 */ 160 class LeastSquaresVelocityTrackerStrategy : public VelocityTrackerStrategy { 161 public: 162 enum Weighting { 163 // No weights applied. All data points are equally reliable. 164 WEIGHTING_NONE, 165 166 // Weight by time delta. Data points clustered together are weighted less. 167 WEIGHTING_DELTA, 168 169 // Weight such that points within a certain horizon are weighed more than those 170 // outside of that horizon. 171 WEIGHTING_CENTRAL, 172 173 // Weight such that points older than a certain amount are weighed less. 174 WEIGHTING_RECENT, 175 }; 176 177 // Degree must be no greater than Estimator::MAX_DEGREE. 178 LeastSquaresVelocityTrackerStrategy(uint32_t degree, Weighting weighting = WEIGHTING_NONE); 179 virtual ~LeastSquaresVelocityTrackerStrategy(); 180 181 virtual void clear(); 182 virtual void clearPointers(BitSet32 idBits); 183 void addMovement(nsecs_t eventTime, BitSet32 idBits, 184 const std::vector<VelocityTracker::Position>& positions) override; 185 virtual bool getEstimator(uint32_t id, VelocityTracker::Estimator* outEstimator) const; 186 187 private: 188 // Sample horizon. 189 // We don't use too much history by default since we want to react to quick 190 // changes in direction. 191 static const nsecs_t HORIZON = 100 * 1000000; // 100 ms 192 193 // Number of samples to keep. 194 static const uint32_t HISTORY_SIZE = 20; 195 196 struct Movement { 197 nsecs_t eventTime; 198 BitSet32 idBits; 199 VelocityTracker::Position positions[MAX_POINTERS]; 200 getPositionMovement201 inline const VelocityTracker::Position& getPosition(uint32_t id) const { 202 return positions[idBits.getIndexOfBit(id)]; 203 } 204 }; 205 206 float chooseWeight(uint32_t index) const; 207 208 const uint32_t mDegree; 209 const Weighting mWeighting; 210 uint32_t mIndex; 211 Movement mMovements[HISTORY_SIZE]; 212 }; 213 214 215 /* 216 * Velocity tracker algorithm that uses an IIR filter. 217 */ 218 class IntegratingVelocityTrackerStrategy : public VelocityTrackerStrategy { 219 public: 220 // Degree must be 1 or 2. 221 IntegratingVelocityTrackerStrategy(uint32_t degree); 222 ~IntegratingVelocityTrackerStrategy(); 223 224 virtual void clear(); 225 virtual void clearPointers(BitSet32 idBits); 226 void addMovement(nsecs_t eventTime, BitSet32 idBits, 227 const std::vector<VelocityTracker::Position>& positions) override; 228 virtual bool getEstimator(uint32_t id, VelocityTracker::Estimator* outEstimator) const; 229 230 private: 231 // Current state estimate for a particular pointer. 232 struct State { 233 nsecs_t updateTime; 234 uint32_t degree; 235 236 float xpos, xvel, xaccel; 237 float ypos, yvel, yaccel; 238 }; 239 240 const uint32_t mDegree; 241 BitSet32 mPointerIdBits; 242 State mPointerState[MAX_POINTER_ID + 1]; 243 244 void initState(State& state, nsecs_t eventTime, float xpos, float ypos) const; 245 void updateState(State& state, nsecs_t eventTime, float xpos, float ypos) const; 246 void populateEstimator(const State& state, VelocityTracker::Estimator* outEstimator) const; 247 }; 248 249 250 /* 251 * Velocity tracker strategy used prior to ICS. 252 */ 253 class LegacyVelocityTrackerStrategy : public VelocityTrackerStrategy { 254 public: 255 LegacyVelocityTrackerStrategy(); 256 virtual ~LegacyVelocityTrackerStrategy(); 257 258 virtual void clear(); 259 virtual void clearPointers(BitSet32 idBits); 260 void addMovement(nsecs_t eventTime, BitSet32 idBits, 261 const std::vector<VelocityTracker::Position>& positions) override; 262 virtual bool getEstimator(uint32_t id, VelocityTracker::Estimator* outEstimator) const; 263 264 private: 265 // Oldest sample to consider when calculating the velocity. 266 static const nsecs_t HORIZON = 200 * 1000000; // 100 ms 267 268 // Number of samples to keep. 269 static const uint32_t HISTORY_SIZE = 20; 270 271 // The minimum duration between samples when estimating velocity. 272 static const nsecs_t MIN_DURATION = 10 * 1000000; // 10 ms 273 274 struct Movement { 275 nsecs_t eventTime; 276 BitSet32 idBits; 277 VelocityTracker::Position positions[MAX_POINTERS]; 278 getPositionMovement279 inline const VelocityTracker::Position& getPosition(uint32_t id) const { 280 return positions[idBits.getIndexOfBit(id)]; 281 } 282 }; 283 284 uint32_t mIndex; 285 Movement mMovements[HISTORY_SIZE]; 286 }; 287 288 class ImpulseVelocityTrackerStrategy : public VelocityTrackerStrategy { 289 public: 290 ImpulseVelocityTrackerStrategy(); 291 virtual ~ImpulseVelocityTrackerStrategy(); 292 293 virtual void clear(); 294 virtual void clearPointers(BitSet32 idBits); 295 void addMovement(nsecs_t eventTime, BitSet32 idBits, 296 const std::vector<VelocityTracker::Position>& positions) override; 297 virtual bool getEstimator(uint32_t id, VelocityTracker::Estimator* outEstimator) const; 298 299 private: 300 // Sample horizon. 301 // We don't use too much history by default since we want to react to quick 302 // changes in direction. 303 static constexpr nsecs_t HORIZON = 100 * 1000000; // 100 ms 304 305 // Number of samples to keep. 306 static constexpr size_t HISTORY_SIZE = 20; 307 308 struct Movement { 309 nsecs_t eventTime; 310 BitSet32 idBits; 311 VelocityTracker::Position positions[MAX_POINTERS]; 312 getPositionMovement313 inline const VelocityTracker::Position& getPosition(uint32_t id) const { 314 return positions[idBits.getIndexOfBit(id)]; 315 } 316 }; 317 318 size_t mIndex; 319 Movement mMovements[HISTORY_SIZE]; 320 }; 321 322 } // namespace android 323 324 #endif // _LIBINPUT_VELOCITY_TRACKER_H 325