blob: dfb2c328021531f50075af92989c1dde578fdab3 [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
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
17package android.view;
18
Romain Guyd928d682009-03-31 17:52:16 -070019import android.util.Poolable;
20import android.util.Pool;
Romain Guy2e9bbce2009-04-01 10:40:10 -070021import android.util.Pools;
Romain Guyd928d682009-03-31 17:52:16 -070022import android.util.PoolableManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080023
24/**
25 * Helper for tracking the velocity of touch events, for implementing
Jeff Brown2ed24622011-03-14 19:39:54 -070026 * 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.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080033 */
Romain Guyd928d682009-03-31 17:52:16 -070034public final class VelocityTracker implements Poolable<VelocityTracker> {
Romain Guy2e9bbce2009-04-01 10:40:10 -070035 private static final Pool<VelocityTracker> sPool = Pools.synchronizedPool(
36 Pools.finitePool(new PoolableManager<VelocityTracker>() {
Romain Guyd928d682009-03-31 17:52:16 -070037 public VelocityTracker newInstance() {
38 return new VelocityTracker();
39 }
40
41 public void onAcquired(VelocityTracker element) {
Romain Guyd928d682009-03-31 17:52:16 -070042 }
43
44 public void onReleased(VelocityTracker element) {
Jeff Brown88cf2fc2010-08-09 18:50:35 -070045 element.clear();
Romain Guyd928d682009-03-31 17:52:16 -070046 }
47 }, 2));
Romain Guyd928d682009-03-31 17:52:16 -070048
Jeff Brown2ed24622011-03-14 19:39:54 -070049 private static final int ACTIVE_POINTER_ID = -1;
50
51 private int mPtr;
Romain Guyd928d682009-03-31 17:52:16 -070052 private VelocityTracker mNext;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -070053 private boolean mIsPooled;
Romain Guyd928d682009-03-31 17:52:16 -070054
Jeff Brown2ed24622011-03-14 19:39:54 -070055 private static native int nativeInitialize();
56 private static native void nativeDispose(int ptr);
57 private static native void nativeClear(int ptr);
58 private static native void nativeAddMovement(int ptr, MotionEvent event);
59 private static native void nativeComputeCurrentVelocity(int ptr, int units, float maxVelocity);
60 private static native float nativeGetXVelocity(int ptr, int id);
61 private static native float nativeGetYVelocity(int ptr, int id);
Jeff Brownb59ab9f2011-09-14 10:53:18 -070062 private static native boolean nativeGetEstimator(int ptr, int id,
63 int degree, int horizonMillis, Estimator outEstimator);
Jeff Brown2ed24622011-03-14 19:39:54 -070064
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080065 /**
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.
Romain Guyd928d682009-03-31 17:52:16 -070070 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080071 * @return Returns a new VelocityTracker.
72 */
73 static public VelocityTracker obtain() {
Romain Guyd928d682009-03-31 17:52:16 -070074 return sPool.acquire();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080075 }
Romain Guyd928d682009-03-31 17:52:16 -070076
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080077 /**
78 * Return a VelocityTracker object back to be re-used by others. You must
79 * not touch the object after calling this function.
80 */
81 public void recycle() {
Romain Guyd928d682009-03-31 17:52:16 -070082 sPool.release(this);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080083 }
Romain Guyd928d682009-03-31 17:52:16 -070084
85 /**
86 * @hide
87 */
88 public void setNextPoolable(VelocityTracker element) {
89 mNext = element;
90 }
91
92 /**
93 * @hide
94 */
95 public VelocityTracker getNextPoolable() {
96 return mNext;
97 }
98
Svetoslav Ganov8643aa02011-04-20 12:12:33 -070099 /**
100 * @hide
101 */
102 public boolean isPooled() {
103 return mIsPooled;
104 }
105
106 /**
107 * @hide
108 */
109 public void setPooled(boolean isPooled) {
110 mIsPooled = isPooled;
111 }
112
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800113 private VelocityTracker() {
Jeff Brown2ed24622011-03-14 19:39:54 -0700114 mPtr = nativeInitialize();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800115 }
Jeff Brown2ed24622011-03-14 19:39:54 -0700116
117 @Override
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
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800129 /**
130 * Reset the velocity tracker back to its initial state.
131 */
132 public void clear() {
Jeff Brown2ed24622011-03-14 19:39:54 -0700133 nativeClear(mPtr);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800134 }
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 *
Jeff Brown2ed24622011-03-14 19:39:54 -0700143 * @param event The MotionEvent you received and would like to track.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800144 */
Jeff Brown2ed24622011-03-14 19:39:54 -0700145 public void addMovement(MotionEvent event) {
146 if (event == null) {
147 throw new IllegalArgumentException("event must not be null");
Adam Powell73d8fca2010-02-12 16:50:19 -0800148 }
Jeff Brown2ed24622011-03-14 19:39:54 -0700149 nativeAddMovement(mPtr, event);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800150 }
Romain Guy4296fc42009-07-06 11:48:52 -0700151
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 */
158 public void computeCurrentVelocity(int units) {
Jeff Brown2ed24622011-03-14 19:39:54 -0700159 nativeComputeCurrentVelocity(mPtr, units, Float.MAX_VALUE);
Romain Guy4296fc42009-07-06 11:48:52 -0700160 }
161
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800162 /**
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.
Romain Guy4296fc42009-07-06 11:48:52 -0700171 * @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.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800174 */
Romain Guy4296fc42009-07-06 11:48:52 -0700175 public void computeCurrentVelocity(int units, float maxVelocity) {
Jeff Brown2ed24622011-03-14 19:39:54 -0700176 nativeComputeCurrentVelocity(mPtr, units, maxVelocity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800177 }
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 */
185 public float getXVelocity() {
Jeff Brown2ed24622011-03-14 19:39:54 -0700186 return nativeGetXVelocity(mPtr, ACTIVE_POINTER_ID);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800187 }
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 */
195 public float getYVelocity() {
Jeff Brown2ed24622011-03-14 19:39:54 -0700196 return nativeGetYVelocity(mPtr, ACTIVE_POINTER_ID);
Adam Powell8acdb202010-01-06 17:33:52 -0800197 }
198
199 /**
200 * Retrieve the last computed X velocity. You must first call
201 * {@link #computeCurrentVelocity(int)} before calling this function.
202 *
Adam Powell73d8fca2010-02-12 16:50:19 -0800203 * @param id Which pointer's velocity to return.
Adam Powell8acdb202010-01-06 17:33:52 -0800204 * @return The previously computed X velocity.
Adam Powell8acdb202010-01-06 17:33:52 -0800205 */
Adam Powell73d8fca2010-02-12 16:50:19 -0800206 public float getXVelocity(int id) {
Jeff Brown2ed24622011-03-14 19:39:54 -0700207 return nativeGetXVelocity(mPtr, id);
Adam Powell8acdb202010-01-06 17:33:52 -0800208 }
209
210 /**
211 * Retrieve the last computed Y velocity. You must first call
212 * {@link #computeCurrentVelocity(int)} before calling this function.
213 *
Adam Powell73d8fca2010-02-12 16:50:19 -0800214 * @param id Which pointer's velocity to return.
Adam Powell8acdb202010-01-06 17:33:52 -0800215 * @return The previously computed Y velocity.
Adam Powell8acdb202010-01-06 17:33:52 -0800216 */
Adam Powell73d8fca2010-02-12 16:50:19 -0800217 public float getYVelocity(int id) {
Jeff Brown2ed24622011-03-14 19:39:54 -0700218 return nativeGetYVelocity(mPtr, id);
Jeff Brown88cf2fc2010-08-09 18:50:35 -0700219 }
Jeff Brownb59ab9f2011-09-14 10:53:18 -0700220
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 */
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 */
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 */
296 public float estimateY(float time) {
297 return estimate(time, yCoeff);
298 }
299
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 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800310}