MotionEvent.java revision f013e1afd1e68af5e3b868c26a653bbfb39538f8
1/*
2 * Copyright (C) 2007 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.os.Parcel;
20import android.os.Parcelable;
21import android.os.SystemClock;
22import android.util.Config;
23
24/**
25 * Object used to report movement (mouse, pen, finger, trackball) events.  This
26 * class may hold either absolute or relative movements, depending on what
27 * it is being used for.
28 */
29public final class MotionEvent implements Parcelable {
30    /**
31     * Constant for {@link #getAction}: A pressed gesture has started, the
32     * motion contains the initial starting location.
33     */
34    public static final int ACTION_DOWN             = 0;
35    /**
36     * Constant for {@link #getAction}: A pressed gesture has finished, the
37     * motion contains the final release location as well as any intermediate
38     * points since the last down or move event.
39     */
40    public static final int ACTION_UP               = 1;
41    /**
42     * Constant for {@link #getAction}: A change has happened during a
43     * press gesture (between {@link #ACTION_DOWN} and {@link #ACTION_UP}).
44     * The motion contains the most recent point, as well as any intermediate
45     * points since the last down or move event.
46     */
47    public static final int ACTION_MOVE             = 2;
48    /**
49     * Constant for {@link #getAction}: The current gesture has been aborted.
50     * You will not receive any more points in it.  You should treat this as
51     * an up event, but not perform any action that you normally would.
52     */
53    public static final int ACTION_CANCEL           = 3;
54    /**
55     * Constant for {@link #getAction}: A movement has happened outside of the
56     * normal bounds of the UI element.  This does not provide a full gesture,
57     * but only the initial location of the movement/touch.
58     */
59    public static final int ACTION_OUTSIDE          = 4;
60
61    private static final boolean TRACK_RECYCLED_LOCATION = false;
62
63    /**
64     * Flag indicating the motion event intersected the top edge of the screen.
65     */
66    public static final int EDGE_TOP = 0x00000001;
67
68    /**
69     * Flag indicating the motion event intersected the bottom edge of the screen.
70     */
71    public static final int EDGE_BOTTOM = 0x00000002;
72
73    /**
74     * Flag indicating the motion event intersected the left edge of the screen.
75     */
76    public static final int EDGE_LEFT = 0x00000004;
77
78    /**
79     * Flag indicating the motion event intersected the right edge of the screen.
80     */
81    public static final int EDGE_RIGHT = 0x00000008;
82
83    static private final int MAX_RECYCLED = 10;
84    static private Object gRecyclerLock = new Object();
85    static private int gRecyclerUsed = 0;
86    static private MotionEvent gRecyclerTop = null;
87
88    private long mDownTime;
89    private long mEventTime;
90    private int mAction;
91    private float mX;
92    private float mY;
93    private float mRawX;
94    private float mRawY;
95    private float mPressure;
96    private float mSize;
97    private int mMetaState;
98    private int mNumHistory;
99    private float[] mHistory;
100    private long[] mHistoryTimes;
101    private float mXPrecision;
102    private float mYPrecision;
103    private int mDeviceId;
104    private int mEdgeFlags;
105
106    private MotionEvent mNext;
107    private RuntimeException mRecycledLocation;
108    private boolean mRecycled;
109
110    private MotionEvent() {
111    }
112
113    static private MotionEvent obtain() {
114        synchronized (gRecyclerLock) {
115            if (gRecyclerTop == null) {
116                return new MotionEvent();
117            }
118            MotionEvent ev = gRecyclerTop;
119            gRecyclerTop = ev.mNext;
120            gRecyclerUsed--;
121            ev.mRecycledLocation = null;
122            ev.mRecycled = false;
123            return ev;
124        }
125    }
126
127    /**
128     * Create a new MotionEvent, filling in all of the basic values that
129     * define the motion.
130     *
131     * @param downTime The time (in ms) when the user originally pressed down to start
132     * a stream of position events.  This must be obtained from {@link SystemClock#uptimeMillis()}.
133     * @param eventTime  The the time (in ms) when this specific event was generated.  This
134     * must be obtained from {@link SystemClock#uptimeMillis()}.
135     * @param action The kind of action being performed -- one of either
136     * {@link #ACTION_DOWN}, {@link #ACTION_MOVE}, {@link #ACTION_UP}, or
137     * {@link #ACTION_CANCEL}.
138     * @param x The X coordinate of this event.
139     * @param y The Y coordinate of this event.
140     * @param pressure The current pressure of this event.  The pressure generally
141     * ranges from 0 (no pressure at all) to 1 (normal pressure), however
142     * values higher than 1 may be generated depending on the calibration of
143     * the input device.
144     * @param size A scaled value of the approximate size of the area being pressed when
145     * touched with the finger. The actual value in pixels corresponding to the finger
146     * touch is normalized with a device specific range of values
147     * and scaled to a value between 0 and 1.
148     * @param metaState The state of any meta / modifier keys that were in effect when
149     * the event was generated.
150     * @param xPrecision The precision of the X coordinate being reported.
151     * @param yPrecision The precision of the Y coordinate being reported.
152     * @param deviceId The id for the device that this event came from.  An id of
153     * zero indicates that the event didn't come from a physical device; other
154     * numbers are arbitrary and you shouldn't depend on the values.
155     * @param edgeFlags A bitfield indicating which edges, if any, where touched by this
156     * MotionEvent.
157     */
158    static public MotionEvent obtain(long downTime, long eventTime, int action,
159            float x, float y, float pressure, float size, int metaState,
160            float xPrecision, float yPrecision, int deviceId, int edgeFlags) {
161        MotionEvent ev = obtain();
162        ev.mDeviceId = deviceId;
163        ev.mEdgeFlags = edgeFlags;
164        ev.mDownTime = downTime;
165        ev.mEventTime = eventTime;
166        ev.mAction = action;
167        ev.mX = ev.mRawX = x;
168        ev.mY = ev.mRawY = y;
169        ev.mPressure = pressure;
170        ev.mSize = size;
171        ev.mMetaState = metaState;
172        ev.mXPrecision = xPrecision;
173        ev.mYPrecision = yPrecision;
174
175        return ev;
176    }
177
178    /**
179     * Create a new MotionEvent, filling in a subset of the basic motion
180     * values.  Those not specified here are: device id (always 0), pressure
181     * and size (always 1), x and y precision (always 1), and edgeFlags (always 0).
182     *
183     * @param downTime The time (in ms) when the user originally pressed down to start
184     * a stream of position events.  This must be obtained from {@link SystemClock#uptimeMillis()}.
185     * @param eventTime  The the time (in ms) when this specific event was generated.  This
186     * must be obtained from {@link SystemClock#uptimeMillis()}.
187     * @param action The kind of action being performed -- one of either
188     * {@link #ACTION_DOWN}, {@link #ACTION_MOVE}, {@link #ACTION_UP}, or
189     * {@link #ACTION_CANCEL}.
190     * @param x The X coordinate of this event.
191     * @param y The Y coordinate of this event.
192     * @param metaState The state of any meta / modifier keys that were in effect when
193     * the event was generated.
194     */
195    static public MotionEvent obtain(long downTime, long eventTime, int action,
196            float x, float y, int metaState) {
197        MotionEvent ev = obtain();
198        ev.mDeviceId = 0;
199        ev.mEdgeFlags = 0;
200        ev.mDownTime = downTime;
201        ev.mEventTime = eventTime;
202        ev.mAction = action;
203        ev.mX = ev.mRawX = x;
204        ev.mY = ev.mRawY = y;
205        ev.mPressure = 1.0f;
206        ev.mSize = 1.0f;
207        ev.mMetaState = metaState;
208        ev.mXPrecision = 1.0f;
209        ev.mYPrecision = 1.0f;
210
211        return ev;
212    }
213
214    /**
215     * Create a new MotionEvent, copying from an existing one.
216     */
217    static public MotionEvent obtain(MotionEvent o) {
218        MotionEvent ev = obtain();
219        ev.mDeviceId = o.mDeviceId;
220        ev.mEdgeFlags = o.mEdgeFlags;
221        ev.mDownTime = o.mDownTime;
222        ev.mEventTime = o.mEventTime;
223        ev.mAction = o.mAction;
224        ev.mX = o.mX;
225        ev.mRawX = o.mRawX;
226        ev.mY = o.mY;
227        ev.mRawY = o.mRawY;
228        ev.mPressure = o.mPressure;
229        ev.mSize = o.mSize;
230        ev.mMetaState = o.mMetaState;
231        ev.mXPrecision = o.mXPrecision;
232        ev.mYPrecision = o.mYPrecision;
233        final int N = o.mNumHistory;
234        ev.mNumHistory = N;
235        if (N > 0) {
236            // could be more efficient about this...
237            ev.mHistory = (float[])o.mHistory.clone();
238            ev.mHistoryTimes = (long[])o.mHistoryTimes.clone();
239        }
240        return ev;
241    }
242
243    /**
244     * Recycle the MotionEvent, to be re-used by a later caller.  After calling
245     * this function you must not ever touch the event again.
246     */
247    public void recycle() {
248        // Ensure recycle is only called once!
249        if (TRACK_RECYCLED_LOCATION) {
250            if (mRecycledLocation != null) {
251                throw new RuntimeException(toString() + " recycled twice!", mRecycledLocation);
252            }
253            mRecycledLocation = new RuntimeException("Last recycled here");
254        } else if (mRecycled) {
255            throw new RuntimeException(toString() + " recycled twice!");
256        }
257
258        //Log.w("MotionEvent", "Recycling event " + this, mRecycledLocation);
259        synchronized (gRecyclerLock) {
260            if (gRecyclerUsed < MAX_RECYCLED) {
261                gRecyclerUsed++;
262                mNumHistory = 0;
263                mNext = gRecyclerTop;
264                gRecyclerTop = this;
265            }
266        }
267    }
268
269    /**
270     * Return the kind of action being performed -- one of either
271     * {@link #ACTION_DOWN}, {@link #ACTION_MOVE}, {@link #ACTION_UP}, or
272     * {@link #ACTION_CANCEL}.
273     */
274    public final int getAction() {
275        return mAction;
276    }
277
278    /**
279     * Returns the time (in ms) when the user originally pressed down to start
280     * a stream of position events.
281     */
282    public final long getDownTime() {
283        return mDownTime;
284    }
285
286    /**
287     * Returns the time (in ms) when this specific event was generated.
288     */
289    public final long getEventTime() {
290        return mEventTime;
291    }
292
293    /**
294     * Returns the X coordinate of this event.  Whole numbers are pixels; the
295     * value may have a fraction for input devices that are sub-pixel precise.
296     */
297    public final float getX() {
298        return mX;
299    }
300
301    /**
302     * Returns the Y coordinate of this event.  Whole numbers are pixels; the
303     * value may have a fraction for input devices that are sub-pixel precise.
304     */
305    public final float getY() {
306        return mY;
307    }
308
309    /**
310     * Returns the current pressure of this event.  The pressure generally
311     * ranges from 0 (no pressure at all) to 1 (normal pressure), however
312     * values higher than 1 may be generated depending on the calibration of
313     * the input device.
314     */
315    public final float getPressure() {
316        return mPressure;
317    }
318
319    /**
320     * Returns a scaled value of the approximate size, of the area being pressed when
321     * touched with the finger. The actual value in pixels corresponding to the finger
322     * touch  is normalized with the device specific range of values
323     * and scaled to a value between 0 and 1. The value of size can be used to
324     * determine fat touch events.
325     */
326    public final float getSize() {
327        return mSize;
328    }
329
330    /**
331     * Returns the state of any meta / modifier keys that were in effect when
332     * the event was generated.  This is the same values as those
333     * returned by {@link KeyEvent#getMetaState() KeyEvent.getMetaState}.
334     *
335     * @return an integer in which each bit set to 1 represents a pressed
336     *         meta key
337     *
338     * @see KeyEvent#getMetaState()
339     */
340    public final int getMetaState() {
341        return mMetaState;
342    }
343
344    /**
345     * Returns the original raw X coordinate of this event.  For touch
346     * events on the screen, this is the original location of the event
347     * on the screen, before it had been adjusted for the containing window
348     * and views.
349     */
350    public final float getRawX() {
351        return mRawX;
352    }
353
354    /**
355     * Returns the original raw Y coordinate of this event.  For touch
356     * events on the screen, this is the original location of the event
357     * on the screen, before it had been adjusted for the containing window
358     * and views.
359     */
360    public final float getRawY() {
361        return mRawY;
362    }
363
364    /**
365     * Return the precision of the X coordinates being reported.  You can
366     * multiple this number with {@link #getX} to find the actual hardware
367     * value of the X coordinate.
368     * @return Returns the precision of X coordinates being reported.
369     */
370    public final float getXPrecision() {
371        return mXPrecision;
372    }
373
374    /**
375     * Return the precision of the Y coordinates being reported.  You can
376     * multiple this number with {@link #getY} to find the actual hardware
377     * value of the Y coordinate.
378     * @return Returns the precision of Y coordinates being reported.
379     */
380    public final float getYPrecision() {
381        return mYPrecision;
382    }
383
384    /**
385     * Returns the number of historical points in this event.  These are
386     * movements that have occurred between this event and the previous event.
387     * This only applies to ACTION_MOVE events -- all other actions will have
388     * a size of 0.
389     *
390     * @return Returns the number of historical points in the event.
391     */
392    public final int getHistorySize() {
393        return mNumHistory;
394    }
395
396    /**
397     * Returns the time that a historical movement occurred between this event
398     * and the previous event.  Only applies to ACTION_MOVE events.
399     *
400     * @param pos Which historical value to return; must be less than
401     * {@link #getHistorySize}
402     *
403     * @see #getHistorySize
404     * @see #getEventTime
405     */
406    public final long getHistoricalEventTime(int pos) {
407        return mHistoryTimes[pos];
408    }
409
410    /**
411     * Returns a historical X coordinate that occurred between this event
412     * and the previous event.  Only applies to ACTION_MOVE events.
413     *
414     * @param pos Which historical value to return; must be less than
415     * {@link #getHistorySize}
416     *
417     * @see #getHistorySize
418     * @see #getX
419     */
420    public final float getHistoricalX(int pos) {
421        return mHistory[pos*4];
422    }
423
424    /**
425     * Returns a historical Y coordinate that occurred between this event
426     * and the previous event.  Only applies to ACTION_MOVE events.
427     *
428     * @param pos Which historical value to return; must be less than
429     * {@link #getHistorySize}
430     *
431     * @see #getHistorySize
432     * @see #getY
433     */
434    public final float getHistoricalY(int pos) {
435        return mHistory[pos*4 + 1];
436    }
437
438    /**
439     * Returns a historical pressure coordinate that occurred between this event
440     * and the previous event.  Only applies to ACTION_MOVE events.
441     *
442     * @param pos Which historical value to return; must be less than
443     * {@link #getHistorySize}
444     *
445     * @see #getHistorySize
446     * @see #getPressure
447     */
448    public final float getHistoricalPressure(int pos) {
449        return mHistory[pos*4 + 2];
450    }
451
452    /**
453     * Returns a historical size coordinate that occurred between this event
454     * and the previous event.  Only applies to ACTION_MOVE events.
455     *
456     * @param pos Which historical value to return; must be less than
457     * {@link #getHistorySize}
458     *
459     * @see #getHistorySize
460     * @see #getSize
461     */
462    public final float getHistoricalSize(int pos) {
463        return mHistory[pos*4 + 3];
464    }
465
466    /**
467     * Return the id for the device that this event came from.  An id of
468     * zero indicates that the event didn't come from a physical device; other
469     * numbers are arbitrary and you shouldn't depend on the values.
470     */
471    public final int getDeviceId() {
472        return mDeviceId;
473    }
474
475    /**
476     * Returns a bitfield indicating which edges, if any, where touched by this
477     * MotionEvent. For touch events, clients can use this to determine if the
478     * user's finger was touching the edge of the display.
479     *
480     * @see #EDGE_LEFT
481     * @see #EDGE_TOP
482     * @see #EDGE_RIGHT
483     * @see #EDGE_BOTTOM
484     */
485    public final int getEdgeFlags() {
486        return mEdgeFlags;
487    }
488
489
490    /**
491     * Sets the bitfield indicating which edges, if any, where touched by this
492     * MotionEvent.
493     *
494     * @see #getEdgeFlags()
495     */
496    public final void setEdgeFlags(int flags) {
497        mEdgeFlags = flags;
498    }
499
500    /**
501     * Sets this event's action.
502     */
503    public final void setAction(int action) {
504        mAction = action;
505    }
506
507    /**
508     * Adjust this event's location.
509     * @param deltaX Amount to add to the current X coordinate of the event.
510     * @param deltaY Amount to add to the current Y coordinate of the event.
511     */
512    public final void offsetLocation(float deltaX, float deltaY) {
513        mX += deltaX;
514        mY += deltaY;
515        final int N = mNumHistory*4;
516        if (N <= 0) {
517            return;
518        }
519        final float[] pos = mHistory;
520        for (int i=0; i<N; i+=4) {
521            pos[i] += deltaX;
522            pos[i+1] += deltaY;
523        }
524    }
525
526    /**
527     * Set this event's location.  Applies {@link #offsetLocation} with a
528     * delta from the current location to the given new location.
529     *
530     * @param x New absolute X location.
531     * @param y New absolute Y location.
532     */
533    public final void setLocation(float x, float y) {
534        float deltaX = x-mX;
535        float deltaY = y-mY;
536        if (deltaX != 0 || deltaY != 0) {
537            offsetLocation(deltaX, deltaY);
538        }
539    }
540
541    /**
542     * Add a new movement to the batch of movements in this event.  The event's
543     * current location, position and size is updated to the new values.  In
544     * the future, the current values in the event will be added to a list of
545     * historic values.
546     *
547     * @param x The new X position.
548     * @param y The new Y position.
549     * @param pressure The new pressure.
550     * @param size The new size.
551     */
552    public final void addBatch(long eventTime, float x, float y,
553            float pressure, float size, int metaState) {
554        float[] history = mHistory;
555        long[] historyTimes = mHistoryTimes;
556        int N;
557        int avail;
558        if (history == null) {
559            mHistory = history = new float[8*4];
560            mHistoryTimes = historyTimes = new long[8];
561            mNumHistory = N = 0;
562            avail = 8;
563        } else {
564            N = mNumHistory;
565            avail = history.length/4;
566            if (N == avail) {
567                avail += 8;
568                float[] newHistory = new float[avail*4];
569                System.arraycopy(history, 0, newHistory, 0, N*4);
570                mHistory = history = newHistory;
571                long[] newHistoryTimes = new long[avail];
572                System.arraycopy(historyTimes, 0, newHistoryTimes, 0, N);
573                mHistoryTimes = historyTimes = newHistoryTimes;
574            }
575        }
576
577        historyTimes[N] = mEventTime;
578
579        final int pos = N*4;
580        history[pos] = mX;
581        history[pos+1] = mY;
582        history[pos+2] = mPressure;
583        history[pos+3] = mSize;
584        mNumHistory = N+1;
585
586        mEventTime = eventTime;
587        mX = mRawX = x;
588        mY = mRawY = y;
589        mPressure = pressure;
590        mSize = size;
591        mMetaState |= metaState;
592    }
593
594    @Override
595    public String toString() {
596        return "MotionEvent{" + Integer.toHexString(System.identityHashCode(this))
597            + " action=" + mAction + " x=" + mX
598            + " y=" + mY + " pressure=" + mPressure + " size=" + mSize + "}";
599    }
600
601    public static final Parcelable.Creator<MotionEvent> CREATOR
602            = new Parcelable.Creator<MotionEvent>() {
603        public MotionEvent createFromParcel(Parcel in) {
604            MotionEvent ev = obtain();
605            ev.readFromParcel(in);
606            return ev;
607        }
608
609        public MotionEvent[] newArray(int size) {
610            return new MotionEvent[size];
611        }
612    };
613
614    public int describeContents() {
615        return 0;
616    }
617
618    public void writeToParcel(Parcel out, int flags) {
619        out.writeLong(mDownTime);
620        out.writeLong(mEventTime);
621        out.writeInt(mAction);
622        out.writeFloat(mX);
623        out.writeFloat(mY);
624        out.writeFloat(mPressure);
625        out.writeFloat(mSize);
626        out.writeInt(mMetaState);
627        out.writeFloat(mRawX);
628        out.writeFloat(mRawY);
629        final int N = mNumHistory;
630        out.writeInt(N);
631        if (N > 0) {
632            final int N4 = N*4;
633            int i;
634            float[] history = mHistory;
635            for (i=0; i<N4; i++) {
636                out.writeFloat(history[i]);
637            }
638            long[] times = mHistoryTimes;
639            for (i=0; i<N; i++) {
640                out.writeLong(times[i]);
641            }
642        }
643        out.writeFloat(mXPrecision);
644        out.writeFloat(mYPrecision);
645        out.writeInt(mDeviceId);
646        out.writeInt(mEdgeFlags);
647    }
648
649    private void readFromParcel(Parcel in) {
650        mDownTime = in.readLong();
651        mEventTime = in.readLong();
652        mAction = in.readInt();
653        mX = in.readFloat();
654        mY = in.readFloat();
655        mPressure = in.readFloat();
656        mSize = in.readFloat();
657        mMetaState = in.readInt();
658        mRawX = in.readFloat();
659        mRawY = in.readFloat();
660        final int N = in.readInt();
661        if ((mNumHistory=N) > 0) {
662            final int N4 = N*4;
663            float[] history = mHistory;
664            if (history == null || history.length < N4) {
665                mHistory = history = new float[N4 + (4*4)];
666            }
667            for (int i=0; i<N4; i++) {
668                history[i] = in.readFloat();
669            }
670            long[] times = mHistoryTimes;
671            if (times == null || times.length < N) {
672                mHistoryTimes = times = new long[N + 4];
673            }
674            for (int i=0; i<N; i++) {
675                times[i] = in.readLong();
676            }
677        }
678        mXPrecision = in.readFloat();
679        mYPrecision = in.readFloat();
680        mDeviceId = in.readInt();
681        mEdgeFlags = in.readInt();
682    }
683
684}
685
686