• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2006 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 package android.view;
18 
19 import android.util.Poolable;
20 import android.util.Pool;
21 import android.util.Pools;
22 import android.util.PoolableManager;
23 
24 /**
25  * Helper for tracking the velocity of touch events, for implementing
26  * flinging and other such gestures.
27  *
28  * Use {@link #obtain} to retrieve a new instance of the class when you are going
29  * to begin tracking.  Put the motion events you receive into it with
30  * {@link #addMovement(MotionEvent)}.  When you want to determine the velocity call
31  * {@link #computeCurrentVelocity(int)} and then call {@link #getXVelocity(int)}
32  * and {@link #getXVelocity(int)} to retrieve the velocity for each pointer id.
33  */
34 public final class VelocityTracker implements Poolable<VelocityTracker> {
35     private static final Pool<VelocityTracker> sPool = Pools.synchronizedPool(
36             Pools.finitePool(new PoolableManager<VelocityTracker>() {
37                 public VelocityTracker newInstance() {
38                     return new VelocityTracker();
39                 }
40 
41                 public void onAcquired(VelocityTracker element) {
42                 }
43 
44                 public void onReleased(VelocityTracker element) {
45                     element.clear();
46                 }
47             }, 2));
48 
49     private static final int ACTIVE_POINTER_ID = -1;
50 
51     private int mPtr;
52     private VelocityTracker mNext;
53     private boolean mIsPooled;
54 
nativeInitialize()55     private static native int nativeInitialize();
nativeDispose(int ptr)56     private static native void nativeDispose(int ptr);
nativeClear(int ptr)57     private static native void nativeClear(int ptr);
nativeAddMovement(int ptr, MotionEvent event)58     private static native void nativeAddMovement(int ptr, MotionEvent event);
nativeComputeCurrentVelocity(int ptr, int units, float maxVelocity)59     private static native void nativeComputeCurrentVelocity(int ptr, int units, float maxVelocity);
nativeGetXVelocity(int ptr, int id)60     private static native float nativeGetXVelocity(int ptr, int id);
nativeGetYVelocity(int ptr, int id)61     private static native float nativeGetYVelocity(int ptr, int id);
nativeGetEstimator(int ptr, int id, int degree, int horizonMillis, Estimator outEstimator)62     private static native boolean nativeGetEstimator(int ptr, int id,
63             int degree, int horizonMillis, Estimator outEstimator);
64 
65     /**
66      * Retrieve a new VelocityTracker object to watch the velocity of a
67      * motion.  Be sure to call {@link #recycle} when done.  You should
68      * generally only maintain an active object while tracking a movement,
69      * so that the VelocityTracker can be re-used elsewhere.
70      *
71      * @return Returns a new VelocityTracker.
72      */
obtain()73     static public VelocityTracker obtain() {
74         return sPool.acquire();
75     }
76 
77     /**
78      * Return a VelocityTracker object back to be re-used by others.  You must
79      * not touch the object after calling this function.
80      */
recycle()81     public void recycle() {
82         sPool.release(this);
83     }
84 
85     /**
86      * @hide
87      */
setNextPoolable(VelocityTracker element)88     public void setNextPoolable(VelocityTracker element) {
89         mNext = element;
90     }
91 
92     /**
93      * @hide
94      */
getNextPoolable()95     public VelocityTracker getNextPoolable() {
96         return mNext;
97     }
98 
99     /**
100      * @hide
101      */
isPooled()102     public boolean isPooled() {
103         return mIsPooled;
104     }
105 
106     /**
107      * @hide
108      */
setPooled(boolean isPooled)109     public void setPooled(boolean isPooled) {
110         mIsPooled = isPooled;
111     }
112 
VelocityTracker()113     private VelocityTracker() {
114         mPtr = nativeInitialize();
115     }
116 
117     @Override
finalize()118     protected void finalize() throws Throwable {
119         try {
120             if (mPtr != 0) {
121                 nativeDispose(mPtr);
122                 mPtr = 0;
123             }
124         } finally {
125             super.finalize();
126         }
127     }
128 
129     /**
130      * Reset the velocity tracker back to its initial state.
131      */
clear()132     public void clear() {
133         nativeClear(mPtr);
134     }
135 
136     /**
137      * Add a user's movement to the tracker.  You should call this for the
138      * initial {@link MotionEvent#ACTION_DOWN}, the following
139      * {@link MotionEvent#ACTION_MOVE} events that you receive, and the
140      * final {@link MotionEvent#ACTION_UP}.  You can, however, call this
141      * for whichever events you desire.
142      *
143      * @param event The MotionEvent you received and would like to track.
144      */
addMovement(MotionEvent event)145     public void addMovement(MotionEvent event) {
146         if (event == null) {
147             throw new IllegalArgumentException("event must not be null");
148         }
149         nativeAddMovement(mPtr, event);
150     }
151 
152     /**
153      * Equivalent to invoking {@link #computeCurrentVelocity(int, float)} with a maximum
154      * velocity of Float.MAX_VALUE.
155      *
156      * @see #computeCurrentVelocity(int, float)
157      */
computeCurrentVelocity(int units)158     public void computeCurrentVelocity(int units) {
159         nativeComputeCurrentVelocity(mPtr, units, Float.MAX_VALUE);
160     }
161 
162     /**
163      * Compute the current velocity based on the points that have been
164      * collected.  Only call this when you actually want to retrieve velocity
165      * information, as it is relatively expensive.  You can then retrieve
166      * the velocity with {@link #getXVelocity()} and
167      * {@link #getYVelocity()}.
168      *
169      * @param units The units you would like the velocity in.  A value of 1
170      * provides pixels per millisecond, 1000 provides pixels per second, etc.
171      * @param maxVelocity The maximum velocity that can be computed by this method.
172      * This value must be declared in the same unit as the units parameter. This value
173      * must be positive.
174      */
computeCurrentVelocity(int units, float maxVelocity)175     public void computeCurrentVelocity(int units, float maxVelocity) {
176         nativeComputeCurrentVelocity(mPtr, units, maxVelocity);
177     }
178 
179     /**
180      * Retrieve the last computed X velocity.  You must first call
181      * {@link #computeCurrentVelocity(int)} before calling this function.
182      *
183      * @return The previously computed X velocity.
184      */
getXVelocity()185     public float getXVelocity() {
186         return nativeGetXVelocity(mPtr, ACTIVE_POINTER_ID);
187     }
188 
189     /**
190      * Retrieve the last computed Y velocity.  You must first call
191      * {@link #computeCurrentVelocity(int)} before calling this function.
192      *
193      * @return The previously computed Y velocity.
194      */
getYVelocity()195     public float getYVelocity() {
196         return nativeGetYVelocity(mPtr, ACTIVE_POINTER_ID);
197     }
198 
199     /**
200      * Retrieve the last computed X velocity.  You must first call
201      * {@link #computeCurrentVelocity(int)} before calling this function.
202      *
203      * @param id Which pointer's velocity to return.
204      * @return The previously computed X velocity.
205      */
getXVelocity(int id)206     public float getXVelocity(int id) {
207         return nativeGetXVelocity(mPtr, id);
208     }
209 
210     /**
211      * Retrieve the last computed Y velocity.  You must first call
212      * {@link #computeCurrentVelocity(int)} before calling this function.
213      *
214      * @param id Which pointer's velocity to return.
215      * @return The previously computed Y velocity.
216      */
getYVelocity(int id)217     public float getYVelocity(int id) {
218         return nativeGetYVelocity(mPtr, id);
219     }
220 
221     /**
222      * Get an estimator for the movements of a pointer using past movements of the
223      * pointer to predict future movements.
224      *
225      * It is not necessary to call {@link #computeCurrentVelocity(int)} before calling
226      * this method.
227      *
228      * @param id Which pointer's velocity to return.
229      * @param degree The desired polynomial degree.  The actual estimator may have
230      * a lower degree than what is requested here.  If -1, uses the default degree.
231      * @param horizonMillis The maximum age of the oldest sample to consider, in milliseconds.
232      * If -1, uses the default horizon.
233      * @param outEstimator The estimator to populate.
234      * @return True if an estimator was obtained, false if there is no information
235      * available about the pointer.
236      *
237      * @hide For internal use only.  Not a final API.
238      */
getEstimator(int id, int degree, int horizonMillis, Estimator outEstimator)239     public boolean getEstimator(int id, int degree, int horizonMillis, Estimator outEstimator) {
240         if (outEstimator == null) {
241             throw new IllegalArgumentException("outEstimator must not be null");
242         }
243         return nativeGetEstimator(mPtr, id, degree, horizonMillis, outEstimator);
244     }
245 
246     /**
247      * An estimator for the movements of a pointer based on a polynomial model.
248      *
249      * The last recorded position of the pointer is at time zero seconds.
250      * Past estimated positions are at negative times and future estimated positions
251      * are at positive times.
252      *
253      * First coefficient is position (in pixels), second is velocity (in pixels per second),
254      * third is acceleration (in pixels per second squared).
255      *
256      * @hide For internal use only.  Not a final API.
257      */
258     public static final class Estimator {
259         // Must match VelocityTracker::Estimator::MAX_DEGREE
260         private static final int MAX_DEGREE = 2;
261 
262         /**
263          * Polynomial coefficients describing motion in X.
264          */
265         public final float[] xCoeff = new float[MAX_DEGREE + 1];
266 
267         /**
268          * Polynomial coefficients describing motion in Y.
269          */
270         public final float[] yCoeff = new float[MAX_DEGREE + 1];
271 
272         /**
273          * Polynomial degree, or zero if only position information is available.
274          */
275         public int degree;
276 
277         /**
278          * Confidence (coefficient of determination), between 0 (no fit) and 1 (perfect fit).
279          */
280         public float confidence;
281 
282         /**
283          * Gets an estimate of the X position of the pointer at the specified time point.
284          * @param time The time point in seconds, 0 is the last recorded time.
285          * @return The estimated X coordinate.
286          */
estimateX(float time)287         public float estimateX(float time) {
288             return estimate(time, xCoeff);
289         }
290 
291         /**
292          * Gets an estimate of the Y position of the pointer at the specified time point.
293          * @param time The time point in seconds, 0 is the last recorded time.
294          * @return The estimated Y coordinate.
295          */
estimateY(float time)296         public float estimateY(float time) {
297             return estimate(time, yCoeff);
298         }
299 
estimate(float time, float[] c)300         private float estimate(float time, float[] c) {
301             float a = 0;
302             float scale = 1;
303             for (int i = 0; i <= degree; i++) {
304                 a += c[i] * scale;
305                 scale *= time;
306             }
307             return a;
308         }
309     }
310 }
311