• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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