@@ -190,6 +190,13 @@ VelocityTrackerStrategy* VelocityTracker::createStrategy(const char* strategy) {
190190 // for acceleration but it typically overestimates the effect.
191191 return new IntegratingVelocityTrackerStrategy (2 );
192192 }
193+ if (!strcmp (" legacy" , strategy)) {
194+ // Legacy velocity tracker algorithm. Quality: POOR.
195+ // For comparison purposes only. This algorithm is strongly influenced by
196+ // old data points, consistently underestimates velocity and takes a very long
197+ // time to adjust to changes in direction.
198+ return new LegacyVelocityTrackerStrategy ();
199+ }
193200 return NULL ;
194201}
195202
@@ -799,4 +806,123 @@ void IntegratingVelocityTrackerStrategy::populateEstimator(const State& state,
799806 outEstimator->yCoeff [2 ] = state.yaccel / 2 ;
800807}
801808
809+
810+ // --- LegacyVelocityTrackerStrategy ---
811+
812+ const nsecs_t LegacyVelocityTrackerStrategy::HORIZON;
813+ const uint32_t LegacyVelocityTrackerStrategy::HISTORY_SIZE;
814+ const nsecs_t LegacyVelocityTrackerStrategy::MIN_DURATION;
815+
816+ LegacyVelocityTrackerStrategy::LegacyVelocityTrackerStrategy () {
817+ clear ();
818+ }
819+
820+ LegacyVelocityTrackerStrategy::~LegacyVelocityTrackerStrategy () {
821+ }
822+
823+ void LegacyVelocityTrackerStrategy::clear () {
824+ mIndex = 0 ;
825+ mMovements [0 ].idBits .clear ();
826+ }
827+
828+ void LegacyVelocityTrackerStrategy::clearPointers (BitSet32 idBits) {
829+ BitSet32 remainingIdBits (mMovements [mIndex ].idBits .value & ~idBits.value );
830+ mMovements [mIndex ].idBits = remainingIdBits;
831+ }
832+
833+ void LegacyVelocityTrackerStrategy::addMovement (nsecs_t eventTime, BitSet32 idBits,
834+ const VelocityTracker::Position* positions) {
835+ if (++mIndex == HISTORY_SIZE) {
836+ mIndex = 0 ;
837+ }
838+
839+ Movement& movement = mMovements [mIndex ];
840+ movement.eventTime = eventTime;
841+ movement.idBits = idBits;
842+ uint32_t count = idBits.count ();
843+ for (uint32_t i = 0 ; i < count; i++) {
844+ movement.positions [i] = positions[i];
845+ }
846+ }
847+
848+ bool LegacyVelocityTrackerStrategy::getEstimator (uint32_t id,
849+ VelocityTracker::Estimator* outEstimator) const {
850+ outEstimator->clear ();
851+
852+ const Movement& newestMovement = mMovements [mIndex ];
853+ if (!newestMovement.idBits .hasBit (id)) {
854+ return false ; // no data
855+ }
856+
857+ // Find the oldest sample that contains the pointer and that is not older than HORIZON.
858+ nsecs_t minTime = newestMovement.eventTime - HORIZON;
859+ uint32_t oldestIndex = mIndex ;
860+ uint32_t numTouches = 1 ;
861+ do {
862+ uint32_t nextOldestIndex = (oldestIndex == 0 ? HISTORY_SIZE : oldestIndex) - 1 ;
863+ const Movement& nextOldestMovement = mMovements [nextOldestIndex];
864+ if (!nextOldestMovement.idBits .hasBit (id)
865+ || nextOldestMovement.eventTime < minTime) {
866+ break ;
867+ }
868+ oldestIndex = nextOldestIndex;
869+ } while (++numTouches < HISTORY_SIZE);
870+
871+ // Calculate an exponentially weighted moving average of the velocity estimate
872+ // at different points in time measured relative to the oldest sample.
873+ // This is essentially an IIR filter. Newer samples are weighted more heavily
874+ // than older samples. Samples at equal time points are weighted more or less
875+ // equally.
876+ //
877+ // One tricky problem is that the sample data may be poorly conditioned.
878+ // Sometimes samples arrive very close together in time which can cause us to
879+ // overestimate the velocity at that time point. Most samples might be measured
880+ // 16ms apart but some consecutive samples could be only 0.5sm apart because
881+ // the hardware or driver reports them irregularly or in bursts.
882+ float accumVx = 0 ;
883+ float accumVy = 0 ;
884+ uint32_t index = oldestIndex;
885+ uint32_t samplesUsed = 0 ;
886+ const Movement& oldestMovement = mMovements [oldestIndex];
887+ const VelocityTracker::Position& oldestPosition = oldestMovement.getPosition (id);
888+ nsecs_t lastDuration = 0 ;
889+
890+ while (numTouches-- > 1 ) {
891+ if (++index == HISTORY_SIZE) {
892+ index = 0 ;
893+ }
894+ const Movement& movement = mMovements [index];
895+ nsecs_t duration = movement.eventTime - oldestMovement.eventTime ;
896+
897+ // If the duration between samples is small, we may significantly overestimate
898+ // the velocity. Consequently, we impose a minimum duration constraint on the
899+ // samples that we include in the calculation.
900+ if (duration >= MIN_DURATION) {
901+ const VelocityTracker::Position& position = movement.getPosition (id);
902+ float scale = 1000000000 .0f / duration; // one over time delta in seconds
903+ float vx = (position.x - oldestPosition.x ) * scale;
904+ float vy = (position.y - oldestPosition.y ) * scale;
905+ accumVx = (accumVx * lastDuration + vx * duration) / (duration + lastDuration);
906+ accumVy = (accumVy * lastDuration + vy * duration) / (duration + lastDuration);
907+ lastDuration = duration;
908+ samplesUsed += 1 ;
909+ }
910+ }
911+
912+ // Report velocity.
913+ const VelocityTracker::Position& newestPosition = newestMovement.getPosition (id);
914+ outEstimator->time = newestMovement.eventTime ;
915+ outEstimator->confidence = 1 ;
916+ outEstimator->xCoeff [0 ] = newestPosition.x ;
917+ outEstimator->yCoeff [0 ] = newestPosition.y ;
918+ if (samplesUsed) {
919+ outEstimator->xCoeff [1 ] = accumVx;
920+ outEstimator->yCoeff [1 ] = accumVy;
921+ outEstimator->degree = 1 ;
922+ } else {
923+ outEstimator->degree = 0 ;
924+ }
925+ return true ;
926+ }
927+
802928} // namespace android
0 commit comments