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