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