• 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