summaryrefslogtreecommitdiffstats
path: root/core/java/android/view/MotionEvent.java
diff options
context:
space:
mode:
Diffstat (limited to 'core/java/android/view/MotionEvent.java')
-rw-r--r--core/java/android/view/MotionEvent.java864
1 files changed, 691 insertions, 173 deletions
diff --git a/core/java/android/view/MotionEvent.java b/core/java/android/view/MotionEvent.java
index a224ed3..ca907af 100644
--- a/core/java/android/view/MotionEvent.java
+++ b/core/java/android/view/MotionEvent.java
@@ -19,7 +19,7 @@ package android.view;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.SystemClock;
-import android.util.Config;
+import android.util.Log;
/**
* Object used to report movement (mouse, pen, finger, trackball) events. This
@@ -27,17 +27,26 @@ import android.util.Config;
* it is being used for.
*/
public final class MotionEvent implements Parcelable {
+ static final boolean DEBUG_POINTERS = false;
+
+ /**
+ * Bit mask of the parts of the action code that are the action itself.
+ */
+ public static final int ACTION_MASK = 0xff;
+
/**
* Constant for {@link #getAction}: A pressed gesture has started, the
* motion contains the initial starting location.
*/
public static final int ACTION_DOWN = 0;
+
/**
* Constant for {@link #getAction}: A pressed gesture has finished, the
* motion contains the final release location as well as any intermediate
* points since the last down or move event.
*/
public static final int ACTION_UP = 1;
+
/**
* Constant for {@link #getAction}: A change has happened during a
* press gesture (between {@link #ACTION_DOWN} and {@link #ACTION_UP}).
@@ -45,12 +54,14 @@ public final class MotionEvent implements Parcelable {
* points since the last down or move event.
*/
public static final int ACTION_MOVE = 2;
+
/**
* Constant for {@link #getAction}: The current gesture has been aborted.
* You will not receive any more points in it. You should treat this as
* an up event, but not perform any action that you normally would.
*/
public static final int ACTION_CANCEL = 3;
+
/**
* Constant for {@link #getAction}: A movement has happened outside of the
* normal bounds of the UI element. This does not provide a full gesture,
@@ -58,6 +69,70 @@ public final class MotionEvent implements Parcelable {
*/
public static final int ACTION_OUTSIDE = 4;
+ /**
+ * A non-primary pointer has gone down. The bits in
+ * {@link #ACTION_POINTER_ID_MASK} indicate which pointer changed.
+ */
+ public static final int ACTION_POINTER_DOWN = 5;
+
+ /**
+ * Synonym for {@link #ACTION_POINTER_DOWN} with
+ * {@link #ACTION_POINTER_ID_MASK} of 0: the primary pointer has gone done.
+ */
+ public static final int ACTION_POINTER_1_DOWN = ACTION_POINTER_DOWN | 0x0000;
+
+ /**
+ * Synonym for {@link #ACTION_POINTER_DOWN} with
+ * {@link #ACTION_POINTER_ID_MASK} of 1: the secondary pointer has gone done.
+ */
+ public static final int ACTION_POINTER_2_DOWN = ACTION_POINTER_DOWN | 0x0100;
+
+ /**
+ * Synonym for {@link #ACTION_POINTER_DOWN} with
+ * {@link #ACTION_POINTER_ID_MASK} of 2: the tertiary pointer has gone done.
+ */
+ public static final int ACTION_POINTER_3_DOWN = ACTION_POINTER_DOWN | 0x0200;
+
+ /**
+ * A non-primary pointer has gone up. The bits in
+ * {@link #ACTION_POINTER_ID_MASK} indicate which pointer changed.
+ */
+ public static final int ACTION_POINTER_UP = 6;
+
+ /**
+ * Synonym for {@link #ACTION_POINTER_UP} with
+ * {@link #ACTION_POINTER_ID_MASK} of 0: the primary pointer has gone up.
+ */
+ public static final int ACTION_POINTER_1_UP = ACTION_POINTER_UP | 0x0000;
+
+ /**
+ * Synonym for {@link #ACTION_POINTER_UP} with
+ * {@link #ACTION_POINTER_ID_MASK} of 1: the secondary pointer has gone up.
+ */
+ public static final int ACTION_POINTER_2_UP = ACTION_POINTER_UP | 0x0100;
+
+ /**
+ * Synonym for {@link #ACTION_POINTER_UP} with
+ * {@link #ACTION_POINTER_ID_MASK} of 2: the tertiary pointer has gone up.
+ */
+ public static final int ACTION_POINTER_3_UP = ACTION_POINTER_UP | 0x0200;
+
+ /**
+ * Bits in the action code that represent a pointer ID, used with
+ * {@link #ACTION_POINTER_DOWN} and {@link #ACTION_POINTER_UP}. Pointer IDs
+ * start at 0, with 0 being the primary (first) pointer in the motion. Note
+ * that this not <em>not</em> an index into the array of pointer values,
+ * which is compacted to only contain pointers that are down; the pointer
+ * ID for a particular index can be found with {@link #findPointerIndex}.
+ */
+ public static final int ACTION_POINTER_ID_MASK = 0xff00;
+
+ /**
+ * Bit shift for the action bits holding the pointer identifier as
+ * defined by {@link #ACTION_POINTER_ID_MASK}.
+ */
+ public static final int ACTION_POINTER_ID_SHIFT = 8;
+
private static final boolean TRACK_RECYCLED_LOCATION = false;
/**
@@ -80,34 +155,83 @@ public final class MotionEvent implements Parcelable {
*/
public static final int EDGE_RIGHT = 0x00000008;
+ /**
+ * Offset for the sample's X coordinate.
+ * @hide
+ */
+ static public final int SAMPLE_X = 0;
+
+ /**
+ * Offset for the sample's Y coordinate.
+ * @hide
+ */
+ static public final int SAMPLE_Y = 1;
+
+ /**
+ * Offset for the sample's X coordinate.
+ * @hide
+ */
+ static public final int SAMPLE_PRESSURE = 2;
+
+ /**
+ * Offset for the sample's X coordinate.
+ * @hide
+ */
+ static public final int SAMPLE_SIZE = 3;
+
+ /**
+ * Number of data items for each sample.
+ * @hide
+ */
+ static public final int NUM_SAMPLE_DATA = 4;
+
+ /**
+ * Number of possible pointers.
+ * @hide
+ */
+ static public final int BASE_AVAIL_POINTERS = 5;
+
+ static private final int BASE_AVAIL_SAMPLES = 8;
+
static private final int MAX_RECYCLED = 10;
static private Object gRecyclerLock = new Object();
static private int gRecyclerUsed = 0;
static private MotionEvent gRecyclerTop = null;
private long mDownTime;
- private long mEventTime;
+ private long mEventTimeNano;
private int mAction;
- private float mX;
- private float mY;
private float mRawX;
private float mRawY;
- private float mPressure;
- private float mSize;
- private int mMetaState;
- private int mNumHistory;
- private float[] mHistory;
- private long[] mHistoryTimes;
private float mXPrecision;
private float mYPrecision;
private int mDeviceId;
private int mEdgeFlags;
+ private int mMetaState;
+
+ // Here is the actual event data. Note that the order of the array
+ // is a little odd: the first entry is the most recent, and the ones
+ // following it are the historical data from oldest to newest. This
+ // allows us to easily retrieve the most recent data, without having
+ // to copy the arrays every time a new sample is added.
+
+ private int mNumPointers;
+ private int mNumSamples;
+ // Array of mNumPointers size of identifiers for each pointer of data.
+ private int[] mPointerIdentifiers;
+ // Array of (mNumSamples * mNumPointers * NUM_SAMPLE_DATA) size of event data.
+ private float[] mDataSamples;
+ // Array of mNumSamples size of time stamps.
+ private long[] mTimeSamples;
private MotionEvent mNext;
private RuntimeException mRecycledLocation;
private boolean mRecycled;
private MotionEvent() {
+ mPointerIdentifiers = new int[BASE_AVAIL_POINTERS];
+ mDataSamples = new float[BASE_AVAIL_POINTERS*BASE_AVAIL_SAMPLES*NUM_SAMPLE_DATA];
+ mTimeSamples = new long[BASE_AVAIL_SAMPLES];
}
static private MotionEvent obtain() {
@@ -127,6 +251,86 @@ public final class MotionEvent implements Parcelable {
/**
* Create a new MotionEvent, filling in all of the basic values that
* define the motion.
+ *
+ * @param downTime The time (in ms) when the user originally pressed down to start
+ * a stream of position events. This must be obtained from {@link SystemClock#uptimeMillis()}.
+ * @param eventTime The the time (in ms) when this specific event was generated. This
+ * must be obtained from {@link SystemClock#uptimeMillis()}.
+ * @param eventTimeNano The the time (in ns) when this specific event was generated. This
+ * must be obtained from {@link System#nanoTime()}.
+ * @param action The kind of action being performed -- one of either
+ * {@link #ACTION_DOWN}, {@link #ACTION_MOVE}, {@link #ACTION_UP}, or
+ * {@link #ACTION_CANCEL}.
+ * @param pointers The number of points that will be in this event.
+ * @param inPointerIds An array of <em>pointers</em> values providing
+ * an identifier for each pointer.
+ * @param inData An array of <em>pointers*NUM_SAMPLE_DATA</em> of initial
+ * data samples for the event.
+ * @param metaState The state of any meta / modifier keys that were in effect when
+ * the event was generated.
+ * @param xPrecision The precision of the X coordinate being reported.
+ * @param yPrecision The precision of the Y coordinate being reported.
+ * @param deviceId The id for the device that this event came from. An id of
+ * zero indicates that the event didn't come from a physical device; other
+ * numbers are arbitrary and you shouldn't depend on the values.
+ * @param edgeFlags A bitfield indicating which edges, if any, where touched by this
+ * MotionEvent.
+ *
+ * @hide
+ */
+ static public MotionEvent obtainNano(long downTime, long eventTime, long eventTimeNano,
+ int action, int pointers, int[] inPointerIds, float[] inData, int metaState,
+ float xPrecision, float yPrecision, int deviceId, int edgeFlags) {
+ MotionEvent ev = obtain();
+ ev.mDeviceId = deviceId;
+ ev.mEdgeFlags = edgeFlags;
+ ev.mDownTime = downTime;
+ ev.mEventTimeNano = eventTimeNano;
+ ev.mAction = action;
+ ev.mMetaState = metaState;
+ ev.mRawX = inData[SAMPLE_X];
+ ev.mRawY = inData[SAMPLE_Y];
+ ev.mXPrecision = xPrecision;
+ ev.mYPrecision = yPrecision;
+ ev.mNumPointers = pointers;
+ ev.mNumSamples = 1;
+
+ int[] pointerIdentifiers = ev.mPointerIdentifiers;
+ if (pointerIdentifiers.length < pointers) {
+ ev.mPointerIdentifiers = pointerIdentifiers = new int[pointers];
+ }
+ System.arraycopy(inPointerIds, 0, pointerIdentifiers, 0, pointers);
+
+ final int ND = pointers * NUM_SAMPLE_DATA;
+ float[] dataSamples = ev.mDataSamples;
+ if (dataSamples.length < ND) {
+ ev.mDataSamples = dataSamples = new float[ND];
+ }
+ System.arraycopy(inData, 0, dataSamples, 0, ND);
+
+ ev.mTimeSamples[0] = eventTime;
+
+ if (DEBUG_POINTERS) {
+ StringBuilder sb = new StringBuilder(128);
+ sb.append("New:");
+ for (int i=0; i<pointers; i++) {
+ sb.append(" #");
+ sb.append(ev.mPointerIdentifiers[i]);
+ sb.append("(");
+ sb.append(ev.mDataSamples[(i*NUM_SAMPLE_DATA) + SAMPLE_X]);
+ sb.append(",");
+ sb.append(ev.mDataSamples[(i*NUM_SAMPLE_DATA) + SAMPLE_Y]);
+ sb.append(")");
+ }
+ Log.v("MotionEvent", sb.toString());
+ }
+
+ return ev;
+ }
+
+ /**
+ * Create a new MotionEvent, filling in all of the basic values that
+ * define the motion.
*
* @param downTime The time (in ms) when the user originally pressed down to start
* a stream of position events. This must be obtained from {@link SystemClock#uptimeMillis()}.
@@ -162,16 +366,83 @@ public final class MotionEvent implements Parcelable {
ev.mDeviceId = deviceId;
ev.mEdgeFlags = edgeFlags;
ev.mDownTime = downTime;
- ev.mEventTime = eventTime;
+ ev.mEventTimeNano = eventTime * 1000000;
ev.mAction = action;
- ev.mX = ev.mRawX = x;
- ev.mY = ev.mRawY = y;
- ev.mPressure = pressure;
- ev.mSize = size;
ev.mMetaState = metaState;
ev.mXPrecision = xPrecision;
ev.mYPrecision = yPrecision;
+ ev.mNumPointers = 1;
+ ev.mNumSamples = 1;
+ int[] pointerIds = ev.mPointerIdentifiers;
+ pointerIds[0] = 0;
+ float[] data = ev.mDataSamples;
+ data[SAMPLE_X] = ev.mRawX = x;
+ data[SAMPLE_Y] = ev.mRawY = y;
+ data[SAMPLE_PRESSURE] = pressure;
+ data[SAMPLE_SIZE] = size;
+ ev.mTimeSamples[0] = eventTime;
+
+ return ev;
+ }
+
+ /**
+ * Create a new MotionEvent, filling in all of the basic values that
+ * define the motion.
+ *
+ * @param downTime The time (in ms) when the user originally pressed down to start
+ * a stream of position events. This must be obtained from {@link SystemClock#uptimeMillis()}.
+ * @param eventTime The the time (in ms) when this specific event was generated. This
+ * must be obtained from {@link SystemClock#uptimeMillis()}.
+ * @param action The kind of action being performed -- one of either
+ * {@link #ACTION_DOWN}, {@link #ACTION_MOVE}, {@link #ACTION_UP}, or
+ * {@link #ACTION_CANCEL}.
+ * @param pointers The number of pointers that are active in this event.
+ * @param x The X coordinate of this event.
+ * @param y The Y coordinate of this event.
+ * @param pressure The current pressure of this event. The pressure generally
+ * ranges from 0 (no pressure at all) to 1 (normal pressure), however
+ * values higher than 1 may be generated depending on the calibration of
+ * the input device.
+ * @param size A scaled value of the approximate size of the area being pressed when
+ * touched with the finger. The actual value in pixels corresponding to the finger
+ * touch is normalized with a device specific range of values
+ * and scaled to a value between 0 and 1.
+ * @param metaState The state of any meta / modifier keys that were in effect when
+ * the event was generated.
+ * @param xPrecision The precision of the X coordinate being reported.
+ * @param yPrecision The precision of the Y coordinate being reported.
+ * @param deviceId The id for the device that this event came from. An id of
+ * zero indicates that the event didn't come from a physical device; other
+ * numbers are arbitrary and you shouldn't depend on the values.
+ * @param edgeFlags A bitfield indicating which edges, if any, where touched by this
+ * MotionEvent.
+ */
+ static public MotionEvent obtain(long downTime, long eventTime, int action,
+ int pointers, float x, float y, float pressure, float size, int metaState,
+ float xPrecision, float yPrecision, int deviceId, int edgeFlags) {
+ MotionEvent ev = obtain();
+ ev.mDeviceId = deviceId;
+ ev.mEdgeFlags = edgeFlags;
+ ev.mDownTime = downTime;
+ ev.mEventTimeNano = eventTime * 1000000;
+ ev.mAction = action;
+ ev.mNumPointers = pointers;
+ ev.mMetaState = metaState;
+ ev.mXPrecision = xPrecision;
+ ev.mYPrecision = yPrecision;
+
+ ev.mNumPointers = 1;
+ ev.mNumSamples = 1;
+ int[] pointerIds = ev.mPointerIdentifiers;
+ pointerIds[0] = 0;
+ float[] data = ev.mDataSamples;
+ data[SAMPLE_X] = ev.mRawX = x;
+ data[SAMPLE_Y] = ev.mRawY = y;
+ data[SAMPLE_PRESSURE] = pressure;
+ data[SAMPLE_SIZE] = size;
+ ev.mTimeSamples[0] = eventTime;
+
return ev;
}
@@ -198,16 +469,24 @@ public final class MotionEvent implements Parcelable {
ev.mDeviceId = 0;
ev.mEdgeFlags = 0;
ev.mDownTime = downTime;
- ev.mEventTime = eventTime;
+ ev.mEventTimeNano = eventTime * 1000000;
ev.mAction = action;
- ev.mX = ev.mRawX = x;
- ev.mY = ev.mRawY = y;
- ev.mPressure = 1.0f;
- ev.mSize = 1.0f;
+ ev.mNumPointers = 1;
ev.mMetaState = metaState;
ev.mXPrecision = 1.0f;
ev.mYPrecision = 1.0f;
+ ev.mNumPointers = 1;
+ ev.mNumSamples = 1;
+ int[] pointerIds = ev.mPointerIdentifiers;
+ pointerIds[0] = 0;
+ float[] data = ev.mDataSamples;
+ data[SAMPLE_X] = ev.mRawX = x;
+ data[SAMPLE_Y] = ev.mRawY = y;
+ data[SAMPLE_PRESSURE] = 1.0f;
+ data[SAMPLE_SIZE] = 1.0f;
+ ev.mTimeSamples[0] = eventTime;
+
return ev;
}
@@ -217,72 +496,96 @@ public final class MotionEvent implements Parcelable {
* @hide
*/
public void scale(float scale) {
- mX *= scale;
- mY *= scale;
mRawX *= scale;
mRawY *= scale;
- mSize *= scale;
mXPrecision *= scale;
mYPrecision *= scale;
- if (mHistory != null) {
- float[] history = mHistory;
- int length = history.length;
- for (int i = 0; i < length; i += 4) {
- history[i] *= scale; // X
- history[i + 1] *= scale; // Y
- // no need to scale pressure ([i+2])
- history[i + 3] *= scale; // Size, TODO: square this?
- }
+ float[] history = mDataSamples;
+ final int length = mNumPointers * mNumSamples * NUM_SAMPLE_DATA;
+ for (int i = 0; i < length; i += NUM_SAMPLE_DATA) {
+ history[i + SAMPLE_X] *= scale;
+ history[i + SAMPLE_Y] *= scale;
+ // no need to scale pressure
+ history[i + SAMPLE_SIZE] *= scale; // TODO: square this?
}
}
/**
- * Translate the coordination of the event by given x and y.
- *
- * @hide
+ * Create a new MotionEvent, copying from an existing one.
*/
- public void translate(float dx, float dy) {
- mX += dx;
- mY += dy;
- mRawX += dx;
- mRawY += dx;
- if (mHistory != null) {
- float[] history = mHistory;
- int length = history.length;
- for (int i = 0; i < length; i += 4) {
- history[i] += dx; // X
- history[i + 1] += dy; // Y
- // no need to translate pressure (i+2) and size (i+3)
- }
+ static public MotionEvent obtain(MotionEvent o) {
+ MotionEvent ev = obtain();
+ ev.mDeviceId = o.mDeviceId;
+ ev.mEdgeFlags = o.mEdgeFlags;
+ ev.mDownTime = o.mDownTime;
+ ev.mEventTimeNano = o.mEventTimeNano;
+ ev.mAction = o.mAction;
+ ev.mNumPointers = o.mNumPointers;
+ ev.mRawX = o.mRawX;
+ ev.mRawY = o.mRawY;
+ ev.mMetaState = o.mMetaState;
+ ev.mXPrecision = o.mXPrecision;
+ ev.mYPrecision = o.mYPrecision;
+
+ final int NS = ev.mNumSamples = o.mNumSamples;
+ if (ev.mTimeSamples.length >= NS) {
+ System.arraycopy(o.mTimeSamples, 0, ev.mTimeSamples, 0, NS);
+ } else {
+ ev.mTimeSamples = (long[])o.mTimeSamples.clone();
}
+
+ final int NP = (ev.mNumPointers=o.mNumPointers);
+ if (ev.mPointerIdentifiers.length >= NP) {
+ System.arraycopy(o.mPointerIdentifiers, 0, ev.mPointerIdentifiers, 0, NP);
+ } else {
+ ev.mPointerIdentifiers = (int[])o.mPointerIdentifiers.clone();
+ }
+
+ final int ND = NP * NS * NUM_SAMPLE_DATA;
+ if (ev.mDataSamples.length >= ND) {
+ System.arraycopy(o.mDataSamples, 0, ev.mDataSamples, 0, ND);
+ } else {
+ ev.mDataSamples = (float[])o.mDataSamples.clone();
+ }
+
+ return ev;
}
/**
- * Create a new MotionEvent, copying from an existing one.
+ * Create a new MotionEvent, copying from an existing one, but not including
+ * any historical point information.
*/
- static public MotionEvent obtain(MotionEvent o) {
+ static public MotionEvent obtainNoHistory(MotionEvent o) {
MotionEvent ev = obtain();
ev.mDeviceId = o.mDeviceId;
ev.mEdgeFlags = o.mEdgeFlags;
ev.mDownTime = o.mDownTime;
- ev.mEventTime = o.mEventTime;
+ ev.mEventTimeNano = o.mEventTimeNano;
ev.mAction = o.mAction;
- ev.mX = o.mX;
+ ev.mNumPointers = o.mNumPointers;
ev.mRawX = o.mRawX;
- ev.mY = o.mY;
ev.mRawY = o.mRawY;
- ev.mPressure = o.mPressure;
- ev.mSize = o.mSize;
ev.mMetaState = o.mMetaState;
ev.mXPrecision = o.mXPrecision;
ev.mYPrecision = o.mYPrecision;
- final int N = o.mNumHistory;
- ev.mNumHistory = N;
- if (N > 0) {
- // could be more efficient about this...
- ev.mHistory = (float[])o.mHistory.clone();
- ev.mHistoryTimes = (long[])o.mHistoryTimes.clone();
+
+ ev.mNumSamples = 1;
+ ev.mTimeSamples[0] = o.mTimeSamples[0];
+
+ final int NP = (ev.mNumPointers=o.mNumPointers);
+ if (ev.mPointerIdentifiers.length >= NP) {
+ System.arraycopy(o.mPointerIdentifiers, 0, ev.mPointerIdentifiers, 0, NP);
+ } else {
+ ev.mPointerIdentifiers = (int[])o.mPointerIdentifiers.clone();
}
+
+ final int ND = NP * NUM_SAMPLE_DATA;
+ if (ev.mDataSamples.length >= ND) {
+ System.arraycopy(o.mDataSamples, 0, ev.mDataSamples, 0, ND);
+ } else {
+ ev.mDataSamples = (float[])o.mDataSamples.clone();
+ }
+
return ev;
}
@@ -305,7 +608,7 @@ public final class MotionEvent implements Parcelable {
synchronized (gRecyclerLock) {
if (gRecyclerUsed < MAX_RECYCLED) {
gRecyclerUsed++;
- mNumHistory = 0;
+ mNumSamples = 0;
mNext = gRecyclerTop;
gRecyclerTop = this;
}
@@ -333,44 +636,145 @@ public final class MotionEvent implements Parcelable {
* Returns the time (in ms) when this specific event was generated.
*/
public final long getEventTime() {
- return mEventTime;
+ return mTimeSamples[0];
}
/**
- * Returns the X coordinate of this event. Whole numbers are pixels; the
- * value may have a fraction for input devices that are sub-pixel precise.
+ * Returns the time (in ns) when this specific event was generated.
+ * The value is in nanosecond precision but it may not have nanosecond accuracy.
+ *
+ * @hide
+ */
+ public final long getEventTimeNano() {
+ return mEventTimeNano;
+ }
+
+ /**
+ * {@link #getX(int)} for the first pointer index (may be an
+ * arbitrary pointer identifier).
*/
public final float getX() {
- return mX;
+ return mDataSamples[SAMPLE_X];
}
/**
- * Returns the Y coordinate of this event. Whole numbers are pixels; the
- * value may have a fraction for input devices that are sub-pixel precise.
+ * {@link #getY(int)} for the first pointer index (may be an
+ * arbitrary pointer identifier).
*/
public final float getY() {
- return mY;
+ return mDataSamples[SAMPLE_Y];
+ }
+
+ /**
+ * {@link #getPressure(int)} for the first pointer index (may be an
+ * arbitrary pointer identifier).
+ */
+ public final float getPressure() {
+ return mDataSamples[SAMPLE_PRESSURE];
+ }
+
+ /**
+ * {@link #getSize(int)} for the first pointer index (may be an
+ * arbitrary pointer identifier).
+ */
+ public final float getSize() {
+ return mDataSamples[SAMPLE_SIZE];
+ }
+
+ /**
+ * The number of pointers of data contained in this event. Always
+ * >= 1.
+ */
+ public final int getPointerCount() {
+ return mNumPointers;
+ }
+
+ /**
+ * Return the pointer identifier associated with a particular pointer
+ * data index is this event. The identifier tells you the actual pointer
+ * number associated with the data, accounting for individual pointers
+ * going up and down since the start of the current gesture.
+ * @param pointerIndex Raw index of pointer to retrieve. Value may be from 0
+ * (the first pointer that is down) to {@link #getPointerCount()}-1.
+ */
+ public final int getPointerId(int pointerIndex) {
+ return mPointerIdentifiers[pointerIndex];
+ }
+
+ /**
+ * Given a pointer identifier, find the index of its data in the event.
+ *
+ * @param pointerId The identifier of the pointer to be found.
+ * @return Returns either the index of the pointer (for use with
+ * {@link #getX(int) et al.), or -1 if there is no data available for
+ * that pointer identifier.
+ */
+ public final int findPointerIndex(int pointerId) {
+ int i = mNumPointers;
+ while (i > 0) {
+ i--;
+ if (mPointerIdentifiers[i] == pointerId) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ /**
+ * Returns the X coordinate of this event for the given pointer
+ * <em>index</em> (use {@link #getPointerId(int)} to find the pointer
+ * identifier for this index).
+ * Whole numbers are pixels; the
+ * value may have a fraction for input devices that are sub-pixel precise.
+ * @param pointerIndex Raw index of pointer to retrieve. Value may be from 0
+ * (the first pointer that is down) to {@link #getPointerCount()}-1.
+ */
+ public final float getX(int pointerIndex) {
+ return mDataSamples[(pointerIndex*NUM_SAMPLE_DATA) + SAMPLE_X];
}
/**
- * Returns the current pressure of this event. The pressure generally
+ * Returns the Y coordinate of this event for the given pointer
+ * <em>index</em> (use {@link #getPointerId(int)} to find the pointer
+ * identifier for this index).
+ * Whole numbers are pixels; the
+ * value may have a fraction for input devices that are sub-pixel precise.
+ * @param pointerIndex Raw index of pointer to retrieve. Value may be from 0
+ * (the first pointer that is down) to {@link #getPointerCount()}-1.
+ */
+ public final float getY(int pointerIndex) {
+ return mDataSamples[(pointerIndex*NUM_SAMPLE_DATA) + SAMPLE_Y];
+ }
+
+ /**
+ * Returns the current pressure of this event for the given pointer
+ * <em>index</em> (use {@link #getPointerId(int)} to find the pointer
+ * identifier for this index).
+ * The pressure generally
* ranges from 0 (no pressure at all) to 1 (normal pressure), however
* values higher than 1 may be generated depending on the calibration of
* the input device.
+ * @param pointerIndex Raw index of pointer to retrieve. Value may be from 0
+ * (the first pointer that is down) to {@link #getPointerCount()}-1.
*/
- public final float getPressure() {
- return mPressure;
+ public final float getPressure(int pointerIndex) {
+ return mDataSamples[(pointerIndex*NUM_SAMPLE_DATA) + SAMPLE_PRESSURE];
}
/**
- * Returns a scaled value of the approximate size, of the area being pressed when
- * touched with the finger. The actual value in pixels corresponding to the finger
- * touch is normalized with the device specific range of values
+ * Returns a scaled value of the approximate size for the given pointer
+ * <em>index</em> (use {@link #getPointerId(int)} to find the pointer
+ * identifier for this index).
+ * This represents some approximation of the area of the screen being
+ * pressed; the actual value in pixels corresponding to the
+ * touch is normalized with the device specific range of values
* and scaled to a value between 0 and 1. The value of size can be used to
* determine fat touch events.
+ * @param pointerIndex Raw index of pointer to retrieve. Value may be from 0
+ * (the first pointer that is down) to {@link #getPointerCount()}-1.
*/
- public final float getSize() {
- return mSize;
+ public final float getSize(int pointerIndex) {
+ return mDataSamples[(pointerIndex*NUM_SAMPLE_DATA) + SAMPLE_SIZE];
}
/**
@@ -436,7 +840,7 @@ public final class MotionEvent implements Parcelable {
* @return Returns the number of historical points in the event.
*/
public final int getHistorySize() {
- return mNumHistory;
+ return mNumSamples - 1;
}
/**
@@ -450,63 +854,111 @@ public final class MotionEvent implements Parcelable {
* @see #getEventTime
*/
public final long getHistoricalEventTime(int pos) {
- return mHistoryTimes[pos];
+ return mTimeSamples[pos + 1];
}
/**
- * Returns a historical X coordinate that occurred between this event
- * and the previous event. Only applies to ACTION_MOVE events.
+ * {@link #getHistoricalX(int)} for the first pointer index (may be an
+ * arbitrary pointer identifier).
+ */
+ public final float getHistoricalX(int pos) {
+ return mDataSamples[((pos + 1) * NUM_SAMPLE_DATA * mNumPointers) + SAMPLE_X];
+ }
+
+ /**
+ * {@link #getHistoricalY(int)} for the first pointer index (may be an
+ * arbitrary pointer identifier).
+ */
+ public final float getHistoricalY(int pos) {
+ return mDataSamples[((pos + 1) * NUM_SAMPLE_DATA * mNumPointers) + SAMPLE_Y];
+ }
+
+ /**
+ * {@link #getHistoricalPressure(int)} for the first pointer index (may be an
+ * arbitrary pointer identifier).
+ */
+ public final float getHistoricalPressure(int pos) {
+ return mDataSamples[((pos + 1) * NUM_SAMPLE_DATA * mNumPointers) + SAMPLE_PRESSURE];
+ }
+
+ /**
+ * {@link #getHistoricalSize(int)} for the first pointer index (may be an
+ * arbitrary pointer identifier).
+ */
+ public final float getHistoricalSize(int pos) {
+ return mDataSamples[((pos + 1) * NUM_SAMPLE_DATA * mNumPointers) + SAMPLE_SIZE];
+ }
+
+ /**
+ * Returns a historical X coordinate, as per {@link #getX(int)}, that
+ * occurred between this event and the previous event for the given pointer.
+ * Only applies to ACTION_MOVE events.
*
+ * @param pointerIndex Raw index of pointer to retrieve. Value may be from 0
+ * (the first pointer that is down) to {@link #getPointerCount()}-1.
* @param pos Which historical value to return; must be less than
* {@link #getHistorySize}
*
* @see #getHistorySize
* @see #getX
*/
- public final float getHistoricalX(int pos) {
- return mHistory[pos*4];
+ public final float getHistoricalX(int pointerIndex, int pos) {
+ return mDataSamples[((pos + 1) * NUM_SAMPLE_DATA * mNumPointers)
+ + (pointerIndex * NUM_SAMPLE_DATA) + SAMPLE_X];
}
/**
- * Returns a historical Y coordinate that occurred between this event
- * and the previous event. Only applies to ACTION_MOVE events.
+ * Returns a historical Y coordinate, as per {@link #getY(int)}, that
+ * occurred between this event and the previous event for the given pointer.
+ * Only applies to ACTION_MOVE events.
*
+ * @param pointerIndex Raw index of pointer to retrieve. Value may be from 0
+ * (the first pointer that is down) to {@link #getPointerCount()}-1.
* @param pos Which historical value to return; must be less than
* {@link #getHistorySize}
*
* @see #getHistorySize
* @see #getY
*/
- public final float getHistoricalY(int pos) {
- return mHistory[pos*4 + 1];
+ public final float getHistoricalY(int pointerIndex, int pos) {
+ return mDataSamples[((pos + 1) * NUM_SAMPLE_DATA * mNumPointers)
+ + (pointerIndex * NUM_SAMPLE_DATA) + SAMPLE_Y];
}
/**
- * Returns a historical pressure coordinate that occurred between this event
- * and the previous event. Only applies to ACTION_MOVE events.
+ * Returns a historical pressure coordinate, as per {@link #getPressure(int)},
+ * that occurred between this event and the previous event for the given
+ * pointer. Only applies to ACTION_MOVE events.
*
+ * @param pointerIndex Raw index of pointer to retrieve. Value may be from 0
+ * (the first pointer that is down) to {@link #getPointerCount()}-1.
* @param pos Which historical value to return; must be less than
* {@link #getHistorySize}
- *
+ *
* @see #getHistorySize
* @see #getPressure
*/
- public final float getHistoricalPressure(int pos) {
- return mHistory[pos*4 + 2];
+ public final float getHistoricalPressure(int pointerIndex, int pos) {
+ return mDataSamples[((pos + 1) * NUM_SAMPLE_DATA * mNumPointers)
+ + (pointerIndex * NUM_SAMPLE_DATA) + SAMPLE_PRESSURE];
}
/**
- * Returns a historical size coordinate that occurred between this event
- * and the previous event. Only applies to ACTION_MOVE events.
+ * Returns a historical size coordinate, as per {@link #getSize(int)}, that
+ * occurred between this event and the previous event for the given pointer.
+ * Only applies to ACTION_MOVE events.
*
+ * @param pointerIndex Raw index of pointer to retrieve. Value may be from 0
+ * (the first pointer that is down) to {@link #getPointerCount()}-1.
* @param pos Which historical value to return; must be less than
* {@link #getHistorySize}
- *
+ *
* @see #getHistorySize
* @see #getSize
*/
- public final float getHistoricalSize(int pos) {
- return mHistory[pos*4 + 3];
+ public final float getHistoricalSize(int pointerIndex, int pos) {
+ return mDataSamples[((pos + 1) * NUM_SAMPLE_DATA * mNumPointers)
+ + (pointerIndex * NUM_SAMPLE_DATA) + SAMPLE_SIZE];
}
/**
@@ -556,16 +1008,11 @@ public final class MotionEvent implements Parcelable {
* @param deltaY Amount to add to the current Y coordinate of the event.
*/
public final void offsetLocation(float deltaX, float deltaY) {
- mX += deltaX;
- mY += deltaY;
- final int N = mNumHistory*4;
- if (N <= 0) {
- return;
- }
- final float[] pos = mHistory;
- for (int i=0; i<N; i+=4) {
- pos[i] += deltaX;
- pos[i+1] += deltaY;
+ final int N = mNumPointers*mNumSamples*4;
+ final float[] pos = mDataSamples;
+ for (int i=0; i<N; i+=NUM_SAMPLE_DATA) {
+ pos[i+SAMPLE_X] += deltaX;
+ pos[i+SAMPLE_Y] += deltaY;
}
}
@@ -577,8 +1024,8 @@ public final class MotionEvent implements Parcelable {
* @param y New absolute Y location.
*/
public final void setLocation(float x, float y) {
- float deltaX = x-mX;
- float deltaY = y-mY;
+ float deltaX = x-mDataSamples[SAMPLE_X];
+ float deltaY = y-mDataSamples[SAMPLE_Y];
if (deltaX != 0 || deltaY != 0) {
offsetLocation(deltaX, deltaY);
}
@@ -590,58 +1037,119 @@ public final class MotionEvent implements Parcelable {
* the future, the current values in the event will be added to a list of
* historic values.
*
+ * @param eventTime The time stamp for this data.
* @param x The new X position.
* @param y The new Y position.
* @param pressure The new pressure.
* @param size The new size.
+ * @param metaState Meta key state.
*/
public final void addBatch(long eventTime, float x, float y,
float pressure, float size, int metaState) {
- float[] history = mHistory;
- long[] historyTimes = mHistoryTimes;
- int N;
- int avail;
- if (history == null) {
- mHistory = history = new float[8*4];
- mHistoryTimes = historyTimes = new long[8];
- mNumHistory = N = 0;
- avail = 8;
- } else {
- N = mNumHistory;
- avail = history.length/4;
- if (N == avail) {
- avail += 8;
- float[] newHistory = new float[avail*4];
- System.arraycopy(history, 0, newHistory, 0, N*4);
- mHistory = history = newHistory;
- long[] newHistoryTimes = new long[avail];
- System.arraycopy(historyTimes, 0, newHistoryTimes, 0, N);
- mHistoryTimes = historyTimes = newHistoryTimes;
- }
+ float[] data = mDataSamples;
+ long[] times = mTimeSamples;
+
+ final int NP = mNumPointers;
+ final int NS = mNumSamples;
+ final int NI = NP*NS;
+ final int ND = NI * NUM_SAMPLE_DATA;
+ if (data.length <= ND) {
+ final int NEW_ND = ND + (NP * (BASE_AVAIL_SAMPLES * NUM_SAMPLE_DATA));
+ float[] newData = new float[NEW_ND];
+ System.arraycopy(data, 0, newData, 0, ND);
+ mDataSamples = data = newData;
+ }
+ if (times.length <= NS) {
+ final int NEW_NS = NS + BASE_AVAIL_SAMPLES;
+ long[] newHistoryTimes = new long[NEW_NS];
+ System.arraycopy(times, 0, newHistoryTimes, 0, NS);
+ mTimeSamples = times = newHistoryTimes;
}
+
+ times[NS] = times[0];
+ times[0] = eventTime;
+
+ final int pos = NS*NUM_SAMPLE_DATA;
+ data[pos+SAMPLE_X] = data[SAMPLE_X];
+ data[pos+SAMPLE_Y] = data[SAMPLE_Y];
+ data[pos+SAMPLE_PRESSURE] = data[SAMPLE_PRESSURE];
+ data[pos+SAMPLE_SIZE] = data[SAMPLE_SIZE];
+ data[SAMPLE_X] = x;
+ data[SAMPLE_Y] = y;
+ data[SAMPLE_PRESSURE] = pressure;
+ data[SAMPLE_SIZE] = size;
+ mNumSamples = NS+1;
- historyTimes[N] = mEventTime;
+ mRawX = x;
+ mRawY = y;
+ mMetaState |= metaState;
+ }
- final int pos = N*4;
- history[pos] = mX;
- history[pos+1] = mY;
- history[pos+2] = mPressure;
- history[pos+3] = mSize;
- mNumHistory = N+1;
+ /**
+ * Add a new movement to the batch of movements in this event. The
+ * input data must contain (NUM_SAMPLE_DATA * {@link #getPointerCount()})
+ * samples of data.
+ *
+ * @param eventTime The time stamp for this data.
+ * @param inData The actual data.
+ * @param metaState Meta key state.
+ *
+ * @hide
+ */
+ public final void addBatch(long eventTime, float[] inData, int metaState) {
+ float[] data = mDataSamples;
+ long[] times = mTimeSamples;
+
+ final int NP = mNumPointers;
+ final int NS = mNumSamples;
+ final int NI = NP*NS;
+ final int ND = NI * NUM_SAMPLE_DATA;
+ if (data.length < (ND+(NP*NUM_SAMPLE_DATA))) {
+ final int NEW_ND = ND + (NP * (BASE_AVAIL_SAMPLES * NUM_SAMPLE_DATA));
+ float[] newData = new float[NEW_ND];
+ System.arraycopy(data, 0, newData, 0, ND);
+ mDataSamples = data = newData;
+ }
+ if (times.length < (NS+1)) {
+ final int NEW_NS = NS + BASE_AVAIL_SAMPLES;
+ long[] newHistoryTimes = new long[NEW_NS];
+ System.arraycopy(times, 0, newHistoryTimes, 0, NS);
+ mTimeSamples = times = newHistoryTimes;
+ }
+
+ times[NS] = times[0];
+ times[0] = eventTime;
+
+ System.arraycopy(data, 0, data, ND, mNumPointers*NUM_SAMPLE_DATA);
+ System.arraycopy(inData, 0, data, 0, mNumPointers*NUM_SAMPLE_DATA);
+
+ mNumSamples = NS+1;
- mEventTime = eventTime;
- mX = mRawX = x;
- mY = mRawY = y;
- mPressure = pressure;
- mSize = size;
+ mRawX = inData[SAMPLE_X];
+ mRawY = inData[SAMPLE_Y];
mMetaState |= metaState;
+
+ if (DEBUG_POINTERS) {
+ StringBuilder sb = new StringBuilder(128);
+ sb.append("Add:");
+ for (int i=0; i<mNumPointers; i++) {
+ sb.append(" #");
+ sb.append(mPointerIdentifiers[i]);
+ sb.append("(");
+ sb.append(mDataSamples[(i*NUM_SAMPLE_DATA) + SAMPLE_X]);
+ sb.append(",");
+ sb.append(mDataSamples[(i*NUM_SAMPLE_DATA) + SAMPLE_Y]);
+ sb.append(")");
+ }
+ Log.v("MotionEvent", sb.toString());
+ }
}
@Override
public String toString() {
return "MotionEvent{" + Integer.toHexString(System.identityHashCode(this))
- + " action=" + mAction + " x=" + mX
- + " y=" + mY + " pressure=" + mPressure + " size=" + mSize + "}";
+ + " action=" + mAction + " x=" + getX()
+ + " y=" + getY() + " pressure=" + getPressure() + " size=" + getSize() + "}";
}
public static final Parcelable.Creator<MotionEvent> CREATOR
@@ -663,26 +1171,29 @@ public final class MotionEvent implements Parcelable {
public void writeToParcel(Parcel out, int flags) {
out.writeLong(mDownTime);
- out.writeLong(mEventTime);
+ out.writeLong(mEventTimeNano);
out.writeInt(mAction);
- out.writeFloat(mX);
- out.writeFloat(mY);
- out.writeFloat(mPressure);
- out.writeFloat(mSize);
out.writeInt(mMetaState);
out.writeFloat(mRawX);
out.writeFloat(mRawY);
- final int N = mNumHistory;
- out.writeInt(N);
- if (N > 0) {
- final int N4 = N*4;
+ final int NP = mNumPointers;
+ out.writeInt(NP);
+ final int NS = mNumSamples;
+ out.writeInt(NS);
+ final int NI = NP*NS;
+ if (NI > 0) {
int i;
- float[] history = mHistory;
- for (i=0; i<N4; i++) {
+ int[] state = mPointerIdentifiers;
+ for (i=0; i<NP; i++) {
+ out.writeInt(state[i]);
+ }
+ final int ND = NI*NUM_SAMPLE_DATA;
+ float[] history = mDataSamples;
+ for (i=0; i<ND; i++) {
out.writeFloat(history[i]);
}
- long[] times = mHistoryTimes;
- for (i=0; i<N; i++) {
+ long[] times = mTimeSamples;
+ for (i=0; i<NS; i++) {
out.writeLong(times[i]);
}
}
@@ -694,30 +1205,37 @@ public final class MotionEvent implements Parcelable {
private void readFromParcel(Parcel in) {
mDownTime = in.readLong();
- mEventTime = in.readLong();
+ mEventTimeNano = in.readLong();
mAction = in.readInt();
- mX = in.readFloat();
- mY = in.readFloat();
- mPressure = in.readFloat();
- mSize = in.readFloat();
mMetaState = in.readInt();
mRawX = in.readFloat();
mRawY = in.readFloat();
- final int N = in.readInt();
- if ((mNumHistory=N) > 0) {
- final int N4 = N*4;
- float[] history = mHistory;
- if (history == null || history.length < N4) {
- mHistory = history = new float[N4 + (4*4)];
+ final int NP = in.readInt();
+ mNumPointers = NP;
+ final int NS = in.readInt();
+ mNumSamples = NS;
+ final int NI = NP*NS;
+ if (NI > 0) {
+ int[] ids = mPointerIdentifiers;
+ if (ids.length < NP) {
+ mPointerIdentifiers = ids = new int[NP];
+ }
+ for (int i=0; i<NP; i++) {
+ ids[i] = in.readInt();
+ }
+ float[] history = mDataSamples;
+ final int ND = NI*NUM_SAMPLE_DATA;
+ if (history.length < ND) {
+ mDataSamples = history = new float[ND];
}
- for (int i=0; i<N4; i++) {
+ for (int i=0; i<ND; i++) {
history[i] = in.readFloat();
}
- long[] times = mHistoryTimes;
- if (times == null || times.length < N) {
- mHistoryTimes = times = new long[N + 4];
+ long[] times = mTimeSamples;
+ if (times == null || times.length < NS) {
+ mTimeSamples = times = new long[NS];
}
- for (int i=0; i<N; i++) {
+ for (int i=0; i<NS; i++) {
times[i] = in.readLong();
}
}