blob: 886f1f7753759c8beb6af69783dfc70988e33bd1 [file] [log] [blame]
Jeff Brown5912f952013-07-01 19:10:31 -07001/*
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>
Jeff Brown5912f952013-07-01 19:10:31 -070021#include <utils/BitSet.h>
Chris Yef8591482020-04-17 11:49:17 -070022#include <utils/Timers.h>
Jeff Brown5912f952013-07-01 19:10:31 -070023
24namespace android {
25
26class VelocityTrackerStrategy;
27
28/*
29 * Calculates the velocity of pointer movements over time.
30 */
31class VelocityTracker {
32public:
Chris Yef8591482020-04-17 11:49:17 -070033 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
Jeff Brown5912f952013-07-01 19:10:31 -070049 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
69 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.
Chris Yef8591482020-04-17 11:49:17 -070081 // If strategy is not provided, uses the default strategy for the platform.
82 VelocityTracker(const Strategy strategy = Strategy::DEFAULT);
Jeff Brown5912f952013-07-01 19:10:31 -070083
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.
Siarhei Vishniakouae0f9902020-09-14 19:23:31 -050099 void addMovement(nsecs_t eventTime, BitSet32 idBits, const std::vector<Position>& positions);
Jeff Brown5912f952013-07-01 19:10:31 -0700100
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.
115 inline int32_t getActivePointerId() const { return mActivePointerId; }
116
117 // Gets a bitset containing all pointer ids from the most recent movement.
118 inline BitSet32 getCurrentPointerIdBits() const { return mCurrentPointerIdBits; }
119
120private:
Chris Yef8591482020-04-17 11:49:17 -0700121 // 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;
Jeff Brown5912f952013-07-01 19:10:31 -0700127
128 nsecs_t mLastEventTime;
129 BitSet32 mCurrentPointerIdBits;
130 int32_t mActivePointerId;
Chris Yef8591482020-04-17 11:49:17 -0700131 std::unique_ptr<VelocityTrackerStrategy> mStrategy;
Jeff Brown5912f952013-07-01 19:10:31 -0700132
Chris Yef8591482020-04-17 11:49:17 -0700133 bool configureStrategy(const Strategy strategy);
Jeff Brown5912f952013-07-01 19:10:31 -0700134
Chris Yef8591482020-04-17 11:49:17 -0700135 static std::unique_ptr<VelocityTrackerStrategy> createStrategy(const Strategy strategy);
Jeff Brown5912f952013-07-01 19:10:31 -0700136};
137
138
139/*
140 * Implements a particular velocity tracker algorithm.
141 */
142class VelocityTrackerStrategy {
143protected:
144 VelocityTrackerStrategy() { }
145
146public:
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,
Siarhei Vishniakouae0f9902020-09-14 19:23:31 -0500152 const std::vector<VelocityTracker::Position>& positions) = 0;
Jeff Brown5912f952013-07-01 19:10:31 -0700153 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 */
160class LeastSquaresVelocityTrackerStrategy : public VelocityTrackerStrategy {
161public:
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);
Siarhei Vishniakouae0f9902020-09-14 19:23:31 -0500183 void addMovement(nsecs_t eventTime, BitSet32 idBits,
184 const std::vector<VelocityTracker::Position>& positions) override;
Jeff Brown5912f952013-07-01 19:10:31 -0700185 virtual bool getEstimator(uint32_t id, VelocityTracker::Estimator* outEstimator) const;
186
187private:
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
201 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 */
218class IntegratingVelocityTrackerStrategy : public VelocityTrackerStrategy {
219public:
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);
Siarhei Vishniakouae0f9902020-09-14 19:23:31 -0500226 void addMovement(nsecs_t eventTime, BitSet32 idBits,
227 const std::vector<VelocityTracker::Position>& positions) override;
Jeff Brown5912f952013-07-01 19:10:31 -0700228 virtual bool getEstimator(uint32_t id, VelocityTracker::Estimator* outEstimator) const;
229
230private:
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 */
253class LegacyVelocityTrackerStrategy : public VelocityTrackerStrategy {
254public:
255 LegacyVelocityTrackerStrategy();
256 virtual ~LegacyVelocityTrackerStrategy();
257
258 virtual void clear();
259 virtual void clearPointers(BitSet32 idBits);
Siarhei Vishniakouae0f9902020-09-14 19:23:31 -0500260 void addMovement(nsecs_t eventTime, BitSet32 idBits,
261 const std::vector<VelocityTracker::Position>& positions) override;
Jeff Brown5912f952013-07-01 19:10:31 -0700262 virtual bool getEstimator(uint32_t id, VelocityTracker::Estimator* outEstimator) const;
263
264private:
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
279 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
Siarhei Vishniakou00a4ea92017-06-08 21:43:20 +0100288class ImpulseVelocityTrackerStrategy : public VelocityTrackerStrategy {
289public:
290 ImpulseVelocityTrackerStrategy();
291 virtual ~ImpulseVelocityTrackerStrategy();
292
293 virtual void clear();
294 virtual void clearPointers(BitSet32 idBits);
Siarhei Vishniakouae0f9902020-09-14 19:23:31 -0500295 void addMovement(nsecs_t eventTime, BitSet32 idBits,
296 const std::vector<VelocityTracker::Position>& positions) override;
Siarhei Vishniakou00a4ea92017-06-08 21:43:20 +0100297 virtual bool getEstimator(uint32_t id, VelocityTracker::Estimator* outEstimator) const;
298
299private:
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
313 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
Jeff Brown5912f952013-07-01 19:10:31 -0700322} // namespace android
323
324#endif // _LIBINPUT_VELOCITY_TRACKER_H