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