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