| /* | 
 |  * Copyright (C) 2012 The Android Open Source Project | 
 |  * | 
 |  * Licensed under the Apache License, Version 2.0 (the "License"); | 
 |  * you may not use this file except in compliance with the License. | 
 |  * You may obtain a copy of the License at | 
 |  * | 
 |  *      http://www.apache.org/licenses/LICENSE-2.0 | 
 |  * | 
 |  * Unless required by applicable law or agreed to in writing, software | 
 |  * distributed under the License is distributed on an "AS IS" BASIS, | 
 |  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
 |  * See the License for the specific language governing permissions and | 
 |  * limitations under the License. | 
 |  */ | 
 |  | 
 | #ifndef _LIBINPUT_VELOCITY_TRACKER_H | 
 | #define _LIBINPUT_VELOCITY_TRACKER_H | 
 |  | 
 | #include <input/Input.h> | 
 | #include <utils/BitSet.h> | 
 | #include <utils/Timers.h> | 
 |  | 
 | namespace android { | 
 |  | 
 | class VelocityTrackerStrategy; | 
 |  | 
 | /* | 
 |  * Calculates the velocity of pointer movements over time. | 
 |  */ | 
 | class VelocityTracker { | 
 | public: | 
 |     enum class Strategy : int32_t { | 
 |         DEFAULT = -1, | 
 |         MIN = 0, | 
 |         IMPULSE = 0, | 
 |         LSQ1 = 1, | 
 |         LSQ2 = 2, | 
 |         LSQ3 = 3, | 
 |         WLSQ2_DELTA = 4, | 
 |         WLSQ2_CENTRAL = 5, | 
 |         WLSQ2_RECENT = 6, | 
 |         INT1 = 7, | 
 |         INT2 = 8, | 
 |         LEGACY = 9, | 
 |         MAX = LEGACY, | 
 |     }; | 
 |  | 
 |     struct Position { | 
 |         float x, y; | 
 |     }; | 
 |  | 
 |     struct Estimator { | 
 |         static const size_t MAX_DEGREE = 4; | 
 |  | 
 |         // Estimator time base. | 
 |         nsecs_t time; | 
 |  | 
 |         // Polynomial coefficients describing motion in X and Y. | 
 |         float xCoeff[MAX_DEGREE + 1], yCoeff[MAX_DEGREE + 1]; | 
 |  | 
 |         // Polynomial degree (number of coefficients), or zero if no information is | 
 |         // available. | 
 |         uint32_t degree; | 
 |  | 
 |         // Confidence (coefficient of determination), between 0 (no fit) and 1 (perfect fit). | 
 |         float confidence; | 
 |  | 
 |         inline void clear() { | 
 |             time = 0; | 
 |             degree = 0; | 
 |             confidence = 0; | 
 |             for (size_t i = 0; i <= MAX_DEGREE; i++) { | 
 |                 xCoeff[i] = 0; | 
 |                 yCoeff[i] = 0; | 
 |             } | 
 |         } | 
 |     }; | 
 |  | 
 |     // Creates a velocity tracker using the specified strategy. | 
 |     // If strategy is not provided, uses the default strategy for the platform. | 
 |     VelocityTracker(const Strategy strategy = Strategy::DEFAULT); | 
 |  | 
 |     ~VelocityTracker(); | 
 |  | 
 |     // Resets the velocity tracker state. | 
 |     void clear(); | 
 |  | 
 |     // Resets the velocity tracker state for specific pointers. | 
 |     // Call this method when some pointers have changed and may be reusing | 
 |     // an id that was assigned to a different pointer earlier. | 
 |     void clearPointers(BitSet32 idBits); | 
 |  | 
 |     // Adds movement information for a set of pointers. | 
 |     // The idBits bitfield specifies the pointer ids of the pointers whose positions | 
 |     // are included in the movement. | 
 |     // The positions array contains position information for each pointer in order by | 
 |     // increasing id.  Its size should be equal to the number of one bits in idBits. | 
 |     void addMovement(nsecs_t eventTime, BitSet32 idBits, const Position* positions); | 
 |  | 
 |     // Adds movement information for all pointers in a MotionEvent, including historical samples. | 
 |     void addMovement(const MotionEvent* event); | 
 |  | 
 |     // Gets the velocity of the specified pointer id in position units per second. | 
 |     // Returns false and sets the velocity components to zero if there is | 
 |     // insufficient movement information for the pointer. | 
 |     bool getVelocity(uint32_t id, float* outVx, float* outVy) const; | 
 |  | 
 |     // Gets an estimator for the recent movements of the specified pointer id. | 
 |     // Returns false and clears the estimator if there is no information available | 
 |     // about the pointer. | 
 |     bool getEstimator(uint32_t id, Estimator* outEstimator) const; | 
 |  | 
 |     // Gets the active pointer id, or -1 if none. | 
 |     inline int32_t getActivePointerId() const { return mActivePointerId; } | 
 |  | 
 |     // Gets a bitset containing all pointer ids from the most recent movement. | 
 |     inline BitSet32 getCurrentPointerIdBits() const { return mCurrentPointerIdBits; } | 
 |  | 
 | private: | 
 |     // The default velocity tracker strategy. | 
 |     // Although other strategies are available for testing and comparison purposes, | 
 |     // this is the strategy that applications will actually use.  Be very careful | 
 |     // when adjusting the default strategy because it can dramatically affect | 
 |     // (often in a bad way) the user experience. | 
 |     static const Strategy DEFAULT_STRATEGY = Strategy::LSQ2; | 
 |  | 
 |     nsecs_t mLastEventTime; | 
 |     BitSet32 mCurrentPointerIdBits; | 
 |     int32_t mActivePointerId; | 
 |     std::unique_ptr<VelocityTrackerStrategy> mStrategy; | 
 |  | 
 |     bool configureStrategy(const Strategy strategy); | 
 |  | 
 |     static std::unique_ptr<VelocityTrackerStrategy> createStrategy(const Strategy strategy); | 
 | }; | 
 |  | 
 |  | 
 | /* | 
 |  * Implements a particular velocity tracker algorithm. | 
 |  */ | 
 | class VelocityTrackerStrategy { | 
 | protected: | 
 |     VelocityTrackerStrategy() { } | 
 |  | 
 | public: | 
 |     virtual ~VelocityTrackerStrategy() { } | 
 |  | 
 |     virtual void clear() = 0; | 
 |     virtual void clearPointers(BitSet32 idBits) = 0; | 
 |     virtual void addMovement(nsecs_t eventTime, BitSet32 idBits, | 
 |             const VelocityTracker::Position* positions) = 0; | 
 |     virtual bool getEstimator(uint32_t id, VelocityTracker::Estimator* outEstimator) const = 0; | 
 | }; | 
 |  | 
 |  | 
 | /* | 
 |  * Velocity tracker algorithm based on least-squares linear regression. | 
 |  */ | 
 | class LeastSquaresVelocityTrackerStrategy : public VelocityTrackerStrategy { | 
 | public: | 
 |     enum Weighting { | 
 |         // No weights applied.  All data points are equally reliable. | 
 |         WEIGHTING_NONE, | 
 |  | 
 |         // Weight by time delta.  Data points clustered together are weighted less. | 
 |         WEIGHTING_DELTA, | 
 |  | 
 |         // Weight such that points within a certain horizon are weighed more than those | 
 |         // outside of that horizon. | 
 |         WEIGHTING_CENTRAL, | 
 |  | 
 |         // Weight such that points older than a certain amount are weighed less. | 
 |         WEIGHTING_RECENT, | 
 |     }; | 
 |  | 
 |     // Degree must be no greater than Estimator::MAX_DEGREE. | 
 |     LeastSquaresVelocityTrackerStrategy(uint32_t degree, Weighting weighting = WEIGHTING_NONE); | 
 |     virtual ~LeastSquaresVelocityTrackerStrategy(); | 
 |  | 
 |     virtual void clear(); | 
 |     virtual void clearPointers(BitSet32 idBits); | 
 |     virtual void addMovement(nsecs_t eventTime, BitSet32 idBits, | 
 |             const VelocityTracker::Position* positions); | 
 |     virtual bool getEstimator(uint32_t id, VelocityTracker::Estimator* outEstimator) const; | 
 |  | 
 | private: | 
 |     // Sample horizon. | 
 |     // We don't use too much history by default since we want to react to quick | 
 |     // changes in direction. | 
 |     static const nsecs_t HORIZON = 100 * 1000000; // 100 ms | 
 |  | 
 |     // Number of samples to keep. | 
 |     static const uint32_t HISTORY_SIZE = 20; | 
 |  | 
 |     struct Movement { | 
 |         nsecs_t eventTime; | 
 |         BitSet32 idBits; | 
 |         VelocityTracker::Position positions[MAX_POINTERS]; | 
 |  | 
 |         inline const VelocityTracker::Position& getPosition(uint32_t id) const { | 
 |             return positions[idBits.getIndexOfBit(id)]; | 
 |         } | 
 |     }; | 
 |  | 
 |     float chooseWeight(uint32_t index) const; | 
 |  | 
 |     const uint32_t mDegree; | 
 |     const Weighting mWeighting; | 
 |     uint32_t mIndex; | 
 |     Movement mMovements[HISTORY_SIZE]; | 
 | }; | 
 |  | 
 |  | 
 | /* | 
 |  * Velocity tracker algorithm that uses an IIR filter. | 
 |  */ | 
 | class IntegratingVelocityTrackerStrategy : public VelocityTrackerStrategy { | 
 | public: | 
 |     // Degree must be 1 or 2. | 
 |     IntegratingVelocityTrackerStrategy(uint32_t degree); | 
 |     ~IntegratingVelocityTrackerStrategy(); | 
 |  | 
 |     virtual void clear(); | 
 |     virtual void clearPointers(BitSet32 idBits); | 
 |     virtual void addMovement(nsecs_t eventTime, BitSet32 idBits, | 
 |             const VelocityTracker::Position* positions); | 
 |     virtual bool getEstimator(uint32_t id, VelocityTracker::Estimator* outEstimator) const; | 
 |  | 
 | private: | 
 |     // Current state estimate for a particular pointer. | 
 |     struct State { | 
 |         nsecs_t updateTime; | 
 |         uint32_t degree; | 
 |  | 
 |         float xpos, xvel, xaccel; | 
 |         float ypos, yvel, yaccel; | 
 |     }; | 
 |  | 
 |     const uint32_t mDegree; | 
 |     BitSet32 mPointerIdBits; | 
 |     State mPointerState[MAX_POINTER_ID + 1]; | 
 |  | 
 |     void initState(State& state, nsecs_t eventTime, float xpos, float ypos) const; | 
 |     void updateState(State& state, nsecs_t eventTime, float xpos, float ypos) const; | 
 |     void populateEstimator(const State& state, VelocityTracker::Estimator* outEstimator) const; | 
 | }; | 
 |  | 
 |  | 
 | /* | 
 |  * Velocity tracker strategy used prior to ICS. | 
 |  */ | 
 | class LegacyVelocityTrackerStrategy : public VelocityTrackerStrategy { | 
 | public: | 
 |     LegacyVelocityTrackerStrategy(); | 
 |     virtual ~LegacyVelocityTrackerStrategy(); | 
 |  | 
 |     virtual void clear(); | 
 |     virtual void clearPointers(BitSet32 idBits); | 
 |     virtual void addMovement(nsecs_t eventTime, BitSet32 idBits, | 
 |             const VelocityTracker::Position* positions); | 
 |     virtual bool getEstimator(uint32_t id, VelocityTracker::Estimator* outEstimator) const; | 
 |  | 
 | private: | 
 |     // Oldest sample to consider when calculating the velocity. | 
 |     static const nsecs_t HORIZON = 200 * 1000000; // 100 ms | 
 |  | 
 |     // Number of samples to keep. | 
 |     static const uint32_t HISTORY_SIZE = 20; | 
 |  | 
 |     // The minimum duration between samples when estimating velocity. | 
 |     static const nsecs_t MIN_DURATION = 10 * 1000000; // 10 ms | 
 |  | 
 |     struct Movement { | 
 |         nsecs_t eventTime; | 
 |         BitSet32 idBits; | 
 |         VelocityTracker::Position positions[MAX_POINTERS]; | 
 |  | 
 |         inline const VelocityTracker::Position& getPosition(uint32_t id) const { | 
 |             return positions[idBits.getIndexOfBit(id)]; | 
 |         } | 
 |     }; | 
 |  | 
 |     uint32_t mIndex; | 
 |     Movement mMovements[HISTORY_SIZE]; | 
 | }; | 
 |  | 
 | class ImpulseVelocityTrackerStrategy : public VelocityTrackerStrategy { | 
 | public: | 
 |     ImpulseVelocityTrackerStrategy(); | 
 |     virtual ~ImpulseVelocityTrackerStrategy(); | 
 |  | 
 |     virtual void clear(); | 
 |     virtual void clearPointers(BitSet32 idBits); | 
 |     virtual void addMovement(nsecs_t eventTime, BitSet32 idBits, | 
 |             const VelocityTracker::Position* positions); | 
 |     virtual bool getEstimator(uint32_t id, VelocityTracker::Estimator* outEstimator) const; | 
 |  | 
 | private: | 
 |     // Sample horizon. | 
 |     // We don't use too much history by default since we want to react to quick | 
 |     // changes in direction. | 
 |     static constexpr nsecs_t HORIZON = 100 * 1000000; // 100 ms | 
 |  | 
 |     // Number of samples to keep. | 
 |     static constexpr size_t HISTORY_SIZE = 20; | 
 |  | 
 |     struct Movement { | 
 |         nsecs_t eventTime; | 
 |         BitSet32 idBits; | 
 |         VelocityTracker::Position positions[MAX_POINTERS]; | 
 |  | 
 |         inline const VelocityTracker::Position& getPosition(uint32_t id) const { | 
 |             return positions[idBits.getIndexOfBit(id)]; | 
 |         } | 
 |     }; | 
 |  | 
 |     size_t mIndex; | 
 |     Movement mMovements[HISTORY_SIZE]; | 
 | }; | 
 |  | 
 | } // namespace android | 
 |  | 
 | #endif // _LIBINPUT_VELOCITY_TRACKER_H |