MotionEvent.java revision cafdea61a85c8f5d0646cc9413a09346c637f43f
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     * Scales down the cood of this event by the given scale.
216     *
217     * @hide
218     */
219    public void scale(float scale) {
220        if (scale != 1.0f) {
221            mX *= scale;
222            mY *= scale;
223            mRawX *= scale;
224            mRawY *= scale;
225            mSize *= scale;
226            mXPrecision *= scale;
227            mYPrecision *= scale;
228            if (mHistory != null) {
229                float[] history = mHistory;
230                int length = history.length;
231                for (int i = 0; i < length; i += 4) {
232                    history[i] *= scale;        // X
233                                                // history[i + 2] == pressure
234                    history[i + 1] *= scale;    // Y
235                    history[i + 3] *= scale;    // Size, TODO: square this?
236                }
237            }
238        }
239    }
240
241    /**
242     * Create a new MotionEvent, copying from an existing one.
243     */
244    static public MotionEvent obtain(MotionEvent o) {
245        MotionEvent ev = obtain();
246        ev.mDeviceId = o.mDeviceId;
247        ev.mEdgeFlags = o.mEdgeFlags;
248        ev.mDownTime = o.mDownTime;
249        ev.mEventTime = o.mEventTime;
250        ev.mAction = o.mAction;
251        ev.mX = o.mX;
252        ev.mRawX = o.mRawX;
253        ev.mY = o.mY;
254        ev.mRawY = o.mRawY;
255        ev.mPressure = o.mPressure;
256        ev.mSize = o.mSize;
257        ev.mMetaState = o.mMetaState;
258        ev.mXPrecision = o.mXPrecision;
259        ev.mYPrecision = o.mYPrecision;
260        final int N = o.mNumHistory;
261        ev.mNumHistory = N;
262        if (N > 0) {
263            // could be more efficient about this...
264            ev.mHistory = (float[])o.mHistory.clone();
265            ev.mHistoryTimes = (long[])o.mHistoryTimes.clone();
266        }
267        return ev;
268    }
269
270    /**
271     * Recycle the MotionEvent, to be re-used by a later caller.  After calling
272     * this function you must not ever touch the event again.
273     */
274    public void recycle() {
275        // Ensure recycle is only called once!
276        if (TRACK_RECYCLED_LOCATION) {
277            if (mRecycledLocation != null) {
278                throw new RuntimeException(toString() + " recycled twice!", mRecycledLocation);
279            }
280            mRecycledLocation = new RuntimeException("Last recycled here");
281        } else if (mRecycled) {
282            throw new RuntimeException(toString() + " recycled twice!");
283        }
284
285        //Log.w("MotionEvent", "Recycling event " + this, mRecycledLocation);
286        synchronized (gRecyclerLock) {
287            if (gRecyclerUsed < MAX_RECYCLED) {
288                gRecyclerUsed++;
289                mNumHistory = 0;
290                mNext = gRecyclerTop;
291                gRecyclerTop = this;
292            }
293        }
294    }
295
296    /**
297     * Return the kind of action being performed -- one of either
298     * {@link #ACTION_DOWN}, {@link #ACTION_MOVE}, {@link #ACTION_UP}, or
299     * {@link #ACTION_CANCEL}.
300     */
301    public final int getAction() {
302        return mAction;
303    }
304
305    /**
306     * Returns the time (in ms) when the user originally pressed down to start
307     * a stream of position events.
308     */
309    public final long getDownTime() {
310        return mDownTime;
311    }
312
313    /**
314     * Returns the time (in ms) when this specific event was generated.
315     */
316    public final long getEventTime() {
317        return mEventTime;
318    }
319
320    /**
321     * Returns the X coordinate of this event.  Whole numbers are pixels; the
322     * value may have a fraction for input devices that are sub-pixel precise.
323     */
324    public final float getX() {
325        return mX;
326    }
327
328    /**
329     * Returns the Y coordinate of this event.  Whole numbers are pixels; the
330     * value may have a fraction for input devices that are sub-pixel precise.
331     */
332    public final float getY() {
333        return mY;
334    }
335
336    /**
337     * Returns the current pressure of this event.  The pressure generally
338     * ranges from 0 (no pressure at all) to 1 (normal pressure), however
339     * values higher than 1 may be generated depending on the calibration of
340     * the input device.
341     */
342    public final float getPressure() {
343        return mPressure;
344    }
345
346    /**
347     * Returns a scaled value of the approximate size, of the area being pressed when
348     * touched with the finger. The actual value in pixels corresponding to the finger
349     * touch  is normalized with the device specific range of values
350     * and scaled to a value between 0 and 1. The value of size can be used to
351     * determine fat touch events.
352     */
353    public final float getSize() {
354        return mSize;
355    }
356
357    /**
358     * Returns the state of any meta / modifier keys that were in effect when
359     * the event was generated.  This is the same values as those
360     * returned by {@link KeyEvent#getMetaState() KeyEvent.getMetaState}.
361     *
362     * @return an integer in which each bit set to 1 represents a pressed
363     *         meta key
364     *
365     * @see KeyEvent#getMetaState()
366     */
367    public final int getMetaState() {
368        return mMetaState;
369    }
370
371    /**
372     * Returns the original raw X coordinate of this event.  For touch
373     * events on the screen, this is the original location of the event
374     * on the screen, before it had been adjusted for the containing window
375     * and views.
376     */
377    public final float getRawX() {
378        return mRawX;
379    }
380
381    /**
382     * Returns the original raw Y coordinate of this event.  For touch
383     * events on the screen, this is the original location of the event
384     * on the screen, before it had been adjusted for the containing window
385     * and views.
386     */
387    public final float getRawY() {
388        return mRawY;
389    }
390
391    /**
392     * Return the precision of the X coordinates being reported.  You can
393     * multiple this number with {@link #getX} to find the actual hardware
394     * value of the X coordinate.
395     * @return Returns the precision of X coordinates being reported.
396     */
397    public final float getXPrecision() {
398        return mXPrecision;
399    }
400
401    /**
402     * Return the precision of the Y coordinates being reported.  You can
403     * multiple this number with {@link #getY} to find the actual hardware
404     * value of the Y coordinate.
405     * @return Returns the precision of Y coordinates being reported.
406     */
407    public final float getYPrecision() {
408        return mYPrecision;
409    }
410
411    /**
412     * Returns the number of historical points in this event.  These are
413     * movements that have occurred between this event and the previous event.
414     * This only applies to ACTION_MOVE events -- all other actions will have
415     * a size of 0.
416     *
417     * @return Returns the number of historical points in the event.
418     */
419    public final int getHistorySize() {
420        return mNumHistory;
421    }
422
423    /**
424     * Returns the time that a historical movement occurred between this event
425     * and the previous event.  Only applies to ACTION_MOVE events.
426     *
427     * @param pos Which historical value to return; must be less than
428     * {@link #getHistorySize}
429     *
430     * @see #getHistorySize
431     * @see #getEventTime
432     */
433    public final long getHistoricalEventTime(int pos) {
434        return mHistoryTimes[pos];
435    }
436
437    /**
438     * Returns a historical X coordinate that occurred between this event
439     * and the previous event.  Only applies to ACTION_MOVE events.
440     *
441     * @param pos Which historical value to return; must be less than
442     * {@link #getHistorySize}
443     *
444     * @see #getHistorySize
445     * @see #getX
446     */
447    public final float getHistoricalX(int pos) {
448        return mHistory[pos*4];
449    }
450
451    /**
452     * Returns a historical Y coordinate that occurred between this event
453     * and the previous event.  Only applies to ACTION_MOVE events.
454     *
455     * @param pos Which historical value to return; must be less than
456     * {@link #getHistorySize}
457     *
458     * @see #getHistorySize
459     * @see #getY
460     */
461    public final float getHistoricalY(int pos) {
462        return mHistory[pos*4 + 1];
463    }
464
465    /**
466     * Returns a historical pressure coordinate that occurred between this event
467     * and the previous event.  Only applies to ACTION_MOVE events.
468     *
469     * @param pos Which historical value to return; must be less than
470     * {@link #getHistorySize}
471     *
472     * @see #getHistorySize
473     * @see #getPressure
474     */
475    public final float getHistoricalPressure(int pos) {
476        return mHistory[pos*4 + 2];
477    }
478
479    /**
480     * Returns a historical size coordinate that occurred between this event
481     * and the previous event.  Only applies to ACTION_MOVE events.
482     *
483     * @param pos Which historical value to return; must be less than
484     * {@link #getHistorySize}
485     *
486     * @see #getHistorySize
487     * @see #getSize
488     */
489    public final float getHistoricalSize(int pos) {
490        return mHistory[pos*4 + 3];
491    }
492
493    /**
494     * Return the id for the device that this event came from.  An id of
495     * zero indicates that the event didn't come from a physical device; other
496     * numbers are arbitrary and you shouldn't depend on the values.
497     */
498    public final int getDeviceId() {
499        return mDeviceId;
500    }
501
502    /**
503     * Returns a bitfield indicating which edges, if any, where touched by this
504     * MotionEvent. For touch events, clients can use this to determine if the
505     * user's finger was touching the edge of the display.
506     *
507     * @see #EDGE_LEFT
508     * @see #EDGE_TOP
509     * @see #EDGE_RIGHT
510     * @see #EDGE_BOTTOM
511     */
512    public final int getEdgeFlags() {
513        return mEdgeFlags;
514    }
515
516
517    /**
518     * Sets the bitfield indicating which edges, if any, where touched by this
519     * MotionEvent.
520     *
521     * @see #getEdgeFlags()
522     */
523    public final void setEdgeFlags(int flags) {
524        mEdgeFlags = flags;
525    }
526
527    /**
528     * Sets this event's action.
529     */
530    public final void setAction(int action) {
531        mAction = action;
532    }
533
534    /**
535     * Adjust this event's location.
536     * @param deltaX Amount to add to the current X coordinate of the event.
537     * @param deltaY Amount to add to the current Y coordinate of the event.
538     */
539    public final void offsetLocation(float deltaX, float deltaY) {
540        mX += deltaX;
541        mY += deltaY;
542        final int N = mNumHistory*4;
543        if (N <= 0) {
544            return;
545        }
546        final float[] pos = mHistory;
547        for (int i=0; i<N; i+=4) {
548            pos[i] += deltaX;
549            pos[i+1] += deltaY;
550        }
551    }
552
553    /**
554     * Set this event's location.  Applies {@link #offsetLocation} with a
555     * delta from the current location to the given new location.
556     *
557     * @param x New absolute X location.
558     * @param y New absolute Y location.
559     */
560    public final void setLocation(float x, float y) {
561        float deltaX = x-mX;
562        float deltaY = y-mY;
563        if (deltaX != 0 || deltaY != 0) {
564            offsetLocation(deltaX, deltaY);
565        }
566    }
567
568    /**
569     * Add a new movement to the batch of movements in this event.  The event's
570     * current location, position and size is updated to the new values.  In
571     * the future, the current values in the event will be added to a list of
572     * historic values.
573     *
574     * @param x The new X position.
575     * @param y The new Y position.
576     * @param pressure The new pressure.
577     * @param size The new size.
578     */
579    public final void addBatch(long eventTime, float x, float y,
580            float pressure, float size, int metaState) {
581        float[] history = mHistory;
582        long[] historyTimes = mHistoryTimes;
583        int N;
584        int avail;
585        if (history == null) {
586            mHistory = history = new float[8*4];
587            mHistoryTimes = historyTimes = new long[8];
588            mNumHistory = N = 0;
589            avail = 8;
590        } else {
591            N = mNumHistory;
592            avail = history.length/4;
593            if (N == avail) {
594                avail += 8;
595                float[] newHistory = new float[avail*4];
596                System.arraycopy(history, 0, newHistory, 0, N*4);
597                mHistory = history = newHistory;
598                long[] newHistoryTimes = new long[avail];
599                System.arraycopy(historyTimes, 0, newHistoryTimes, 0, N);
600                mHistoryTimes = historyTimes = newHistoryTimes;
601            }
602        }
603
604        historyTimes[N] = mEventTime;
605
606        final int pos = N*4;
607        history[pos] = mX;
608        history[pos+1] = mY;
609        history[pos+2] = mPressure;
610        history[pos+3] = mSize;
611        mNumHistory = N+1;
612
613        mEventTime = eventTime;
614        mX = mRawX = x;
615        mY = mRawY = y;
616        mPressure = pressure;
617        mSize = size;
618        mMetaState |= metaState;
619    }
620
621    @Override
622    public String toString() {
623        return "MotionEvent{" + Integer.toHexString(System.identityHashCode(this))
624            + " action=" + mAction + " x=" + mX
625            + " y=" + mY + " pressure=" + mPressure + " size=" + mSize + "}";
626    }
627
628    public static final Parcelable.Creator<MotionEvent> CREATOR
629            = new Parcelable.Creator<MotionEvent>() {
630        public MotionEvent createFromParcel(Parcel in) {
631            MotionEvent ev = obtain();
632            ev.readFromParcel(in);
633            return ev;
634        }
635
636        public MotionEvent[] newArray(int size) {
637            return new MotionEvent[size];
638        }
639    };
640
641    public int describeContents() {
642        return 0;
643    }
644
645    public void writeToParcel(Parcel out, int flags) {
646        out.writeLong(mDownTime);
647        out.writeLong(mEventTime);
648        out.writeInt(mAction);
649        out.writeFloat(mX);
650        out.writeFloat(mY);
651        out.writeFloat(mPressure);
652        out.writeFloat(mSize);
653        out.writeInt(mMetaState);
654        out.writeFloat(mRawX);
655        out.writeFloat(mRawY);
656        final int N = mNumHistory;
657        out.writeInt(N);
658        if (N > 0) {
659            final int N4 = N*4;
660            int i;
661            float[] history = mHistory;
662            for (i=0; i<N4; i++) {
663                out.writeFloat(history[i]);
664            }
665            long[] times = mHistoryTimes;
666            for (i=0; i<N; i++) {
667                out.writeLong(times[i]);
668            }
669        }
670        out.writeFloat(mXPrecision);
671        out.writeFloat(mYPrecision);
672        out.writeInt(mDeviceId);
673        out.writeInt(mEdgeFlags);
674    }
675
676    private void readFromParcel(Parcel in) {
677        mDownTime = in.readLong();
678        mEventTime = in.readLong();
679        mAction = in.readInt();
680        mX = in.readFloat();
681        mY = in.readFloat();
682        mPressure = in.readFloat();
683        mSize = in.readFloat();
684        mMetaState = in.readInt();
685        mRawX = in.readFloat();
686        mRawY = in.readFloat();
687        final int N = in.readInt();
688        if ((mNumHistory=N) > 0) {
689            final int N4 = N*4;
690            float[] history = mHistory;
691            if (history == null || history.length < N4) {
692                mHistory = history = new float[N4 + (4*4)];
693            }
694            for (int i=0; i<N4; i++) {
695                history[i] = in.readFloat();
696            }
697            long[] times = mHistoryTimes;
698            if (times == null || times.length < N) {
699                mHistoryTimes = times = new long[N + 4];
700            }
701            for (int i=0; i<N; i++) {
702                times[i] = in.readLong();
703            }
704        }
705        mXPrecision = in.readFloat();
706        mYPrecision = in.readFloat();
707        mDeviceId = in.readInt();
708        mEdgeFlags = in.readInt();
709    }
710
711}
712