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