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