Even more native input dispatch work in progress.

Added more tests.
Fixed a regression in Vector.
Fixed bugs in pointer tracking.
Fixed a starvation issue in PollLoop when setting or removing callbacks.
Fixed a couple of policy nits.

Modified the internal representation of MotionEvent to be more
efficient and more consistent.

Added code to skip/cancel virtual key processing when there are multiple
pointers down.  This helps to better disambiguate virtual key presses
from stray touches (such as cheek presses).

Change-Id: I2a7d2cce0195afb9125b23378baa94fd2fc6671c
This commit is contained in:
Jeff Brown
2010-06-16 01:53:36 -07:00
parent 3a0146cd29
commit 5c225b1680
23 changed files with 1266 additions and 611 deletions

View File

@ -176769,7 +176769,7 @@
synchronized="false" synchronized="false"
static="true" static="true"
final="false" final="false"
deprecated="not deprecated" deprecated="deprecated"
visibility="public" visibility="public"
> >
<parameter name="downTime" type="long"> <parameter name="downTime" type="long">
@ -176904,7 +176904,7 @@
native="false" native="false"
synchronized="false" synchronized="false"
static="false" static="false"
final="false" final="true"
deprecated="not deprecated" deprecated="not deprecated"
visibility="public" visibility="public"
> >

View File

@ -27,6 +27,7 @@ import android.util.Log;
* it is being used for. * it is being used for.
*/ */
public final class MotionEvent implements Parcelable { public final class MotionEvent implements Parcelable {
private static final long MS_PER_NS = 1000000;
static final boolean DEBUG_POINTERS = false; static final boolean DEBUG_POINTERS = false;
/** /**
@ -218,31 +219,32 @@ public final class MotionEvent implements Parcelable {
static private int gRecyclerUsed = 0; static private int gRecyclerUsed = 0;
static private MotionEvent gRecyclerTop = null; static private MotionEvent gRecyclerTop = null;
private long mDownTime; private long mDownTimeNano;
private long mEventTimeNano;
private int mAction; private int mAction;
private float mRawX; private float mXOffset;
private float mRawY; private float mYOffset;
private float mXPrecision; private float mXPrecision;
private float mYPrecision; private float mYPrecision;
private int mDeviceId; private int mDeviceId;
private int mEdgeFlags; private int mEdgeFlags;
private int mMetaState; 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 mNumPointers;
private int mNumSamples; private int mNumSamples;
private int mLastDataSampleIndex;
private int mLastEventTimeNanoSampleIndex;
// Array of mNumPointers size of identifiers for each pointer of data. // Array of mNumPointers size of identifiers for each pointer of data.
private int[] mPointerIdentifiers; private int[] mPointerIdentifiers;
// Array of (mNumSamples * mNumPointers * NUM_SAMPLE_DATA) size of event data. // Array of (mNumSamples * mNumPointers * NUM_SAMPLE_DATA) size of event data.
// Samples are ordered from oldest to newest.
private float[] mDataSamples; private float[] mDataSamples;
// Array of mNumSamples size of time stamps.
private long[] mTimeSamples; // Array of mNumSamples size of event time stamps in nanoseconds.
// Samples are ordered from oldest to newest.
private long[] mEventTimeNanoSamples;
private MotionEvent mNext; private MotionEvent mNext;
private RuntimeException mRecycledLocation; private RuntimeException mRecycledLocation;
@ -251,26 +253,9 @@ public final class MotionEvent implements Parcelable {
private MotionEvent(int pointerCount, int sampleCount) { private MotionEvent(int pointerCount, int sampleCount) {
mPointerIdentifiers = new int[pointerCount]; mPointerIdentifiers = new int[pointerCount];
mDataSamples = new float[pointerCount * sampleCount * NUM_SAMPLE_DATA]; mDataSamples = new float[pointerCount * sampleCount * NUM_SAMPLE_DATA];
mTimeSamples = new long[sampleCount]; mEventTimeNanoSamples = new long[sampleCount];
} }
static private MotionEvent obtain() {
final MotionEvent ev;
synchronized (gRecyclerLock) {
if (gRecyclerTop == null) {
return new MotionEvent(BASE_AVAIL_POINTERS, BASE_AVAIL_SAMPLES);
}
ev = gRecyclerTop;
gRecyclerTop = ev.mNext;
gRecyclerUsed--;
}
ev.mRecycledLocation = null;
ev.mRecycled = false;
ev.mNext = null;
return ev;
}
@SuppressWarnings("unused") // used by native code
static private MotionEvent obtain(int pointerCount, int sampleCount) { static private MotionEvent obtain(int pointerCount, int sampleCount) {
final MotionEvent ev; final MotionEvent ev;
synchronized (gRecyclerLock) { synchronized (gRecyclerLock) {
@ -285,7 +270,7 @@ public final class MotionEvent implements Parcelable {
} }
ev = gRecyclerTop; ev = gRecyclerTop;
gRecyclerTop = ev.mNext; gRecyclerTop = ev.mNext;
gRecyclerUsed--; gRecyclerUsed -= 1;
} }
ev.mRecycledLocation = null; ev.mRecycledLocation = null;
ev.mRecycled = false; ev.mRecycled = false;
@ -295,14 +280,12 @@ public final class MotionEvent implements Parcelable {
ev.mPointerIdentifiers = new int[pointerCount]; ev.mPointerIdentifiers = new int[pointerCount];
} }
final int timeSamplesLength = ev.mTimeSamples.length; if (ev.mEventTimeNanoSamples.length < sampleCount) {
if (timeSamplesLength < sampleCount) { ev.mEventTimeNanoSamples = new long[sampleCount];
ev.mTimeSamples = new long[sampleCount];
} }
final int dataSamplesLength = ev.mDataSamples.length;
final int neededDataSamplesLength = pointerCount * sampleCount * NUM_SAMPLE_DATA; final int neededDataSamplesLength = pointerCount * sampleCount * NUM_SAMPLE_DATA;
if (dataSamplesLength < neededDataSamplesLength) { if (ev.mDataSamples.length < neededDataSamplesLength) {
ev.mDataSamples = new float[neededDataSamplesLength]; ev.mDataSamples = new float[neededDataSamplesLength];
} }
@ -342,45 +325,39 @@ public final class MotionEvent implements Parcelable {
static public MotionEvent obtainNano(long downTime, long eventTime, long eventTimeNano, static public MotionEvent obtainNano(long downTime, long eventTime, long eventTimeNano,
int action, int pointers, int[] inPointerIds, float[] inData, int metaState, int action, int pointers, int[] inPointerIds, float[] inData, int metaState,
float xPrecision, float yPrecision, int deviceId, int edgeFlags) { float xPrecision, float yPrecision, int deviceId, int edgeFlags) {
MotionEvent ev = obtain(); MotionEvent ev = obtain(pointers, 1);
ev.mDeviceId = deviceId; ev.mDeviceId = deviceId;
ev.mEdgeFlags = edgeFlags; ev.mEdgeFlags = edgeFlags;
ev.mDownTime = downTime; ev.mDownTimeNano = downTime * MS_PER_NS;
ev.mEventTimeNano = eventTimeNano;
ev.mAction = action; ev.mAction = action;
ev.mMetaState = metaState; ev.mMetaState = metaState;
ev.mRawX = inData[SAMPLE_X]; ev.mXOffset = 0;
ev.mRawY = inData[SAMPLE_Y]; ev.mYOffset = 0;
ev.mXPrecision = xPrecision; ev.mXPrecision = xPrecision;
ev.mYPrecision = yPrecision; ev.mYPrecision = yPrecision;
ev.mNumPointers = pointers; ev.mNumPointers = pointers;
ev.mNumSamples = 1; ev.mNumSamples = 1;
int[] pointerIdentifiers = ev.mPointerIdentifiers; ev.mLastDataSampleIndex = 0;
if (pointerIdentifiers.length < pointers) { ev.mLastEventTimeNanoSampleIndex = 0;
ev.mPointerIdentifiers = pointerIdentifiers = new int[pointers];
}
System.arraycopy(inPointerIds, 0, pointerIdentifiers, 0, pointers);
final int ND = pointers * NUM_SAMPLE_DATA; System.arraycopy(inPointerIds, 0, ev.mPointerIdentifiers, 0, pointers);
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; ev.mEventTimeNanoSamples[0] = eventTimeNano;
System.arraycopy(inData, 0, ev.mDataSamples, 0, pointers * NUM_SAMPLE_DATA);
if (DEBUG_POINTERS) { if (DEBUG_POINTERS) {
StringBuilder sb = new StringBuilder(128); StringBuilder sb = new StringBuilder(128);
sb.append("New:"); sb.append("New:");
for (int i = 0; i < pointers; i++) { for (int i = 0; i < pointers; i++) {
sb.append(" #"); sb.append(" #");
sb.append(ev.mPointerIdentifiers[i]); sb.append(ev.getPointerId(i));
sb.append("("); sb.append("(");
sb.append(ev.mDataSamples[(i*NUM_SAMPLE_DATA) + SAMPLE_X]); sb.append(ev.getX(i));
sb.append(","); sb.append(",");
sb.append(ev.mDataSamples[(i*NUM_SAMPLE_DATA) + SAMPLE_Y]); sb.append(ev.getY(i));
sb.append(")"); sb.append(")");
} }
Log.v("MotionEvent", sb.toString()); Log.v("MotionEvent", sb.toString());
@ -423,27 +400,32 @@ public final class MotionEvent implements Parcelable {
static public MotionEvent obtain(long downTime, long eventTime, int action, static public MotionEvent obtain(long downTime, long eventTime, int action,
float x, float y, float pressure, float size, int metaState, float x, float y, float pressure, float size, int metaState,
float xPrecision, float yPrecision, int deviceId, int edgeFlags) { float xPrecision, float yPrecision, int deviceId, int edgeFlags) {
MotionEvent ev = obtain(); MotionEvent ev = obtain(1, 1);
ev.mDeviceId = deviceId; ev.mDeviceId = deviceId;
ev.mEdgeFlags = edgeFlags; ev.mEdgeFlags = edgeFlags;
ev.mDownTime = downTime; ev.mDownTimeNano = downTime * MS_PER_NS;
ev.mEventTimeNano = eventTime * 1000000;
ev.mAction = action; ev.mAction = action;
ev.mMetaState = metaState; ev.mMetaState = metaState;
ev.mXOffset = 0;
ev.mYOffset = 0;
ev.mXPrecision = xPrecision; ev.mXPrecision = xPrecision;
ev.mYPrecision = yPrecision; ev.mYPrecision = yPrecision;
ev.mNumPointers = 1; ev.mNumPointers = 1;
ev.mNumSamples = 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;
ev.mLastDataSampleIndex = 0;
ev.mLastEventTimeNanoSampleIndex = 0;
ev.mPointerIdentifiers[0] = 0;
ev.mEventTimeNanoSamples[0] = eventTime * MS_PER_NS;
float[] dataSamples = ev.mDataSamples;
dataSamples[SAMPLE_X] = x;
dataSamples[SAMPLE_Y] = y;
dataSamples[SAMPLE_PRESSURE] = pressure;
dataSamples[SAMPLE_SIZE] = size;
return ev; return ev;
} }
@ -478,33 +460,16 @@ public final class MotionEvent implements Parcelable {
* numbers are arbitrary and you shouldn't depend on the values. * numbers are arbitrary and you shouldn't depend on the values.
* @param edgeFlags A bitfield indicating which edges, if any, where touched by this * @param edgeFlags A bitfield indicating which edges, if any, where touched by this
* MotionEvent. * MotionEvent.
*
* @deprecated Use {@link #obtain(long, long, int, float, float, float, float, int, float, float, int, int)}
* instead.
*/ */
@Deprecated
static public MotionEvent obtain(long downTime, long eventTime, int action, static public MotionEvent obtain(long downTime, long eventTime, int action,
int pointers, float x, float y, float pressure, float size, int metaState, int pointers, float x, float y, float pressure, float size, int metaState,
float xPrecision, float yPrecision, int deviceId, int edgeFlags) { float xPrecision, float yPrecision, int deviceId, int edgeFlags) {
MotionEvent ev = obtain(); return obtain(downTime, eventTime, action, x, y, pressure, size,
ev.mDeviceId = deviceId; metaState, xPrecision, yPrecision, deviceId, edgeFlags);
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;
} }
/** /**
@ -526,89 +491,36 @@ public final class MotionEvent implements Parcelable {
*/ */
static public MotionEvent obtain(long downTime, long eventTime, int action, static public MotionEvent obtain(long downTime, long eventTime, int action,
float x, float y, int metaState) { float x, float y, int metaState) {
MotionEvent ev = obtain(); return obtain(downTime, eventTime, action, x, y, 1.0f, 1.0f,
ev.mDeviceId = 0; metaState, 1.0f, 1.0f, 0, 0);
ev.mEdgeFlags = 0;
ev.mDownTime = downTime;
ev.mEventTimeNano = eventTime * 1000000;
ev.mAction = action;
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;
}
/**
* Scales down the coordination of this event by the given scale.
*
* @hide
*/
public void scale(float scale) {
mRawX *= scale;
mRawY *= scale;
mXPrecision *= scale;
mYPrecision *= scale;
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?
}
} }
/** /**
* Create a new MotionEvent, copying from an existing one. * Create a new MotionEvent, copying from an existing one.
*/ */
static public MotionEvent obtain(MotionEvent o) { static public MotionEvent obtain(MotionEvent o) {
MotionEvent ev = obtain(); MotionEvent ev = obtain(o.mNumPointers, o.mNumSamples);
ev.mDeviceId = o.mDeviceId; ev.mDeviceId = o.mDeviceId;
ev.mEdgeFlags = o.mEdgeFlags; ev.mEdgeFlags = o.mEdgeFlags;
ev.mDownTime = o.mDownTime; ev.mDownTimeNano = o.mDownTimeNano;
ev.mEventTimeNano = o.mEventTimeNano;
ev.mAction = o.mAction; ev.mAction = o.mAction;
ev.mNumPointers = o.mNumPointers;
ev.mRawX = o.mRawX;
ev.mRawY = o.mRawY;
ev.mMetaState = o.mMetaState; ev.mMetaState = o.mMetaState;
ev.mXOffset = o.mXOffset;
ev.mYOffset = o.mYOffset;
ev.mXPrecision = o.mXPrecision; ev.mXPrecision = o.mXPrecision;
ev.mYPrecision = o.mYPrecision; ev.mYPrecision = o.mYPrecision;
int numPointers = ev.mNumPointers = o.mNumPointers;
int numSamples = ev.mNumSamples = o.mNumSamples;
final int NS = ev.mNumSamples = o.mNumSamples; ev.mLastDataSampleIndex = o.mLastDataSampleIndex;
if (ev.mTimeSamples.length >= NS) { ev.mLastEventTimeNanoSampleIndex = o.mLastEventTimeNanoSampleIndex;
System.arraycopy(o.mTimeSamples, 0, ev.mTimeSamples, 0, NS);
} else {
ev.mTimeSamples = (long[])o.mTimeSamples.clone();
}
final int NP = (ev.mNumPointers=o.mNumPointers); System.arraycopy(o.mPointerIdentifiers, 0, ev.mPointerIdentifiers, 0, numPointers);
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; System.arraycopy(o.mEventTimeNanoSamples, 0, ev.mEventTimeNanoSamples, 0, numSamples);
if (ev.mDataSamples.length >= ND) {
System.arraycopy(o.mDataSamples, 0, ev.mDataSamples, 0, ND);
} else {
ev.mDataSamples = (float[])o.mDataSamples.clone();
}
System.arraycopy(o.mDataSamples, 0, ev.mDataSamples, 0,
numPointers * numSamples * NUM_SAMPLE_DATA);
return ev; return ev;
} }
@ -617,36 +529,29 @@ public final class MotionEvent implements Parcelable {
* any historical point information. * any historical point information.
*/ */
static public MotionEvent obtainNoHistory(MotionEvent o) { static public MotionEvent obtainNoHistory(MotionEvent o) {
MotionEvent ev = obtain(); MotionEvent ev = obtain(o.mNumPointers, 1);
ev.mDeviceId = o.mDeviceId; ev.mDeviceId = o.mDeviceId;
ev.mEdgeFlags = o.mEdgeFlags; ev.mEdgeFlags = o.mEdgeFlags;
ev.mDownTime = o.mDownTime; ev.mDownTimeNano = o.mDownTimeNano;
ev.mEventTimeNano = o.mEventTimeNano;
ev.mAction = o.mAction; ev.mAction = o.mAction;
ev.mNumPointers = o.mNumPointers;
ev.mRawX = o.mRawX;
ev.mRawY = o.mRawY;
ev.mMetaState = o.mMetaState; ev.mMetaState = o.mMetaState;
ev.mXOffset = o.mXOffset;
ev.mYOffset = o.mYOffset;
ev.mXPrecision = o.mXPrecision; ev.mXPrecision = o.mXPrecision;
ev.mYPrecision = o.mYPrecision; ev.mYPrecision = o.mYPrecision;
int numPointers = ev.mNumPointers = o.mNumPointers;
ev.mNumSamples = 1; ev.mNumSamples = 1;
ev.mTimeSamples[0] = o.mTimeSamples[0];
final int NP = (ev.mNumPointers=o.mNumPointers); ev.mLastDataSampleIndex = 0;
if (ev.mPointerIdentifiers.length >= NP) { ev.mLastEventTimeNanoSampleIndex = 0;
System.arraycopy(o.mPointerIdentifiers, 0, ev.mPointerIdentifiers, 0, NP);
} else {
ev.mPointerIdentifiers = (int[])o.mPointerIdentifiers.clone();
}
final int ND = NP * NUM_SAMPLE_DATA; System.arraycopy(o.mPointerIdentifiers, 0, ev.mPointerIdentifiers, 0, numPointers);
if (ev.mDataSamples.length >= ND) {
System.arraycopy(o.mDataSamples, 0, ev.mDataSamples, 0, ND);
} else {
ev.mDataSamples = (float[])o.mDataSamples.clone();
}
ev.mEventTimeNanoSamples[0] = o.mEventTimeNanoSamples[o.mLastEventTimeNanoSampleIndex];
System.arraycopy(o.mDataSamples, o.mLastDataSampleIndex, ev.mDataSamples, 0,
numPointers * NUM_SAMPLE_DATA);
return ev; return ev;
} }
@ -654,7 +559,7 @@ public final class MotionEvent implements Parcelable {
* Recycle the MotionEvent, to be re-used by a later caller. After calling * Recycle the MotionEvent, to be re-used by a later caller. After calling
* this function you must not ever touch the event again. * this function you must not ever touch the event again.
*/ */
public void recycle() { public final void recycle() {
// Ensure recycle is only called once! // Ensure recycle is only called once!
if (TRACK_RECYCLED_LOCATION) { if (TRACK_RECYCLED_LOCATION) {
if (mRecycledLocation != null) { if (mRecycledLocation != null) {
@ -679,6 +584,27 @@ public final class MotionEvent implements Parcelable {
} }
} }
/**
* Scales down the coordination of this event by the given scale.
*
* @hide
*/
public final void scale(float scale) {
mXOffset *= scale;
mYOffset *= scale;
mXPrecision *= scale;
mYPrecision *= scale;
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?
}
}
/** /**
* Return the kind of action being performed -- one of either * Return the kind of action being performed -- one of either
* {@link #ACTION_DOWN}, {@link #ACTION_MOVE}, {@link #ACTION_UP}, or * {@link #ACTION_DOWN}, {@link #ACTION_MOVE}, {@link #ACTION_UP}, or
@ -719,14 +645,14 @@ public final class MotionEvent implements Parcelable {
* a stream of position events. * a stream of position events.
*/ */
public final long getDownTime() { public final long getDownTime() {
return mDownTime; return mDownTimeNano / MS_PER_NS;
} }
/** /**
* Returns the time (in ms) when this specific event was generated. * Returns the time (in ms) when this specific event was generated.
*/ */
public final long getEventTime() { public final long getEventTime() {
return mTimeSamples[0]; return mEventTimeNanoSamples[mLastEventTimeNanoSampleIndex] / MS_PER_NS;
} }
/** /**
@ -736,7 +662,7 @@ public final class MotionEvent implements Parcelable {
* @hide * @hide
*/ */
public final long getEventTimeNano() { public final long getEventTimeNano() {
return mEventTimeNano; return mEventTimeNanoSamples[mLastEventTimeNanoSampleIndex];
} }
/** /**
@ -744,7 +670,7 @@ public final class MotionEvent implements Parcelable {
* arbitrary pointer identifier). * arbitrary pointer identifier).
*/ */
public final float getX() { public final float getX() {
return mDataSamples[SAMPLE_X]; return mDataSamples[mLastDataSampleIndex + SAMPLE_X] + mXOffset;
} }
/** /**
@ -752,7 +678,7 @@ public final class MotionEvent implements Parcelable {
* arbitrary pointer identifier). * arbitrary pointer identifier).
*/ */
public final float getY() { public final float getY() {
return mDataSamples[SAMPLE_Y]; return mDataSamples[mLastDataSampleIndex + SAMPLE_Y] + mYOffset;
} }
/** /**
@ -760,7 +686,7 @@ public final class MotionEvent implements Parcelable {
* arbitrary pointer identifier). * arbitrary pointer identifier).
*/ */
public final float getPressure() { public final float getPressure() {
return mDataSamples[SAMPLE_PRESSURE]; return mDataSamples[mLastDataSampleIndex + SAMPLE_PRESSURE];
} }
/** /**
@ -768,7 +694,7 @@ public final class MotionEvent implements Parcelable {
* arbitrary pointer identifier). * arbitrary pointer identifier).
*/ */
public final float getSize() { public final float getSize() {
return mDataSamples[SAMPLE_SIZE]; return mDataSamples[mLastDataSampleIndex + SAMPLE_SIZE];
} }
/** /**
@ -820,7 +746,8 @@ public final class MotionEvent implements Parcelable {
* (the first pointer that is down) to {@link #getPointerCount()}-1. * (the first pointer that is down) to {@link #getPointerCount()}-1.
*/ */
public final float getX(int pointerIndex) { public final float getX(int pointerIndex) {
return mDataSamples[(pointerIndex*NUM_SAMPLE_DATA) + SAMPLE_X]; return mDataSamples[mLastDataSampleIndex
+ pointerIndex * NUM_SAMPLE_DATA + SAMPLE_X] + mXOffset;
} }
/** /**
@ -833,7 +760,8 @@ public final class MotionEvent implements Parcelable {
* (the first pointer that is down) to {@link #getPointerCount()}-1. * (the first pointer that is down) to {@link #getPointerCount()}-1.
*/ */
public final float getY(int pointerIndex) { public final float getY(int pointerIndex) {
return mDataSamples[(pointerIndex*NUM_SAMPLE_DATA) + SAMPLE_Y]; return mDataSamples[mLastDataSampleIndex
+ pointerIndex * NUM_SAMPLE_DATA + SAMPLE_Y] + mYOffset;
} }
/** /**
@ -848,7 +776,8 @@ public final class MotionEvent implements Parcelable {
* (the first pointer that is down) to {@link #getPointerCount()}-1. * (the first pointer that is down) to {@link #getPointerCount()}-1.
*/ */
public final float getPressure(int pointerIndex) { public final float getPressure(int pointerIndex) {
return mDataSamples[(pointerIndex*NUM_SAMPLE_DATA) + SAMPLE_PRESSURE]; return mDataSamples[mLastDataSampleIndex
+ pointerIndex * NUM_SAMPLE_DATA + SAMPLE_PRESSURE];
} }
/** /**
@ -864,7 +793,8 @@ public final class MotionEvent implements Parcelable {
* (the first pointer that is down) to {@link #getPointerCount()}-1. * (the first pointer that is down) to {@link #getPointerCount()}-1.
*/ */
public final float getSize(int pointerIndex) { public final float getSize(int pointerIndex) {
return mDataSamples[(pointerIndex*NUM_SAMPLE_DATA) + SAMPLE_SIZE]; return mDataSamples[mLastDataSampleIndex
+ pointerIndex * NUM_SAMPLE_DATA + SAMPLE_SIZE];
} }
/** /**
@ -888,7 +818,7 @@ public final class MotionEvent implements Parcelable {
* and views. * and views.
*/ */
public final float getRawX() { public final float getRawX() {
return mRawX; return mDataSamples[mLastDataSampleIndex + SAMPLE_X];
} }
/** /**
@ -898,7 +828,7 @@ public final class MotionEvent implements Parcelable {
* and views. * and views.
*/ */
public final float getRawY() { public final float getRawY() {
return mRawY; return mDataSamples[mLastDataSampleIndex + SAMPLE_Y];
} }
/** /**
@ -930,7 +860,7 @@ public final class MotionEvent implements Parcelable {
* @return Returns the number of historical points in the event. * @return Returns the number of historical points in the event.
*/ */
public final int getHistorySize() { public final int getHistorySize() {
return mNumSamples - 1; return mLastEventTimeNanoSampleIndex;
} }
/** /**
@ -944,7 +874,7 @@ public final class MotionEvent implements Parcelable {
* @see #getEventTime * @see #getEventTime
*/ */
public final long getHistoricalEventTime(int pos) { public final long getHistoricalEventTime(int pos) {
return mTimeSamples[pos + 1]; return mEventTimeNanoSamples[pos] / MS_PER_NS;
} }
/** /**
@ -952,7 +882,7 @@ public final class MotionEvent implements Parcelable {
* arbitrary pointer identifier). * arbitrary pointer identifier).
*/ */
public final float getHistoricalX(int pos) { public final float getHistoricalX(int pos) {
return mDataSamples[((pos + 1) * NUM_SAMPLE_DATA * mNumPointers) + SAMPLE_X]; return mDataSamples[pos * mNumPointers * NUM_SAMPLE_DATA + SAMPLE_X] + mXOffset;
} }
/** /**
@ -960,7 +890,7 @@ public final class MotionEvent implements Parcelable {
* arbitrary pointer identifier). * arbitrary pointer identifier).
*/ */
public final float getHistoricalY(int pos) { public final float getHistoricalY(int pos) {
return mDataSamples[((pos + 1) * NUM_SAMPLE_DATA * mNumPointers) + SAMPLE_Y]; return mDataSamples[pos * mNumPointers * NUM_SAMPLE_DATA + SAMPLE_Y] + mYOffset;
} }
/** /**
@ -968,7 +898,7 @@ public final class MotionEvent implements Parcelable {
* arbitrary pointer identifier). * arbitrary pointer identifier).
*/ */
public final float getHistoricalPressure(int pos) { public final float getHistoricalPressure(int pos) {
return mDataSamples[((pos + 1) * NUM_SAMPLE_DATA * mNumPointers) + SAMPLE_PRESSURE]; return mDataSamples[pos * mNumPointers * NUM_SAMPLE_DATA + SAMPLE_PRESSURE];
} }
/** /**
@ -976,7 +906,7 @@ public final class MotionEvent implements Parcelable {
* arbitrary pointer identifier). * arbitrary pointer identifier).
*/ */
public final float getHistoricalSize(int pos) { public final float getHistoricalSize(int pos) {
return mDataSamples[((pos + 1) * NUM_SAMPLE_DATA * mNumPointers) + SAMPLE_SIZE]; return mDataSamples[pos * mNumPointers * NUM_SAMPLE_DATA + SAMPLE_SIZE];
} }
/** /**
@ -993,8 +923,8 @@ public final class MotionEvent implements Parcelable {
* @see #getX * @see #getX
*/ */
public final float getHistoricalX(int pointerIndex, int pos) { public final float getHistoricalX(int pointerIndex, int pos) {
return mDataSamples[((pos + 1) * NUM_SAMPLE_DATA * mNumPointers) return mDataSamples[(pos * mNumPointers + pointerIndex)
+ (pointerIndex * NUM_SAMPLE_DATA) + SAMPLE_X]; * NUM_SAMPLE_DATA + SAMPLE_X] + mXOffset;
} }
/** /**
@ -1011,8 +941,8 @@ public final class MotionEvent implements Parcelable {
* @see #getY * @see #getY
*/ */
public final float getHistoricalY(int pointerIndex, int pos) { public final float getHistoricalY(int pointerIndex, int pos) {
return mDataSamples[((pos + 1) * NUM_SAMPLE_DATA * mNumPointers) return mDataSamples[(pos * mNumPointers + pointerIndex)
+ (pointerIndex * NUM_SAMPLE_DATA) + SAMPLE_Y]; * NUM_SAMPLE_DATA + SAMPLE_Y] + mYOffset;
} }
/** /**
@ -1029,8 +959,8 @@ public final class MotionEvent implements Parcelable {
* @see #getPressure * @see #getPressure
*/ */
public final float getHistoricalPressure(int pointerIndex, int pos) { public final float getHistoricalPressure(int pointerIndex, int pos) {
return mDataSamples[((pos + 1) * NUM_SAMPLE_DATA * mNumPointers) return mDataSamples[(pos * mNumPointers + pointerIndex)
+ (pointerIndex * NUM_SAMPLE_DATA) + SAMPLE_PRESSURE]; * NUM_SAMPLE_DATA + SAMPLE_PRESSURE];
} }
/** /**
@ -1047,8 +977,8 @@ public final class MotionEvent implements Parcelable {
* @see #getSize * @see #getSize
*/ */
public final float getHistoricalSize(int pointerIndex, int pos) { public final float getHistoricalSize(int pointerIndex, int pos) {
return mDataSamples[((pos + 1) * NUM_SAMPLE_DATA * mNumPointers) return mDataSamples[(pos * mNumPointers + pointerIndex)
+ (pointerIndex * NUM_SAMPLE_DATA) + SAMPLE_SIZE]; * NUM_SAMPLE_DATA + SAMPLE_SIZE];
} }
/** /**
@ -1098,12 +1028,8 @@ public final class MotionEvent implements Parcelable {
* @param deltaY Amount to add to the current Y coordinate of the event. * @param deltaY Amount to add to the current Y coordinate of the event.
*/ */
public final void offsetLocation(float deltaX, float deltaY) { public final void offsetLocation(float deltaX, float deltaY) {
final int N = mNumPointers*mNumSamples*4; mXOffset += deltaX;
final float[] pos = mDataSamples; mYOffset += deltaY;
for (int i=0; i<N; i+=NUM_SAMPLE_DATA) {
pos[i+SAMPLE_X] += deltaX;
pos[i+SAMPLE_Y] += deltaY;
}
} }
/** /**
@ -1114,11 +1040,28 @@ public final class MotionEvent implements Parcelable {
* @param y New absolute Y location. * @param y New absolute Y location.
*/ */
public final void setLocation(float x, float y) { public final void setLocation(float x, float y) {
float deltaX = x-mDataSamples[SAMPLE_X]; mXOffset = x - mDataSamples[mLastDataSampleIndex + SAMPLE_X];
float deltaY = y-mDataSamples[SAMPLE_Y]; mYOffset = y - mDataSamples[mLastDataSampleIndex + SAMPLE_Y];
if (deltaX != 0 || deltaY != 0) {
offsetLocation(deltaX, deltaY);
} }
private final void incrementNumSamplesAndReserveStorage(int dataSampleStride) {
if (mNumSamples == mEventTimeNanoSamples.length) {
long[] newEventTimeNanoSamples = new long[mNumSamples + BASE_AVAIL_SAMPLES];
System.arraycopy(mEventTimeNanoSamples, 0, newEventTimeNanoSamples, 0, mNumSamples);
mEventTimeNanoSamples = newEventTimeNanoSamples;
}
int nextDataSampleIndex = mLastDataSampleIndex + dataSampleStride;
if (nextDataSampleIndex + dataSampleStride > mDataSamples.length) {
float[] newDataSamples = new float[nextDataSampleIndex
+ BASE_AVAIL_SAMPLES * dataSampleStride];
System.arraycopy(mDataSamples, 0, newDataSamples, 0, nextDataSampleIndex);
mDataSamples = newDataSamples;
}
mLastEventTimeNanoSampleIndex = mNumSamples;
mLastDataSampleIndex = nextDataSampleIndex;
mNumSamples += 1;
} }
/** /**
@ -1136,42 +1079,16 @@ public final class MotionEvent implements Parcelable {
*/ */
public final void addBatch(long eventTime, float x, float y, public final void addBatch(long eventTime, float x, float y,
float pressure, float size, int metaState) { float pressure, float size, int metaState) {
float[] data = mDataSamples; incrementNumSamplesAndReserveStorage(NUM_SAMPLE_DATA);
long[] times = mTimeSamples;
final int NP = mNumPointers; mEventTimeNanoSamples[mLastEventTimeNanoSampleIndex] = eventTime * MS_PER_NS;
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]; float[] dataSamples = mDataSamples;
times[0] = eventTime; dataSamples[mLastDataSampleIndex + SAMPLE_X] = x - mXOffset;
dataSamples[mLastDataSampleIndex + SAMPLE_Y] = y - mYOffset;
dataSamples[mLastDataSampleIndex + SAMPLE_PRESSURE] = pressure;
dataSamples[mLastDataSampleIndex + SAMPLE_SIZE] = size;
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;
mRawX = x;
mRawY = y;
mMetaState |= metaState; mMetaState |= metaState;
} }
@ -1187,36 +1104,24 @@ public final class MotionEvent implements Parcelable {
* @hide * @hide
*/ */
public final void addBatch(long eventTime, float[] inData, int metaState) { public final void addBatch(long eventTime, float[] inData, int metaState) {
float[] data = mDataSamples; final int numPointers = mNumPointers;
long[] times = mTimeSamples; final int dataSampleStride = numPointers * NUM_SAMPLE_DATA;
incrementNumSamplesAndReserveStorage(dataSampleStride);
final int NP = mNumPointers; mEventTimeNanoSamples[mLastEventTimeNanoSampleIndex] = eventTime * MS_PER_NS;
final int NS = mNumSamples;
final int NI = NP*NS; float[] dataSamples = mDataSamples;
final int ND = NI * NUM_SAMPLE_DATA; System.arraycopy(inData, 0, dataSamples, mLastDataSampleIndex, dataSampleStride);
if (data.length < (ND+(NP*NUM_SAMPLE_DATA))) {
final int NEW_ND = ND + (NP * (BASE_AVAIL_SAMPLES * NUM_SAMPLE_DATA)); if (mXOffset != 0 || mYOffset != 0) {
float[] newData = new float[NEW_ND]; int index = mLastEventTimeNanoSampleIndex;
System.arraycopy(data, 0, newData, 0, ND); for (int i = 0; i < numPointers; i++) {
mDataSamples = data = newData; dataSamples[index + SAMPLE_X] -= mXOffset;
dataSamples[index + SAMPLE_Y] -= mYOffset;
index += NUM_SAMPLE_DATA;
} }
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;
mRawX = inData[SAMPLE_X];
mRawY = inData[SAMPLE_Y];
mMetaState |= metaState; mMetaState |= metaState;
if (DEBUG_POINTERS) { if (DEBUG_POINTERS) {
@ -1224,11 +1129,11 @@ public final class MotionEvent implements Parcelable {
sb.append("Add:"); sb.append("Add:");
for (int i = 0; i < mNumPointers; i++) { for (int i = 0; i < mNumPointers; i++) {
sb.append(" #"); sb.append(" #");
sb.append(mPointerIdentifiers[i]); sb.append(getPointerId(i));
sb.append("("); sb.append("(");
sb.append(mDataSamples[(i*NUM_SAMPLE_DATA) + SAMPLE_X]); sb.append(getX(i));
sb.append(","); sb.append(",");
sb.append(mDataSamples[(i*NUM_SAMPLE_DATA) + SAMPLE_Y]); sb.append(getY(i));
sb.append(")"); sb.append(")");
} }
Log.v("MotionEvent", sb.toString()); Log.v("MotionEvent", sb.toString());
@ -1245,8 +1150,41 @@ public final class MotionEvent implements Parcelable {
public static final Parcelable.Creator<MotionEvent> CREATOR public static final Parcelable.Creator<MotionEvent> CREATOR
= new Parcelable.Creator<MotionEvent>() { = new Parcelable.Creator<MotionEvent>() {
public MotionEvent createFromParcel(Parcel in) { public MotionEvent createFromParcel(Parcel in) {
MotionEvent ev = obtain(); final int NP = in.readInt();
ev.readFromParcel(in); final int NS = in.readInt();
final int NI = NP * NS * NUM_SAMPLE_DATA;
MotionEvent ev = obtain(NP, NS);
ev.mNumPointers = NP;
ev.mNumSamples = NS;
ev.mDownTimeNano = in.readLong();
ev.mAction = in.readInt();
ev.mXOffset = in.readFloat();
ev.mYOffset = in.readFloat();
ev.mXPrecision = in.readFloat();
ev.mYPrecision = in.readFloat();
ev.mDeviceId = in.readInt();
ev.mEdgeFlags = in.readInt();
ev.mMetaState = in.readInt();
final int[] pointerIdentifiers = ev.mPointerIdentifiers;
for (int i = 0; i < NP; i++) {
pointerIdentifiers[i] = in.readInt();
}
final long[] eventTimeNanoSamples = ev.mEventTimeNanoSamples;
for (int i = 0; i < NS; i++) {
eventTimeNanoSamples[i] = in.readLong();
}
final float[] dataSamples = ev.mDataSamples;
for (int i = 0; i < NI; i++) {
dataSamples[i] = in.readFloat();
}
ev.mLastEventTimeNanoSampleIndex = NS - 1;
ev.mLastDataSampleIndex = (NS - 1) * NP * NUM_SAMPLE_DATA;
return ev; return ev;
} }
@ -1260,79 +1198,36 @@ public final class MotionEvent implements Parcelable {
} }
public void writeToParcel(Parcel out, int flags) { public void writeToParcel(Parcel out, int flags) {
out.writeLong(mDownTime);
out.writeLong(mEventTimeNano);
out.writeInt(mAction);
out.writeInt(mMetaState);
out.writeFloat(mRawX);
out.writeFloat(mRawY);
final int NP = mNumPointers; final int NP = mNumPointers;
out.writeInt(NP);
final int NS = mNumSamples; final int NS = mNumSamples;
final int NI = NP * NS * NUM_SAMPLE_DATA;
out.writeInt(NP);
out.writeInt(NS); out.writeInt(NS);
final int NI = NP*NS;
if (NI > 0) { out.writeLong(mDownTimeNano);
int i; out.writeInt(mAction);
int[] state = mPointerIdentifiers; out.writeFloat(mXOffset);
for (i=0; i<NP; i++) { out.writeFloat(mYOffset);
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 = mTimeSamples;
for (i=0; i<NS; i++) {
out.writeLong(times[i]);
}
}
out.writeFloat(mXPrecision); out.writeFloat(mXPrecision);
out.writeFloat(mYPrecision); out.writeFloat(mYPrecision);
out.writeInt(mDeviceId); out.writeInt(mDeviceId);
out.writeInt(mEdgeFlags); out.writeInt(mEdgeFlags);
} out.writeInt(mMetaState);
private void readFromParcel(Parcel in) { final int[] pointerIdentifiers = mPointerIdentifiers;
mDownTime = in.readLong();
mEventTimeNano = in.readLong();
mAction = in.readInt();
mMetaState = in.readInt();
mRawX = in.readFloat();
mRawY = in.readFloat();
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++) { for (int i = 0; i < NP; i++) {
ids[i] = in.readInt(); out.writeInt(pointerIdentifiers[i]);
}
float[] history = mDataSamples;
final int ND = NI*NUM_SAMPLE_DATA;
if (history.length < ND) {
mDataSamples = history = new float[ND];
}
for (int i=0; i<ND; i++) {
history[i] = in.readFloat();
}
long[] times = mTimeSamples;
if (times == null || times.length < NS) {
mTimeSamples = times = new long[NS];
}
for (int i=0; i<NS; i++) {
times[i] = in.readLong();
}
}
mXPrecision = in.readFloat();
mYPrecision = in.readFloat();
mDeviceId = in.readInt();
mEdgeFlags = in.readInt();
} }
final long[] eventTimeNanoSamples = mEventTimeNanoSamples;
for (int i = 0; i < NS; i++) {
out.writeLong(eventTimeNanoSamples[i]);
}
final float[] dataSamples = mDataSamples;
for (int i = 0; i < NI; i++) {
out.writeFloat(dataSamples[i]);
}
}
} }

View File

@ -121,9 +121,9 @@ static jobjectArray android_view_InputChannel_nativeOpenInputChannelPair(JNIEnv*
String8 name(nameChars); String8 name(nameChars);
env->ReleaseStringUTFChars(nameObj, nameChars); env->ReleaseStringUTFChars(nameObj, nameChars);
InputChannel* serverChannel; sp<InputChannel> serverChannel;
InputChannel* clientChannel; sp<InputChannel> clientChannel;
status_t result = InputChannel::openInputChannelPair(name, & serverChannel, & clientChannel); status_t result = InputChannel::openInputChannelPair(name, serverChannel, clientChannel);
if (result) { if (result) {
LOGE("Could not open input channel pair. status=%d", result); LOGE("Could not open input channel pair. status=%d", result);

View File

@ -36,11 +36,10 @@ static struct {
jmethodID obtain; jmethodID obtain;
jmethodID recycle; jmethodID recycle;
jfieldID mDownTime; jfieldID mDownTimeNano;
jfieldID mEventTimeNano;
jfieldID mAction; jfieldID mAction;
jfieldID mRawX; jfieldID mXOffset;
jfieldID mRawY; jfieldID mYOffset;
jfieldID mXPrecision; jfieldID mXPrecision;
jfieldID mYPrecision; jfieldID mYPrecision;
jfieldID mDeviceId; jfieldID mDeviceId;
@ -50,7 +49,9 @@ static struct {
jfieldID mNumSamples; jfieldID mNumSamples;
jfieldID mPointerIdentifiers; jfieldID mPointerIdentifiers;
jfieldID mDataSamples; jfieldID mDataSamples;
jfieldID mTimeSamples; jfieldID mEventTimeNanoSamples;
jfieldID mLastDataSampleIndex;
jfieldID mLastEventTimeNanoSampleIndex;
} gMotionEventClassInfo; } gMotionEventClassInfo;
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
@ -69,22 +70,14 @@ jobject android_view_MotionEvent_fromNative(JNIEnv* env, const MotionEvent* even
return NULL; return NULL;
} }
// MotionEvent.mEventTimeNano is the time of the oldest sample because env->SetLongField(eventObj, gMotionEventClassInfo.mDownTimeNano,
// MotionEvent.addBatch does not update it as successive samples are added. event->getDownTime());
jlong eventTimeNano = numHistoricalSamples != 0
? event->getHistoricalEventTime(0)
: event->getEventTime();
env->SetLongField(eventObj, gMotionEventClassInfo.mDownTime,
nanoseconds_to_milliseconds(event->getDownTime()));
env->SetLongField(eventObj, gMotionEventClassInfo.mEventTimeNano,
eventTimeNano);
env->SetIntField(eventObj, gMotionEventClassInfo.mAction, env->SetIntField(eventObj, gMotionEventClassInfo.mAction,
event->getAction()); event->getAction());
env->SetFloatField(eventObj, gMotionEventClassInfo.mRawX, env->SetFloatField(eventObj, gMotionEventClassInfo.mXOffset,
event->getRawX()); event->getXOffset());
env->SetFloatField(eventObj, gMotionEventClassInfo.mRawY, env->SetFloatField(eventObj, gMotionEventClassInfo.mYOffset,
event->getRawY()); event->getYOffset());
env->SetFloatField(eventObj, gMotionEventClassInfo.mXPrecision, env->SetFloatField(eventObj, gMotionEventClassInfo.mXPrecision,
event->getXPrecision()); event->getXPrecision());
env->SetFloatField(eventObj, gMotionEventClassInfo.mYPrecision, env->SetFloatField(eventObj, gMotionEventClassInfo.mYPrecision,
@ -99,65 +92,62 @@ jobject android_view_MotionEvent_fromNative(JNIEnv* env, const MotionEvent* even
numPointers); numPointers);
env->SetIntField(eventObj, gMotionEventClassInfo.mNumSamples, env->SetIntField(eventObj, gMotionEventClassInfo.mNumSamples,
numSamples); numSamples);
env->SetIntField(eventObj, gMotionEventClassInfo.mLastDataSampleIndex,
(numSamples - 1) * numPointers * NUM_SAMPLE_DATA);
env->SetIntField(eventObj, gMotionEventClassInfo.mLastEventTimeNanoSampleIndex,
numSamples - 1);
jintArray pointerIdentifierArray = jintArray(env->GetObjectField(eventObj, jintArray pointerIdentifierArray = jintArray(env->GetObjectField(eventObj,
gMotionEventClassInfo.mPointerIdentifiers)); gMotionEventClassInfo.mPointerIdentifiers));
jfloatArray dataSampleArray = jfloatArray(env->GetObjectField(eventObj, jfloatArray dataSampleArray = jfloatArray(env->GetObjectField(eventObj,
gMotionEventClassInfo.mDataSamples)); gMotionEventClassInfo.mDataSamples));
jlongArray timeSampleArray = jlongArray(env->GetObjectField(eventObj, jlongArray eventTimeNanoSampleArray = jlongArray(env->GetObjectField(eventObj,
gMotionEventClassInfo.mTimeSamples)); gMotionEventClassInfo.mEventTimeNanoSamples));
jint* pointerIdentifiers = (jint*)env->GetPrimitiveArrayCritical(pointerIdentifierArray, NULL); jint* pointerIdentifiers = (jint*)env->GetPrimitiveArrayCritical(pointerIdentifierArray, NULL);
jfloat* dataSamples = (jfloat*)env->GetPrimitiveArrayCritical(dataSampleArray, NULL); jfloat* dataSamples = (jfloat*)env->GetPrimitiveArrayCritical(dataSampleArray, NULL);
jlong* timeSamples = (jlong*)env->GetPrimitiveArrayCritical(timeSampleArray, NULL); jlong* eventTimeNanoSamples = (jlong*)env->GetPrimitiveArrayCritical(
eventTimeNanoSampleArray, NULL);
const int32_t* srcPointerIdentifiers = event->getPointerIds();
jint* destPointerIdentifiers = pointerIdentifiers;
for (jint i = 0; i < numPointers; i++) { for (jint i = 0; i < numPointers; i++) {
pointerIdentifiers[i] = event->getPointerId(i); *(destPointerIdentifiers++) = *(srcPointerIdentifiers++);
} }
// Most recent data is in first slot of the DVM array, followed by the oldest, const nsecs_t* srcSampleEventTimes = event->getSampleEventTimes();
// and then all others are in order. jlong* destEventTimeNanoSamples = eventTimeNanoSamples;
for (jint i = 0; i < numSamples; i++) {
jfloat* currentDataSample = dataSamples; *(destEventTimeNanoSamples++) = *(srcSampleEventTimes++);
jlong* currentTimeSample = timeSamples;
*(currentTimeSample++) = nanoseconds_to_milliseconds(event->getEventTime());
for (jint j = 0; j < numPointers; j++) {
*(currentDataSample++) = event->getX(j);
*(currentDataSample++) = event->getY(j);
*(currentDataSample++) = event->getPressure(j);
*(currentDataSample++) = event->getSize(j);
} }
for (jint i = 0; i < numHistoricalSamples; i++) { const PointerCoords* srcSamplePointerCoords = event->getSamplePointerCoords();
*(currentTimeSample++) = nanoseconds_to_milliseconds(event->getHistoricalEventTime(i)); jfloat* destDataSamples = dataSamples;
for (jint j = 0; j < numPointers; j++) { jint numItems = numSamples * numPointers;
*(currentDataSample++) = event->getHistoricalX(j, i); for (jint i = 0; i < numItems; i++) {
*(currentDataSample++) = event->getHistoricalY(j, i); *(destDataSamples++) = srcSamplePointerCoords->x;
*(currentDataSample++) = event->getHistoricalPressure(j, i); *(destDataSamples++) = srcSamplePointerCoords->y;
*(currentDataSample++) = event->getHistoricalSize(j, i); *(destDataSamples++) = srcSamplePointerCoords->pressure;
} *(destDataSamples++) = srcSamplePointerCoords->size;
srcSamplePointerCoords += 1;
} }
env->ReleasePrimitiveArrayCritical(pointerIdentifierArray, pointerIdentifiers, 0); env->ReleasePrimitiveArrayCritical(pointerIdentifierArray, pointerIdentifiers, 0);
env->ReleasePrimitiveArrayCritical(dataSampleArray, dataSamples, 0); env->ReleasePrimitiveArrayCritical(dataSampleArray, dataSamples, 0);
env->ReleasePrimitiveArrayCritical(timeSampleArray, timeSamples, 0); env->ReleasePrimitiveArrayCritical(eventTimeNanoSampleArray, eventTimeNanoSamples, 0);
env->DeleteLocalRef(pointerIdentifierArray); env->DeleteLocalRef(pointerIdentifierArray);
env->DeleteLocalRef(dataSampleArray); env->DeleteLocalRef(dataSampleArray);
env->DeleteLocalRef(timeSampleArray); env->DeleteLocalRef(eventTimeNanoSampleArray);
return eventObj; return eventObj;
} }
void android_view_MotionEvent_toNative(JNIEnv* env, jobject eventObj, int32_t nature, void android_view_MotionEvent_toNative(JNIEnv* env, jobject eventObj, int32_t nature,
MotionEvent* event) { MotionEvent* event) {
// MotionEvent.mEventTimeNano is the time of the oldest sample because jlong downTimeNano = env->GetLongField(eventObj, gMotionEventClassInfo.mDownTimeNano);
// MotionEvent.addBatch does not update it as successive samples are added.
jlong downTime = env->GetLongField(eventObj, gMotionEventClassInfo.mDownTime);
jlong eventTimeNano = env->GetLongField(eventObj, gMotionEventClassInfo.mEventTimeNano);
jint action = env->GetIntField(eventObj, gMotionEventClassInfo.mAction); jint action = env->GetIntField(eventObj, gMotionEventClassInfo.mAction);
jfloat rawX = env->GetFloatField(eventObj, gMotionEventClassInfo.mRawX); jfloat xOffset = env->GetFloatField(eventObj, gMotionEventClassInfo.mXOffset);
jfloat rawY = env->GetFloatField(eventObj, gMotionEventClassInfo.mRawY); jfloat yOffset = env->GetFloatField(eventObj, gMotionEventClassInfo.mYOffset);
jfloat xPrecision = env->GetFloatField(eventObj, gMotionEventClassInfo.mXPrecision); jfloat xPrecision = env->GetFloatField(eventObj, gMotionEventClassInfo.mXPrecision);
jfloat yPrecision = env->GetFloatField(eventObj, gMotionEventClassInfo.mYPrecision); jfloat yPrecision = env->GetFloatField(eventObj, gMotionEventClassInfo.mYPrecision);
jint deviceId = env->GetIntField(eventObj, gMotionEventClassInfo.mDeviceId); jint deviceId = env->GetIntField(eventObj, gMotionEventClassInfo.mDeviceId);
@ -169,72 +159,51 @@ void android_view_MotionEvent_toNative(JNIEnv* env, jobject eventObj, int32_t na
gMotionEventClassInfo.mPointerIdentifiers)); gMotionEventClassInfo.mPointerIdentifiers));
jfloatArray dataSampleArray = jfloatArray(env->GetObjectField(eventObj, jfloatArray dataSampleArray = jfloatArray(env->GetObjectField(eventObj,
gMotionEventClassInfo.mDataSamples)); gMotionEventClassInfo.mDataSamples));
jlongArray timeSampleArray = jlongArray(env->GetObjectField(eventObj, jlongArray eventTimeNanoSampleArray = jlongArray(env->GetObjectField(eventObj,
gMotionEventClassInfo.mTimeSamples)); gMotionEventClassInfo.mEventTimeNanoSamples));
LOG_FATAL_IF(numPointers == 0, "numPointers was zero"); LOG_FATAL_IF(numPointers == 0, "numPointers was zero");
LOG_FATAL_IF(numSamples == 0, "numSamples was zero"); LOG_FATAL_IF(numSamples == 0, "numSamples was zero");
jint* pointerIdentifiers = (jint*)env->GetPrimitiveArrayCritical(pointerIdentifierArray, NULL); jint* pointerIdentifiers = (jint*)env->GetPrimitiveArrayCritical(pointerIdentifierArray, NULL);
jfloat* dataSamples = (jfloat*)env->GetPrimitiveArrayCritical(dataSampleArray, NULL); jfloat* dataSamples = (jfloat*)env->GetPrimitiveArrayCritical(dataSampleArray, NULL);
jlong* timeSamples = (jlong*)env->GetPrimitiveArrayCritical(timeSampleArray, NULL); jlong* eventTimeNanoSamples = (jlong*)env->GetPrimitiveArrayCritical(
eventTimeNanoSampleArray, NULL);
// Most recent data is in first slot of the DVM array, followed by the oldest, jfloat* srcDataSamples = dataSamples;
// and then all others are in order. eventTimeNano is the time of the oldest sample jlong* srcEventTimeNanoSamples = eventTimeNanoSamples;
// since MotionEvent.addBatch does not update it.
jint numHistoricalSamples = numSamples - 1; jlong sampleEventTime = *(srcEventTimeNanoSamples++);
jint dataSampleStride = numPointers * NUM_SAMPLE_DATA; PointerCoords samplePointerCoords[MAX_POINTERS];
const jfloat* currentDataSample;
const jlong* currentTimeSample;
if (numHistoricalSamples == 0) {
currentDataSample = dataSamples;
currentTimeSample = timeSamples;
} else {
currentDataSample = dataSamples + dataSampleStride;
currentTimeSample = timeSamples + 1;
}
PointerCoords pointerCoords[MAX_POINTERS];
for (jint j = 0; j < numPointers; j++) { for (jint j = 0; j < numPointers; j++) {
pointerCoords[j].x = *(currentDataSample++); samplePointerCoords[j].x = *(srcDataSamples++);
pointerCoords[j].y = *(currentDataSample++); samplePointerCoords[j].y = *(srcDataSamples++);
pointerCoords[j].pressure = *(currentDataSample++); samplePointerCoords[j].pressure = *(srcDataSamples++);
pointerCoords[j].size = *(currentDataSample++); samplePointerCoords[j].size = *(srcDataSamples++);
} }
event->initialize(deviceId, nature, action, edgeFlags, metaState, event->initialize(deviceId, nature, action, edgeFlags, metaState,
rawX, rawY, xPrecision, yPrecision, xOffset, yOffset, xPrecision, yPrecision, downTimeNano, sampleEventTime,
milliseconds_to_nanoseconds(downTime), eventTimeNano, numPointers, pointerIdentifiers, samplePointerCoords);
numPointers, pointerIdentifiers, pointerCoords);
while (numHistoricalSamples > 0) {
numHistoricalSamples -= 1;
if (numHistoricalSamples == 0) {
currentDataSample = dataSamples;
currentTimeSample = timeSamples;
}
nsecs_t sampleEventTime = milliseconds_to_nanoseconds(*(currentTimeSample++));
for (jint i = 1; i < numSamples; i++) {
sampleEventTime = *(srcEventTimeNanoSamples++);
for (jint j = 0; j < numPointers; j++) { for (jint j = 0; j < numPointers; j++) {
pointerCoords[j].x = *(currentDataSample++); samplePointerCoords[j].x = *(srcDataSamples++);
pointerCoords[j].y = *(currentDataSample++); samplePointerCoords[j].y = *(srcDataSamples++);
pointerCoords[j].pressure = *(currentDataSample++); samplePointerCoords[j].pressure = *(srcDataSamples++);
pointerCoords[j].size = *(currentDataSample++); samplePointerCoords[j].size = *(srcDataSamples++);
} }
event->addSample(sampleEventTime, samplePointerCoords);
event->addSample(sampleEventTime, pointerCoords);
} }
env->ReleasePrimitiveArrayCritical(pointerIdentifierArray, pointerIdentifiers, JNI_ABORT); env->ReleasePrimitiveArrayCritical(pointerIdentifierArray, pointerIdentifiers, JNI_ABORT);
env->ReleasePrimitiveArrayCritical(dataSampleArray, dataSamples, JNI_ABORT); env->ReleasePrimitiveArrayCritical(dataSampleArray, dataSamples, JNI_ABORT);
env->ReleasePrimitiveArrayCritical(timeSampleArray, timeSamples, JNI_ABORT); env->ReleasePrimitiveArrayCritical(eventTimeNanoSampleArray, eventTimeNanoSamples, JNI_ABORT);
env->DeleteLocalRef(pointerIdentifierArray); env->DeleteLocalRef(pointerIdentifierArray);
env->DeleteLocalRef(dataSampleArray); env->DeleteLocalRef(dataSampleArray);
env->DeleteLocalRef(timeSampleArray); env->DeleteLocalRef(eventTimeNanoSampleArray);
} }
void android_view_MotionEvent_recycle(JNIEnv* env, jobject eventObj) { void android_view_MotionEvent_recycle(JNIEnv* env, jobject eventObj) {
@ -273,16 +242,14 @@ int register_android_view_MotionEvent(JNIEnv* env) {
GET_METHOD_ID(gMotionEventClassInfo.recycle, gMotionEventClassInfo.clazz, GET_METHOD_ID(gMotionEventClassInfo.recycle, gMotionEventClassInfo.clazz,
"recycle", "()V"); "recycle", "()V");
GET_FIELD_ID(gMotionEventClassInfo.mDownTime, gMotionEventClassInfo.clazz, GET_FIELD_ID(gMotionEventClassInfo.mDownTimeNano, gMotionEventClassInfo.clazz,
"mDownTime", "J"); "mDownTimeNano", "J");
GET_FIELD_ID(gMotionEventClassInfo.mEventTimeNano, gMotionEventClassInfo.clazz,
"mEventTimeNano", "J");
GET_FIELD_ID(gMotionEventClassInfo.mAction, gMotionEventClassInfo.clazz, GET_FIELD_ID(gMotionEventClassInfo.mAction, gMotionEventClassInfo.clazz,
"mAction", "I"); "mAction", "I");
GET_FIELD_ID(gMotionEventClassInfo.mRawX, gMotionEventClassInfo.clazz, GET_FIELD_ID(gMotionEventClassInfo.mXOffset, gMotionEventClassInfo.clazz,
"mRawX", "F"); "mXOffset", "F");
GET_FIELD_ID(gMotionEventClassInfo.mRawY, gMotionEventClassInfo.clazz, GET_FIELD_ID(gMotionEventClassInfo.mYOffset, gMotionEventClassInfo.clazz,
"mRawY", "F"); "mYOffset", "F");
GET_FIELD_ID(gMotionEventClassInfo.mXPrecision, gMotionEventClassInfo.clazz, GET_FIELD_ID(gMotionEventClassInfo.mXPrecision, gMotionEventClassInfo.clazz,
"mXPrecision", "F"); "mXPrecision", "F");
GET_FIELD_ID(gMotionEventClassInfo.mYPrecision, gMotionEventClassInfo.clazz, GET_FIELD_ID(gMotionEventClassInfo.mYPrecision, gMotionEventClassInfo.clazz,
@ -301,8 +268,12 @@ int register_android_view_MotionEvent(JNIEnv* env) {
"mPointerIdentifiers", "[I"); "mPointerIdentifiers", "[I");
GET_FIELD_ID(gMotionEventClassInfo.mDataSamples, gMotionEventClassInfo.clazz, GET_FIELD_ID(gMotionEventClassInfo.mDataSamples, gMotionEventClassInfo.clazz,
"mDataSamples", "[F"); "mDataSamples", "[F");
GET_FIELD_ID(gMotionEventClassInfo.mTimeSamples, gMotionEventClassInfo.clazz, GET_FIELD_ID(gMotionEventClassInfo.mEventTimeNanoSamples, gMotionEventClassInfo.clazz,
"mTimeSamples", "[J"); "mEventTimeNanoSamples", "[J");
GET_FIELD_ID(gMotionEventClassInfo.mLastDataSampleIndex, gMotionEventClassInfo.clazz,
"mLastDataSampleIndex", "I");
GET_FIELD_ID(gMotionEventClassInfo.mLastEventTimeNanoSampleIndex, gMotionEventClassInfo.clazz,
"mLastEventTimeNanoSampleIndex", "I");
return 0; return 0;
} }

View File

@ -148,6 +148,9 @@ private:
int32_t mNature; int32_t mNature;
}; };
/*
* Key events.
*/
class KeyEvent : public InputEvent { class KeyEvent : public InputEvent {
public: public:
virtual ~KeyEvent() { } virtual ~KeyEvent() { }
@ -193,6 +196,9 @@ private:
nsecs_t mEventTime; nsecs_t mEventTime;
}; };
/*
* Motion events.
*/
class MotionEvent : public InputEvent { class MotionEvent : public InputEvent {
public: public:
virtual ~MotionEvent() { } virtual ~MotionEvent() { }
@ -205,6 +211,10 @@ public:
inline int32_t getMetaState() const { return mMetaState; } inline int32_t getMetaState() const { return mMetaState; }
inline float getXOffset() const { return mXOffset; }
inline float getYOffset() const { return mYOffset; }
inline float getXPrecision() const { return mXPrecision; } inline float getXPrecision() const { return mXPrecision; }
inline float getYPrecision() const { return mYPrecision; } inline float getYPrecision() const { return mYPrecision; }
@ -217,18 +227,22 @@ public:
inline nsecs_t getEventTime() const { return mSampleEventTimes[getHistorySize()]; } inline nsecs_t getEventTime() const { return mSampleEventTimes[getHistorySize()]; }
inline float getRawX() const { return mRawX; } inline float getRawX(size_t pointerIndex) const {
inline float getRawY() const { return mRawY; }
inline float getX(size_t pointerIndex) const {
return getCurrentPointerCoords(pointerIndex).x; return getCurrentPointerCoords(pointerIndex).x;
} }
inline float getY(size_t pointerIndex) const { inline float getRawY(size_t pointerIndex) const {
return getCurrentPointerCoords(pointerIndex).y; return getCurrentPointerCoords(pointerIndex).y;
} }
inline float getX(size_t pointerIndex) const {
return getRawX(pointerIndex) + mXOffset;
}
inline float getY(size_t pointerIndex) const {
return getRawY(pointerIndex) + mYOffset;
}
inline float getPressure(size_t pointerIndex) const { inline float getPressure(size_t pointerIndex) const {
return getCurrentPointerCoords(pointerIndex).pressure; return getCurrentPointerCoords(pointerIndex).pressure;
} }
@ -243,14 +257,22 @@ public:
return mSampleEventTimes[historicalIndex]; return mSampleEventTimes[historicalIndex];
} }
inline float getHistoricalX(size_t pointerIndex, size_t historicalIndex) const { inline float getHistoricalRawX(size_t pointerIndex, size_t historicalIndex) const {
return getHistoricalPointerCoords(pointerIndex, historicalIndex).x; return getHistoricalPointerCoords(pointerIndex, historicalIndex).x;
} }
inline float getHistoricalY(size_t pointerIndex, size_t historicalIndex) const { inline float getHistoricalRawY(size_t pointerIndex, size_t historicalIndex) const {
return getHistoricalPointerCoords(pointerIndex, historicalIndex).y; return getHistoricalPointerCoords(pointerIndex, historicalIndex).y;
} }
inline float getHistoricalX(size_t pointerIndex, size_t historicalIndex) const {
return getHistoricalRawX(pointerIndex, historicalIndex) + mXOffset;
}
inline float getHistoricalY(size_t pointerIndex, size_t historicalIndex) const {
return getHistoricalRawY(pointerIndex, historicalIndex) + mYOffset;
}
inline float getHistoricalPressure(size_t pointerIndex, size_t historicalIndex) const { inline float getHistoricalPressure(size_t pointerIndex, size_t historicalIndex) const {
return getHistoricalPointerCoords(pointerIndex, historicalIndex).pressure; return getHistoricalPointerCoords(pointerIndex, historicalIndex).pressure;
} }
@ -265,8 +287,8 @@ public:
int32_t action, int32_t action,
int32_t edgeFlags, int32_t edgeFlags,
int32_t metaState, int32_t metaState,
float rawX, float xOffset,
float rawY, float yOffset,
float xPrecision, float xPrecision,
float yPrecision, float yPrecision,
nsecs_t downTime, nsecs_t downTime,
@ -281,12 +303,19 @@ public:
void offsetLocation(float xOffset, float yOffset); void offsetLocation(float xOffset, float yOffset);
// Low-level accessors.
inline const int32_t* getPointerIds() const { return mPointerIds.array(); }
inline const nsecs_t* getSampleEventTimes() const { return mSampleEventTimes.array(); }
inline const PointerCoords* getSamplePointerCoords() const {
return mSamplePointerCoords.array();
}
private: private:
int32_t mAction; int32_t mAction;
int32_t mEdgeFlags; int32_t mEdgeFlags;
int32_t mMetaState; int32_t mMetaState;
float mRawX; float mXOffset;
float mRawY; float mYOffset;
float mXPrecision; float mXPrecision;
float mYPrecision; float mYPrecision;
nsecs_t mDownTime; nsecs_t mDownTime;

View File

@ -62,7 +62,7 @@ public:
* Returns OK on success. * Returns OK on success.
*/ */
static status_t openInputChannelPair(const String8& name, static status_t openInputChannelPair(const String8& name,
InputChannel** outServerChannel, InputChannel** outClientChannel); sp<InputChannel>& outServerChannel, sp<InputChannel>& outClientChannel);
inline String8 getName() const { return mName; } inline String8 getName() const { return mName; }
inline int32_t getAshmemFd() const { return mAshmemFd; } inline int32_t getAshmemFd() const { return mAshmemFd; }
@ -72,7 +72,8 @@ public:
/* Sends a signal to the other endpoint. /* Sends a signal to the other endpoint.
* *
* Returns OK on success. * Returns OK on success.
* Errors probably indicate that the channel is broken. * Returns DEAD_OBJECT if the channel's peer has been closed.
* Other errors probably indicate that the channel is broken.
*/ */
status_t sendSignal(char signal); status_t sendSignal(char signal);
@ -81,6 +82,7 @@ public:
* *
* Returns OK on success. * Returns OK on success.
* Returns WOULD_BLOCK if there is no signal present. * Returns WOULD_BLOCK if there is no signal present.
* Returns DEAD_OBJECT if the channel's peer has been closed.
* Other errors probably indicate that the channel is broken. * Other errors probably indicate that the channel is broken.
*/ */
status_t receiveSignal(char* outSignal); status_t receiveSignal(char* outSignal);
@ -298,7 +300,7 @@ public:
* Returns INVALID_OPERATION if there is no currently published event. * Returns INVALID_OPERATION if there is no currently published event.
* Returns NO_MEMORY if the event could not be created. * Returns NO_MEMORY if the event could not be created.
*/ */
status_t consume(InputEventFactoryInterface* factory, InputEvent** event); status_t consume(InputEventFactoryInterface* factory, InputEvent** outEvent);
/* Sends a finished signal to the publisher to inform it that the current message is /* Sends a finished signal to the publisher to inform it that the current message is
* finished processing. * finished processing.

View File

@ -114,8 +114,10 @@ private:
}; };
Mutex mLock; Mutex mLock;
Condition mAwake;
bool mPolling; bool mPolling;
uint32_t mWaiters;
Condition mAwake;
Condition mResume;
int mWakeReadPipeFd; int mWakeReadPipeFd;
int mWakeWritePipeFd; int mWakeWritePipeFd;

View File

@ -115,10 +115,10 @@ public:
//! insert an array at a given index //! insert an array at a given index
ssize_t insertArrayAt(const TYPE* array, size_t index, size_t numItems); ssize_t insertArrayAt(const TYPE* array, size_t index, size_t length);
//! append an array at the end of this vector //! append an array at the end of this vector
ssize_t appendArray(const TYPE* array, size_t numItems); ssize_t appendArray(const TYPE* array, size_t length);
/*! /*!
* add/insert/replace items * add/insert/replace items
@ -126,7 +126,7 @@ public:
//! insert one or several items initialized with their default constructor //! insert one or several items initialized with their default constructor
inline ssize_t insertAt(size_t index, size_t numItems = 1); inline ssize_t insertAt(size_t index, size_t numItems = 1);
//! insert on onr several items initialized from a prototype item //! insert one or several items initialized from a prototype item
ssize_t insertAt(const TYPE& prototype_item, size_t index, size_t numItems = 1); ssize_t insertAt(const TYPE& prototype_item, size_t index, size_t numItems = 1);
//! pop the top of the stack (removes the last element). No-op if the stack's empty //! pop the top of the stack (removes the last element). No-op if the stack's empty
inline void pop(); inline void pop();
@ -265,13 +265,13 @@ ssize_t Vector<TYPE>::appendVector(const Vector<TYPE>& vector) {
} }
template<class TYPE> inline template<class TYPE> inline
ssize_t Vector<TYPE>::insertArrayAt(const TYPE* array, size_t index, size_t numItems) { ssize_t Vector<TYPE>::insertArrayAt(const TYPE* array, size_t index, size_t length) {
return VectorImpl::insertAt(array, index, numItems); return VectorImpl::insertArrayAt(array, index, length);
} }
template<class TYPE> inline template<class TYPE> inline
ssize_t Vector<TYPE>::appendArray(const TYPE* array, size_t numItems) { ssize_t Vector<TYPE>::appendArray(const TYPE* array, size_t length) {
return VectorImpl::add(array, numItems); return VectorImpl::appendArray(array, length);
} }
template<class TYPE> inline template<class TYPE> inline

View File

@ -65,9 +65,11 @@ public:
size_t capacity() const; size_t capacity() const;
ssize_t setCapacity(size_t size); ssize_t setCapacity(size_t size);
/*! append/insert another vector */ /*! append/insert another vector or array */
ssize_t insertVectorAt(const VectorImpl& vector, size_t index); ssize_t insertVectorAt(const VectorImpl& vector, size_t index);
ssize_t appendVector(const VectorImpl& vector); ssize_t appendVector(const VectorImpl& vector);
ssize_t insertArrayAt(const void* array, size_t index, size_t length);
ssize_t appendArray(const void* array, size_t length);
/*! add/insert/replace items */ /*! add/insert/replace items */
ssize_t insertAt(size_t where, size_t numItems = 1); ssize_t insertAt(size_t where, size_t numItems = 1);
@ -76,7 +78,7 @@ public:
void push(); void push();
void push(const void* item); void push(const void* item);
ssize_t add(); ssize_t add();
ssize_t add(const void* item, size_t numItems = 1); ssize_t add(const void* item);
ssize_t replaceAt(size_t index); ssize_t replaceAt(size_t index);
ssize_t replaceAt(const void* item, size_t index); ssize_t replaceAt(const void* item, size_t index);
@ -184,8 +186,8 @@ private:
void push(const void* item); void push(const void* item);
ssize_t insertVectorAt(const VectorImpl& vector, size_t index); ssize_t insertVectorAt(const VectorImpl& vector, size_t index);
ssize_t appendVector(const VectorImpl& vector); ssize_t appendVector(const VectorImpl& vector);
ssize_t insertArrayAt(const void* array, size_t index, size_t numItems); ssize_t insertArrayAt(const void* array, size_t index, size_t length);
ssize_t appendArray(const void* array, size_t numItems); ssize_t appendArray(const void* array, size_t length);
ssize_t insertAt(size_t where, size_t numItems = 1); ssize_t insertAt(size_t where, size_t numItems = 1);
ssize_t insertAt(const void* item, size_t where, size_t numItems = 1); ssize_t insertAt(const void* item, size_t where, size_t numItems = 1);
ssize_t replaceAt(size_t index); ssize_t replaceAt(size_t index);

View File

@ -50,8 +50,8 @@ void MotionEvent::initialize(
int32_t action, int32_t action,
int32_t edgeFlags, int32_t edgeFlags,
int32_t metaState, int32_t metaState,
float rawX, float xOffset,
float rawY, float yOffset,
float xPrecision, float xPrecision,
float yPrecision, float yPrecision,
nsecs_t downTime, nsecs_t downTime,
@ -63,8 +63,8 @@ void MotionEvent::initialize(
mAction = action; mAction = action;
mEdgeFlags = edgeFlags; mEdgeFlags = edgeFlags;
mMetaState = metaState; mMetaState = metaState;
mRawX = rawX; mXOffset = xOffset;
mRawY = rawY; mYOffset = yOffset;
mXPrecision = xPrecision; mXPrecision = xPrecision;
mYPrecision = yPrecision; mYPrecision = yPrecision;
mDownTime = downTime; mDownTime = downTime;
@ -83,13 +83,8 @@ void MotionEvent::addSample(
} }
void MotionEvent::offsetLocation(float xOffset, float yOffset) { void MotionEvent::offsetLocation(float xOffset, float yOffset) {
if (xOffset != 0 || yOffset != 0) { mXOffset += xOffset;
for (size_t i = 0; i < mSamplePointerCoords.size(); i++) { mYOffset += yOffset;
PointerCoords& pointerCoords = mSamplePointerCoords.editItemAt(i);
pointerCoords.x += xOffset;
pointerCoords.y += yOffset;
}
}
} }
} // namespace android } // namespace android
@ -163,6 +158,14 @@ int64_t motion_event_get_event_time(const input_event_t* motion_event) {
return reinterpret_cast<const MotionEvent*>(motion_event)->getEventTime(); return reinterpret_cast<const MotionEvent*>(motion_event)->getEventTime();
} }
float motion_event_get_x_offset(const input_event_t* motion_event) {
return reinterpret_cast<const MotionEvent*>(motion_event)->getXOffset();
}
float motion_event_get_y_offset(const input_event_t* motion_event) {
return reinterpret_cast<const MotionEvent*>(motion_event)->getYOffset();
}
float motion_event_get_x_precision(const input_event_t* motion_event) { float motion_event_get_x_precision(const input_event_t* motion_event) {
return reinterpret_cast<const MotionEvent*>(motion_event)->getXPrecision(); return reinterpret_cast<const MotionEvent*>(motion_event)->getXPrecision();
} }
@ -179,12 +182,12 @@ int32_t motion_event_get_pointer_id(const input_event_t* motion_event, size_t po
return reinterpret_cast<const MotionEvent*>(motion_event)->getPointerId(pointer_index); return reinterpret_cast<const MotionEvent*>(motion_event)->getPointerId(pointer_index);
} }
float motion_event_get_raw_x(const input_event_t* motion_event) { float motion_event_get_raw_x(const input_event_t* motion_event, size_t pointer_index) {
return reinterpret_cast<const MotionEvent*>(motion_event)->getRawX(); return reinterpret_cast<const MotionEvent*>(motion_event)->getRawX(pointer_index);
} }
float motion_event_get_raw_y(const input_event_t* motion_event) { float motion_event_get_raw_y(const input_event_t* motion_event, size_t pointer_index) {
return reinterpret_cast<const MotionEvent*>(motion_event)->getRawY(); return reinterpret_cast<const MotionEvent*>(motion_event)->getRawY(pointer_index);
} }
float motion_event_get_x(const input_event_t* motion_event, size_t pointer_index) { float motion_event_get_x(const input_event_t* motion_event, size_t pointer_index) {
@ -213,6 +216,18 @@ int64_t motion_event_get_historical_event_time(input_event_t* motion_event,
history_index); history_index);
} }
float motion_event_get_historical_raw_x(input_event_t* motion_event, size_t pointer_index,
size_t history_index) {
return reinterpret_cast<const MotionEvent*>(motion_event)->getHistoricalRawX(
pointer_index, history_index);
}
float motion_event_get_historical_raw_y(input_event_t* motion_event, size_t pointer_index,
size_t history_index) {
return reinterpret_cast<const MotionEvent*>(motion_event)->getHistoricalRawY(
pointer_index, history_index);
}
float motion_event_get_historical_x(input_event_t* motion_event, size_t pointer_index, float motion_event_get_historical_x(input_event_t* motion_event, size_t pointer_index,
size_t history_index) { size_t history_index) {
return reinterpret_cast<const MotionEvent*>(motion_event)->getHistoricalX( return reinterpret_cast<const MotionEvent*>(motion_event)->getHistoricalX(

View File

@ -379,8 +379,7 @@ void InputDispatcher::identifyInputTargetsAndDispatchMotionLockedInterruptible(
mReusableMotionEvent.initialize(entry->deviceId, entry->nature, entry->action, mReusableMotionEvent.initialize(entry->deviceId, entry->nature, entry->action,
entry->edgeFlags, entry->metaState, entry->edgeFlags, entry->metaState,
entry->firstSample.pointerCoords[0].x, entry->firstSample.pointerCoords[0].y, 0, 0, entry->xPrecision, entry->yPrecision,
entry->xPrecision, entry->yPrecision,
entry->downTime, entry->eventTime, entry->pointerCount, entry->pointerIds, entry->downTime, entry->eventTime, entry->pointerCount, entry->pointerIds,
entry->firstSample.pointerCoords); entry->firstSample.pointerCoords);

View File

@ -19,6 +19,9 @@
// Log debug messages about pointers. // Log debug messages about pointers.
#define DEBUG_POINTERS 1 #define DEBUG_POINTERS 1
// Log debug messages about pointer assignment calculations.
#define DEBUG_POINTER_ASSIGNMENT 0
#include <cutils/log.h> #include <cutils/log.h>
#include <ui/InputReader.h> #include <ui/InputReader.h>
@ -57,6 +60,14 @@ inline static T min(const T& a, const T& b) {
return a < b ? a : b; return a < b ? a : b;
} }
template<typename T>
inline static void swap(T& a, T& b) {
T temp = a;
a = b;
b = temp;
}
int32_t updateMetaState(int32_t keyCode, bool down, int32_t oldMetaState) { int32_t updateMetaState(int32_t keyCode, bool down, int32_t oldMetaState) {
int32_t mask; int32_t mask;
switch (keyCode) { switch (keyCode) {
@ -188,6 +199,12 @@ void InputDevice::TouchScreenState::reset() {
jumpyTouchFilter.jumpyPointsDropped = 0; jumpyTouchFilter.jumpyPointsDropped = 0;
} }
struct PointerDistanceHeapElement {
uint32_t currentPointerIndex : 8;
uint32_t lastPointerIndex : 8;
uint64_t distance : 48; // squared distance
};
void InputDevice::TouchScreenState::calculatePointerIds() { void InputDevice::TouchScreenState::calculatePointerIds() {
uint32_t currentPointerCount = currentTouch.pointerCount; uint32_t currentPointerCount = currentTouch.pointerCount;
uint32_t lastPointerCount = lastTouch.pointerCount; uint32_t lastPointerCount = lastTouch.pointerCount;
@ -214,11 +231,7 @@ void InputDevice::TouchScreenState::calculatePointerIds() {
// We build a heap of squared euclidean distances between current and last pointers // We build a heap of squared euclidean distances between current and last pointers
// associated with the current and last pointer indices. Then, we find the best // associated with the current and last pointer indices. Then, we find the best
// match (by distance) for each current pointer. // match (by distance) for each current pointer.
struct { PointerDistanceHeapElement heap[MAX_POINTERS * MAX_POINTERS];
uint32_t currentPointerIndex : 8;
uint32_t lastPointerIndex : 8;
uint64_t distance : 48; // squared distance
} heap[MAX_POINTERS * MAX_POINTERS];
uint32_t heapSize = 0; uint32_t heapSize = 0;
for (uint32_t currentPointerIndex = 0; currentPointerIndex < currentPointerCount; for (uint32_t currentPointerIndex = 0; currentPointerIndex < currentPointerCount;
@ -233,23 +246,45 @@ void InputDevice::TouchScreenState::calculatePointerIds() {
uint64_t distance = uint64_t(deltaX * deltaX + deltaY * deltaY); uint64_t distance = uint64_t(deltaX * deltaX + deltaY * deltaY);
// Insert new element into the heap (sift up). // Insert new element into the heap (sift up).
heap[heapSize].currentPointerIndex = currentPointerIndex;
heap[heapSize].lastPointerIndex = lastPointerIndex;
heap[heapSize].distance = distance;
heapSize += 1; heapSize += 1;
uint32_t insertionIndex = heapSize; }
while (insertionIndex > 1) { }
uint32_t parentIndex = (insertionIndex - 1) / 2;
if (distance < heap[parentIndex].distance) { // Heapify
heap[insertionIndex] = heap[parentIndex]; for (uint32_t startIndex = heapSize / 2; startIndex != 0; ) {
insertionIndex = parentIndex; startIndex -= 1;
} else { for (uint32_t parentIndex = startIndex; ;) {
uint32_t childIndex = parentIndex * 2 + 1;
if (childIndex >= heapSize) {
break; break;
} }
if (childIndex + 1 < heapSize
&& heap[childIndex + 1].distance < heap[childIndex].distance) {
childIndex += 1;
} }
heap[insertionIndex].currentPointerIndex = currentPointerIndex;
heap[insertionIndex].lastPointerIndex = lastPointerIndex; if (heap[parentIndex].distance <= heap[childIndex].distance) {
heap[insertionIndex].distance = distance; break;
}
swap(heap[parentIndex], heap[childIndex]);
parentIndex = childIndex;
} }
} }
#if DEBUG_POINTER_ASSIGNMENT
LOGD("calculatePointerIds - initial distance min-heap: size=%d", heapSize);
for (size_t i = 0; i < heapSize; i++) {
LOGD(" heap[%d]: cur=%d, last=%d, distance=%lld",
i, heap[i].currentPointerIndex, heap[i].lastPointerIndex,
heap[i].distance);
}
#endif
// Pull matches out by increasing order of distance. // Pull matches out by increasing order of distance.
// To avoid reassigning pointers that have already been matched, the loop keeps track // To avoid reassigning pointers that have already been matched, the loop keeps track
// of which last and current pointers have been matched using the matchedXXXBits variables. // of which last and current pointers have been matched using the matchedXXXBits variables.
@ -262,7 +297,7 @@ void InputDevice::TouchScreenState::calculatePointerIds() {
for (;;) { for (;;) {
if (first) { if (first) {
// The first time through the loop, we just consume the root element of // The first time through the loop, we just consume the root element of
// the heap (the one with smalled distance). // the heap (the one with smallest distance).
first = false; first = false;
} else { } else {
// Previous iterations consumed the root element of the heap. // Previous iterations consumed the root element of the heap.
@ -270,10 +305,10 @@ void InputDevice::TouchScreenState::calculatePointerIds() {
heapSize -= 1; heapSize -= 1;
assert(heapSize > 0); assert(heapSize > 0);
// Sift down to find where the element at index heapSize needs to be moved. // Sift down.
uint32_t rootIndex = 0; heap[0] = heap[heapSize];
for (;;) { for (uint32_t parentIndex = 0; ;) {
uint32_t childIndex = rootIndex * 2 + 1; uint32_t childIndex = parentIndex * 2 + 1;
if (childIndex >= heapSize) { if (childIndex >= heapSize) {
break; break;
} }
@ -283,14 +318,22 @@ void InputDevice::TouchScreenState::calculatePointerIds() {
childIndex += 1; childIndex += 1;
} }
if (heap[heapSize].distance < heap[childIndex].distance) { if (heap[parentIndex].distance <= heap[childIndex].distance) {
break; break;
} }
heap[rootIndex] = heap[childIndex]; swap(heap[parentIndex], heap[childIndex]);
rootIndex = childIndex; parentIndex = childIndex;
} }
heap[rootIndex] = heap[heapSize];
#if DEBUG_POINTER_ASSIGNMENT
LOGD("calculatePointerIds - reduced distance min-heap: size=%d", heapSize);
for (size_t i = 0; i < heapSize; i++) {
LOGD(" heap[%d]: cur=%d, last=%d, distance=%lld",
i, heap[i].currentPointerIndex, heap[i].lastPointerIndex,
heap[i].distance);
}
#endif
} }
uint32_t currentPointerIndex = heap[0].currentPointerIndex; uint32_t currentPointerIndex = heap[0].currentPointerIndex;
@ -306,6 +349,11 @@ void InputDevice::TouchScreenState::calculatePointerIds() {
currentTouch.pointers[currentPointerIndex].id = id; currentTouch.pointers[currentPointerIndex].id = id;
currentTouch.idToIndex[id] = currentPointerIndex; currentTouch.idToIndex[id] = currentPointerIndex;
usedIdBits.markBit(id); usedIdBits.markBit(id);
#if DEBUG_POINTER_ASSIGNMENT
LOGD("calculatePointerIds - matched: cur=%d, last=%d, id=%d, distance=%lld",
lastPointerIndex, currentPointerIndex, id, heap[0].distance);
#endif
break; break;
} }
} }
@ -320,6 +368,11 @@ void InputDevice::TouchScreenState::calculatePointerIds() {
currentTouch.idToIndex[id] = currentPointerIndex; currentTouch.idToIndex[id] = currentPointerIndex;
usedIdBits.markBit(id); usedIdBits.markBit(id);
#if DEBUG_POINTER_ASSIGNMENT
LOGD("calculatePointerIds - assigned: cur=%d, id=%d",
currentPointerIndex, id);
#endif
if (--i == 0) break; // done if (--i == 0) break; // done
matchedCurrentBits.markBit(currentPointerIndex); matchedCurrentBits.markBit(currentPointerIndex);
} }
@ -1208,8 +1261,10 @@ bool InputReader::consumeVirtualKeyTouches(nsecs_t when,
int32_t x = device->touchScreen.currentTouch.pointers[0].x; int32_t x = device->touchScreen.currentTouch.pointers[0].x;
int32_t y = device->touchScreen.currentTouch.pointers[0].y; int32_t y = device->touchScreen.currentTouch.pointers[0].y;
if (device->touchScreen.isPointInsideDisplay(x, y)) { if (device->touchScreen.isPointInsideDisplay(x, y)
// Pointer moved inside the display area. Send key cancellation. || device->touchScreen.currentTouch.pointerCount != 1) {
// Pointer moved inside the display area or another pointer also went down.
// Send key cancellation.
device->touchScreen.currentVirtualKey.down = false; device->touchScreen.currentVirtualKey.down = false;
#if DEBUG_VIRTUAL_KEYS #if DEBUG_VIRTUAL_KEYS
@ -1227,7 +1282,7 @@ bool InputReader::consumeVirtualKeyTouches(nsecs_t when,
device->touchScreen.lastTouch.clear(); device->touchScreen.lastTouch.clear();
return false; // not consumed return false; // not consumed
} }
} else if (device->touchScreen.currentTouch.pointerCount > 0 } else if (device->touchScreen.currentTouch.pointerCount == 1
&& device->touchScreen.lastTouch.pointerCount == 0) { && device->touchScreen.lastTouch.pointerCount == 0) {
int32_t x = device->touchScreen.currentTouch.pointers[0].x; int32_t x = device->touchScreen.currentTouch.pointers[0].x;
int32_t y = device->touchScreen.currentTouch.pointers[0].y; int32_t y = device->touchScreen.currentTouch.pointers[0].y;

View File

@ -8,13 +8,13 @@
//#define LOG_NDEBUG 0 //#define LOG_NDEBUG 0
// Log debug messages about channel signalling (send signal, receive signal) // Log debug messages about channel signalling (send signal, receive signal)
#define DEBUG_CHANNEL_SIGNALS 1 #define DEBUG_CHANNEL_SIGNALS 0
// Log debug messages whenever InputChannel objects are created/destroyed // Log debug messages whenever InputChannel objects are created/destroyed
#define DEBUG_CHANNEL_LIFECYCLE 1 #define DEBUG_CHANNEL_LIFECYCLE 0
// Log debug messages about transport actions (initialize, reset, publish, ...) // Log debug messages about transport actions (initialize, reset, publish, ...)
#define DEBUG_TRANSPORT_ACTIONS 1 #define DEBUG_TRANSPORT_ACTIONS 0
#include <cutils/ashmem.h> #include <cutils/ashmem.h>
@ -70,7 +70,7 @@ InputChannel::~InputChannel() {
} }
status_t InputChannel::openInputChannelPair(const String8& name, status_t InputChannel::openInputChannelPair(const String8& name,
InputChannel** outServerChannel, InputChannel** outClientChannel) { sp<InputChannel>& outServerChannel, sp<InputChannel>& outClientChannel) {
status_t result; status_t result;
int serverAshmemFd = ashmem_create_region(name.string(), DEFAULT_MESSAGE_BUFFER_SIZE); int serverAshmemFd = ashmem_create_region(name.string(), DEFAULT_MESSAGE_BUFFER_SIZE);
@ -107,12 +107,12 @@ status_t InputChannel::openInputChannelPair(const String8& name,
} else { } else {
String8 serverChannelName = name; String8 serverChannelName = name;
serverChannelName.append(" (server)"); serverChannelName.append(" (server)");
*outServerChannel = new InputChannel(serverChannelName, outServerChannel = new InputChannel(serverChannelName,
serverAshmemFd, reverse[0], forward[1]); serverAshmemFd, reverse[0], forward[1]);
String8 clientChannelName = name; String8 clientChannelName = name;
clientChannelName.append(" (client)"); clientChannelName.append(" (client)");
*outClientChannel = new InputChannel(clientChannelName, outClientChannel = new InputChannel(clientChannelName,
clientAshmemFd, forward[0], reverse[1]); clientAshmemFd, forward[0], reverse[1]);
return OK; return OK;
} }
@ -125,8 +125,8 @@ status_t InputChannel::openInputChannelPair(const String8& name,
::close(serverAshmemFd); ::close(serverAshmemFd);
} }
*outServerChannel = NULL; outServerChannel.clear();
*outClientChannel = NULL; outClientChannel.clear();
return result; return result;
} }
@ -155,6 +155,13 @@ status_t InputChannel::receiveSignal(char* outSignal) {
return OK; return OK;
} }
if (nRead == 0) { // check for EOF
#if DEBUG_CHANNEL_SIGNALS
LOGD("channel '%s' ~ receive signal failed because peer was closed", mName.string());
#endif
return DEAD_OBJECT;
}
if (errno == EAGAIN) { if (errno == EAGAIN) {
#if DEBUG_CHANNEL_SIGNALS #if DEBUG_CHANNEL_SIGNALS
LOGD("channel '%s' ~ receive signal failed because no signal available", mName.string()); LOGD("channel '%s' ~ receive signal failed because no signal available", mName.string());
@ -535,13 +542,13 @@ status_t InputConsumer::initialize() {
return OK; return OK;
} }
status_t InputConsumer::consume(InputEventFactoryInterface* factory, InputEvent** event) { status_t InputConsumer::consume(InputEventFactoryInterface* factory, InputEvent** outEvent) {
#if DEBUG_TRANSPORT_ACTIONS #if DEBUG_TRANSPORT_ACTIONS
LOGD("channel '%s' consumer ~ consume", LOGD("channel '%s' consumer ~ consume",
mChannel->getName().string()); mChannel->getName().string());
#endif #endif
*event = NULL; *outEvent = NULL;
int ashmemFd = mChannel->getAshmemFd(); int ashmemFd = mChannel->getAshmemFd();
int result = ashmem_pin_region(ashmemFd, 0, 0); int result = ashmem_pin_region(ashmemFd, 0, 0);
@ -583,7 +590,7 @@ status_t InputConsumer::consume(InputEventFactoryInterface* factory, InputEvent*
populateKeyEvent(keyEvent); populateKeyEvent(keyEvent);
*event = keyEvent; *outEvent = keyEvent;
break; break;
} }
@ -593,7 +600,7 @@ status_t InputConsumer::consume(InputEventFactoryInterface* factory, InputEvent*
populateMotionEvent(motionEvent); populateMotionEvent(motionEvent);
*event = motionEvent; *outEvent = motionEvent;
break; break;
} }
@ -655,8 +662,8 @@ void InputConsumer::populateMotionEvent(MotionEvent* motionEvent) const {
mSharedMessage->motion.action, mSharedMessage->motion.action,
mSharedMessage->motion.edgeFlags, mSharedMessage->motion.edgeFlags,
mSharedMessage->motion.metaState, mSharedMessage->motion.metaState,
mSharedMessage->motion.sampleData[0].coords[0].x, mSharedMessage->motion.xOffset,
mSharedMessage->motion.sampleData[0].coords[0].y, mSharedMessage->motion.yOffset,
mSharedMessage->motion.xPrecision, mSharedMessage->motion.xPrecision,
mSharedMessage->motion.yPrecision, mSharedMessage->motion.yPrecision,
mSharedMessage->motion.downTime, mSharedMessage->motion.downTime,
@ -676,9 +683,6 @@ void InputConsumer::populateMotionEvent(MotionEvent* motionEvent) const {
motionEvent->addSample(sampleData->eventTime, sampleData->coords); motionEvent->addSample(sampleData->eventTime, sampleData->coords);
} }
} }
motionEvent->offsetLocation(mSharedMessage->motion.xOffset,
mSharedMessage->motion.yOffset);
} }
} // namespace android } // namespace android

View File

@ -3,7 +3,9 @@ LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS) include $(CLEAR_VARS)
test_src_files := \ test_src_files := \
InputDispatcher_test.cpp InputChannel_test.cpp \
InputDispatcher_test.cpp \
InputPublisherAndConsumer_test.cpp
shared_libraries := \ shared_libraries := \
libcutils \ libcutils \

View File

@ -0,0 +1,158 @@
//
// Copyright 2010 The Android Open Source Project
//
#include <ui/InputTransport.h>
#include <utils/Timers.h>
#include <utils/StopWatch.h>
#include <gtest/gtest.h>
#include <unistd.h>
#include <time.h>
#include <sys/mman.h>
#include <cutils/ashmem.h>
#include "../../utils/tests/TestHelpers.h"
namespace android {
class InputChannelTest : public testing::Test {
protected:
virtual void SetUp() { }
virtual void TearDown() { }
};
TEST_F(InputChannelTest, ConstructorAndDestructor_TakesOwnershipOfFileDescriptors) {
// Our purpose here is to verify that the input channel destructor closes the
// file descriptors provided to it. One easy way is to provide it with one end
// of a pipe and to check for EPIPE on the other end after the channel is destroyed.
Pipe fakeAshmem, sendPipe, receivePipe;
sp<InputChannel> inputChannel = new InputChannel(String8("channel name"),
fakeAshmem.sendFd, receivePipe.receiveFd, sendPipe.sendFd);
EXPECT_STREQ("channel name", inputChannel->getName().string())
<< "channel should have provided name";
EXPECT_EQ(fakeAshmem.sendFd, inputChannel->getAshmemFd())
<< "channel should have provided ashmem fd";
EXPECT_EQ(receivePipe.receiveFd, inputChannel->getReceivePipeFd())
<< "channel should have provided receive pipe fd";
EXPECT_EQ(sendPipe.sendFd, inputChannel->getSendPipeFd())
<< "channel should have provided send pipe fd";
inputChannel.clear(); // destroys input channel
EXPECT_EQ(-EPIPE, fakeAshmem.readSignal())
<< "channel should have closed ashmem fd when destroyed";
EXPECT_EQ(-EPIPE, receivePipe.writeSignal())
<< "channel should have closed receive pipe fd when destroyed";
EXPECT_EQ(-EPIPE, sendPipe.readSignal())
<< "channel should have closed send pipe fd when destroyed";
// clean up fds of Pipe endpoints that were closed so we don't try to close them again
fakeAshmem.sendFd = -1;
receivePipe.receiveFd = -1;
sendPipe.sendFd = -1;
}
TEST_F(InputChannelTest, OpenInputChannelPair_ReturnsAPairOfConnectedChannels) {
sp<InputChannel> serverChannel, clientChannel;
status_t result = InputChannel::openInputChannelPair(String8("channel name"),
serverChannel, clientChannel);
ASSERT_EQ(OK, result)
<< "should have successfully opened a channel pair";
// Name
EXPECT_STREQ("channel name (server)", serverChannel->getName().string())
<< "server channel should have suffixed name";
EXPECT_STREQ("channel name (client)", clientChannel->getName().string())
<< "client channel should have suffixed name";
// Ashmem uniqueness
EXPECT_NE(serverChannel->getAshmemFd(), clientChannel->getAshmemFd())
<< "server and client channel should have different ashmem fds because it was dup'd";
// Ashmem usability
ssize_t serverAshmemSize = ashmem_get_size_region(serverChannel->getAshmemFd());
ssize_t clientAshmemSize = ashmem_get_size_region(clientChannel->getAshmemFd());
uint32_t* serverAshmem = static_cast<uint32_t*>(mmap(NULL, serverAshmemSize,
PROT_READ | PROT_WRITE, MAP_SHARED, serverChannel->getAshmemFd(), 0));
uint32_t* clientAshmem = static_cast<uint32_t*>(mmap(NULL, clientAshmemSize,
PROT_READ | PROT_WRITE, MAP_SHARED, clientChannel->getAshmemFd(), 0));
ASSERT_TRUE(serverAshmem != NULL)
<< "server channel ashmem should be mappable";
ASSERT_TRUE(clientAshmem != NULL)
<< "client channel ashmem should be mappable";
*serverAshmem = 0xf00dd00d;
EXPECT_EQ(0xf00dd00d, *clientAshmem)
<< "ashmem buffer should be shared by client and server";
munmap(serverAshmem, serverAshmemSize);
munmap(clientAshmem, clientAshmemSize);
// Server->Client communication
EXPECT_EQ(OK, serverChannel->sendSignal('S'))
<< "server channel should be able to send signal to client channel";
char signal;
EXPECT_EQ(OK, clientChannel->receiveSignal(& signal))
<< "client channel should be able to receive signal from server channel";
EXPECT_EQ('S', signal)
<< "client channel should receive the correct signal from server channel";
// Client->Server communication
EXPECT_EQ(OK, clientChannel->sendSignal('c'))
<< "client channel should be able to send signal to server channel";
EXPECT_EQ(OK, serverChannel->receiveSignal(& signal))
<< "server channel should be able to receive signal from client channel";
EXPECT_EQ('c', signal)
<< "server channel should receive the correct signal from client channel";
}
TEST_F(InputChannelTest, ReceiveSignal_WhenNoSignalPresent_ReturnsAnError) {
sp<InputChannel> serverChannel, clientChannel;
status_t result = InputChannel::openInputChannelPair(String8("channel name"),
serverChannel, clientChannel);
ASSERT_EQ(OK, result)
<< "should have successfully opened a channel pair";
char signal;
EXPECT_EQ(WOULD_BLOCK, clientChannel->receiveSignal(& signal))
<< "receiveSignal should have returned WOULD_BLOCK";
}
TEST_F(InputChannelTest, ReceiveSignal_WhenPeerClosed_ReturnsAnError) {
sp<InputChannel> serverChannel, clientChannel;
status_t result = InputChannel::openInputChannelPair(String8("channel name"),
serverChannel, clientChannel);
ASSERT_EQ(OK, result)
<< "should have successfully opened a channel pair";
serverChannel.clear(); // close server channel
char signal;
EXPECT_EQ(DEAD_OBJECT, clientChannel->receiveSignal(& signal))
<< "receiveSignal should have returned DEAD_OBJECT";
}
TEST_F(InputChannelTest, SendSignal_WhenPeerClosed_ReturnsAnError) {
sp<InputChannel> serverChannel, clientChannel;
status_t result = InputChannel::openInputChannelPair(String8("channel name"),
serverChannel, clientChannel);
ASSERT_EQ(OK, result)
<< "should have successfully opened a channel pair";
serverChannel.clear(); // close server channel
EXPECT_EQ(DEAD_OBJECT, clientChannel->sendSignal('S'))
<< "sendSignal should have returned DEAD_OBJECT";
}
} // namespace android

View File

@ -12,8 +12,7 @@ public:
}; };
TEST_F(InputDispatcherTest, Dummy) { TEST_F(InputDispatcherTest, Dummy) {
SCOPED_TRACE("Trace"); // TODO
ASSERT_FALSE(true);
} }
} // namespace android } // namespace android

View File

@ -0,0 +1,449 @@
//
// Copyright 2010 The Android Open Source Project
//
#include <ui/InputTransport.h>
#include <utils/Timers.h>
#include <utils/StopWatch.h>
#include <gtest/gtest.h>
#include <unistd.h>
#include <time.h>
#include <sys/mman.h>
#include <cutils/ashmem.h>
#include "../../utils/tests/TestHelpers.h"
namespace android {
class InputPublisherAndConsumerTest : public testing::Test {
protected:
sp<InputChannel> serverChannel, clientChannel;
InputPublisher* mPublisher;
InputConsumer* mConsumer;
PreallocatedInputEventFactory mEventFactory;
virtual void SetUp() {
status_t result = InputChannel::openInputChannelPair(String8("channel name"),
serverChannel, clientChannel);
mPublisher = new InputPublisher(serverChannel);
mConsumer = new InputConsumer(clientChannel);
}
virtual void TearDown() {
if (mPublisher) {
delete mPublisher;
mPublisher = NULL;
}
if (mConsumer) {
delete mConsumer;
mConsumer = NULL;
}
serverChannel.clear();
clientChannel.clear();
}
void Initialize();
void PublishAndConsumeKeyEvent();
void PublishAndConsumeMotionEvent(
size_t samplesToAppendBeforeDispatch = 0,
size_t samplesToAppendAfterDispatch = 0);
};
TEST_F(InputPublisherAndConsumerTest, GetChannel_ReturnsTheChannel) {
EXPECT_EQ(serverChannel.get(), mPublisher->getChannel().get());
EXPECT_EQ(clientChannel.get(), mConsumer->getChannel().get());
}
void InputPublisherAndConsumerTest::Initialize() {
status_t status;
status = mPublisher->initialize();
ASSERT_EQ(OK, status)
<< "publisher initialize should return OK";
status = mConsumer->initialize();
ASSERT_EQ(OK, status)
<< "consumer initialize should return OK";
}
void InputPublisherAndConsumerTest::PublishAndConsumeKeyEvent() {
status_t status;
const int32_t deviceId = 1;
const int32_t nature = INPUT_EVENT_NATURE_KEY;
const int32_t action = KEY_EVENT_ACTION_DOWN;
const int32_t flags = KEY_EVENT_FLAG_FROM_SYSTEM;
const int32_t keyCode = KEYCODE_ENTER;
const int32_t scanCode = 13;
const int32_t metaState = META_ALT_LEFT_ON | META_ALT_ON;
const int32_t repeatCount = 1;
const nsecs_t downTime = 3;
const nsecs_t eventTime = 4;
status = mPublisher->publishKeyEvent(deviceId, nature, action, flags,
keyCode, scanCode, metaState, repeatCount, downTime, eventTime);
ASSERT_EQ(OK, status)
<< "publisher publishKeyEvent should return OK";
status = mPublisher->sendDispatchSignal();
ASSERT_EQ(OK, status)
<< "publisher sendDispatchSignal should return OK";
status = mConsumer->receiveDispatchSignal();
ASSERT_EQ(OK, status)
<< "consumer receiveDispatchSignal should return OK";
InputEvent* event;
status = mConsumer->consume(& mEventFactory, & event);
ASSERT_EQ(OK, status)
<< "consumer consume should return OK";
ASSERT_TRUE(event != NULL)
<< "consumer should have returned non-NULL event";
ASSERT_EQ(INPUT_EVENT_TYPE_KEY, event->getType())
<< "consumer should have returned a key event";
KeyEvent* keyEvent = static_cast<KeyEvent*>(event);
EXPECT_EQ(deviceId, keyEvent->getDeviceId());
EXPECT_EQ(nature, keyEvent->getNature());
EXPECT_EQ(action, keyEvent->getAction());
EXPECT_EQ(flags, keyEvent->getFlags());
EXPECT_EQ(keyCode, keyEvent->getKeyCode());
EXPECT_EQ(scanCode, keyEvent->getScanCode());
EXPECT_EQ(metaState, keyEvent->getMetaState());
EXPECT_EQ(repeatCount, keyEvent->getRepeatCount());
EXPECT_EQ(downTime, keyEvent->getDownTime());
EXPECT_EQ(eventTime, keyEvent->getEventTime());
status = mConsumer->sendFinishedSignal();
ASSERT_EQ(OK, status)
<< "consumer sendFinishedSignal should return OK";
status = mPublisher->receiveFinishedSignal();
ASSERT_EQ(OK, status)
<< "publisher receiveFinishedSignal should return OK";
status = mPublisher->reset();
ASSERT_EQ(OK, status)
<< "publisher reset should return OK";
}
void InputPublisherAndConsumerTest::PublishAndConsumeMotionEvent(
size_t samplesToAppendBeforeDispatch, size_t samplesToAppendAfterDispatch) {
status_t status;
const int32_t deviceId = 1;
const int32_t nature = INPUT_EVENT_NATURE_TOUCH;
const int32_t action = MOTION_EVENT_ACTION_MOVE;
const int32_t edgeFlags = MOTION_EVENT_EDGE_FLAG_TOP;
const int32_t metaState = META_ALT_LEFT_ON | META_ALT_ON;
const float xOffset = -10;
const float yOffset = -20;
const float xPrecision = 0.25;
const float yPrecision = 0.5;
const nsecs_t downTime = 3;
const size_t pointerCount = 3;
const int32_t pointerIds[pointerCount] = { 2, 0, 1 };
Vector<nsecs_t> sampleEventTimes;
Vector<PointerCoords> samplePointerCoords;
for (size_t i = 0; i <= samplesToAppendAfterDispatch + samplesToAppendBeforeDispatch; i++) {
sampleEventTimes.push(i + 10);
for (size_t j = 0; j < pointerCount; j++) {
samplePointerCoords.push();
samplePointerCoords.editTop().x = 100 * i + j;
samplePointerCoords.editTop().y = 200 * i + j;
samplePointerCoords.editTop().pressure = 0.5 * i + j;
samplePointerCoords.editTop().size = 0.7 * i + j;
}
}
status = mPublisher->publishMotionEvent(deviceId, nature, action, edgeFlags,
metaState, xOffset, yOffset, xPrecision, yPrecision,
downTime, sampleEventTimes[0], pointerCount, pointerIds, samplePointerCoords.array());
ASSERT_EQ(OK, status)
<< "publisher publishMotionEvent should return OK";
for (size_t i = 0; i < samplesToAppendBeforeDispatch; i++) {
size_t sampleIndex = i + 1;
status = mPublisher->appendMotionSample(sampleEventTimes[sampleIndex],
samplePointerCoords.array() + sampleIndex * pointerCount);
ASSERT_EQ(OK, status)
<< "publisher appendMotionEvent should return OK";
}
status = mPublisher->sendDispatchSignal();
ASSERT_EQ(OK, status)
<< "publisher sendDispatchSignal should return OK";
for (size_t i = 0; i < samplesToAppendAfterDispatch; i++) {
size_t sampleIndex = i + 1 + samplesToAppendBeforeDispatch;
status = mPublisher->appendMotionSample(sampleEventTimes[sampleIndex],
samplePointerCoords.array() + sampleIndex * pointerCount);
ASSERT_EQ(OK, status)
<< "publisher appendMotionEvent should return OK";
}
status = mConsumer->receiveDispatchSignal();
ASSERT_EQ(OK, status)
<< "consumer receiveDispatchSignal should return OK";
InputEvent* event;
status = mConsumer->consume(& mEventFactory, & event);
ASSERT_EQ(OK, status)
<< "consumer consume should return OK";
ASSERT_TRUE(event != NULL)
<< "consumer should have returned non-NULL event";
ASSERT_EQ(INPUT_EVENT_TYPE_MOTION, event->getType())
<< "consumer should have returned a motion event";
size_t lastSampleIndex = samplesToAppendBeforeDispatch + samplesToAppendAfterDispatch;
MotionEvent* motionEvent = static_cast<MotionEvent*>(event);
EXPECT_EQ(deviceId, motionEvent->getDeviceId());
EXPECT_EQ(nature, motionEvent->getNature());
EXPECT_EQ(action, motionEvent->getAction());
EXPECT_EQ(edgeFlags, motionEvent->getEdgeFlags());
EXPECT_EQ(metaState, motionEvent->getMetaState());
EXPECT_EQ(xPrecision, motionEvent->getXPrecision());
EXPECT_EQ(yPrecision, motionEvent->getYPrecision());
EXPECT_EQ(downTime, motionEvent->getDownTime());
EXPECT_EQ(sampleEventTimes[lastSampleIndex], motionEvent->getEventTime());
EXPECT_EQ(pointerCount, motionEvent->getPointerCount());
EXPECT_EQ(lastSampleIndex, motionEvent->getHistorySize());
for (size_t i = 0; i < pointerCount; i++) {
SCOPED_TRACE(i);
EXPECT_EQ(pointerIds[i], motionEvent->getPointerId(i));
}
for (size_t sampleIndex = 0; sampleIndex < lastSampleIndex; sampleIndex++) {
SCOPED_TRACE(sampleIndex);
EXPECT_EQ(sampleEventTimes[sampleIndex],
motionEvent->getHistoricalEventTime(sampleIndex));
for (size_t i = 0; i < pointerCount; i++) {
SCOPED_TRACE(i);
size_t offset = sampleIndex * pointerCount + i;
EXPECT_EQ(samplePointerCoords[offset].x,
motionEvent->getHistoricalRawX(i, sampleIndex));
EXPECT_EQ(samplePointerCoords[offset].y,
motionEvent->getHistoricalRawY(i, sampleIndex));
EXPECT_EQ(samplePointerCoords[offset].x + xOffset,
motionEvent->getHistoricalX(i, sampleIndex));
EXPECT_EQ(samplePointerCoords[offset].y + yOffset,
motionEvent->getHistoricalY(i, sampleIndex));
EXPECT_EQ(samplePointerCoords[offset].pressure,
motionEvent->getHistoricalPressure(i, sampleIndex));
EXPECT_EQ(samplePointerCoords[offset].size,
motionEvent->getHistoricalSize(i, sampleIndex));
}
}
SCOPED_TRACE(lastSampleIndex);
EXPECT_EQ(sampleEventTimes[lastSampleIndex], motionEvent->getEventTime());
for (size_t i = 0; i < pointerCount; i++) {
SCOPED_TRACE(i);
size_t offset = lastSampleIndex * pointerCount + i;
EXPECT_EQ(samplePointerCoords[offset].x, motionEvent->getRawX(i));
EXPECT_EQ(samplePointerCoords[offset].y, motionEvent->getRawY(i));
EXPECT_EQ(samplePointerCoords[offset].x + xOffset, motionEvent->getX(i));
EXPECT_EQ(samplePointerCoords[offset].y + yOffset, motionEvent->getY(i));
EXPECT_EQ(samplePointerCoords[offset].pressure, motionEvent->getPressure(i));
EXPECT_EQ(samplePointerCoords[offset].size, motionEvent->getSize(i));
}
status = mConsumer->sendFinishedSignal();
ASSERT_EQ(OK, status)
<< "consumer sendFinishedSignal should return OK";
status = mPublisher->receiveFinishedSignal();
ASSERT_EQ(OK, status)
<< "publisher receiveFinishedSignal should return OK";
status = mPublisher->reset();
ASSERT_EQ(OK, status)
<< "publisher reset should return OK";
}
TEST_F(InputPublisherAndConsumerTest, PublishKeyEvent_EndToEnd) {
ASSERT_NO_FATAL_FAILURE(Initialize());
ASSERT_NO_FATAL_FAILURE(PublishAndConsumeKeyEvent());
}
TEST_F(InputPublisherAndConsumerTest, PublishKeyEvent_WhenNotReset_ReturnsError) {
status_t status;
ASSERT_NO_FATAL_FAILURE(Initialize());
status = mPublisher->publishKeyEvent(0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
ASSERT_EQ(OK, status)
<< "publisher publishKeyEvent should return OK first time";
status = mPublisher->publishKeyEvent(0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
ASSERT_EQ(INVALID_OPERATION, status)
<< "publisher publishKeyEvent should return INVALID_OPERATION because "
"the publisher was not reset";
}
TEST_F(InputPublisherAndConsumerTest, PublishMotionEvent_EndToEnd) {
ASSERT_NO_FATAL_FAILURE(Initialize());
ASSERT_NO_FATAL_FAILURE(PublishAndConsumeMotionEvent());
}
TEST_F(InputPublisherAndConsumerTest, PublishMotionEvent_WhenNotReset_ReturnsError) {
status_t status;
ASSERT_NO_FATAL_FAILURE(Initialize());
const size_t pointerCount = 1;
int32_t pointerIds[pointerCount] = { 0 };
PointerCoords pointerCoords[pointerCount] = { { 0, 0, 0, 0 } };
status = mPublisher->publishMotionEvent(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
pointerCount, pointerIds, pointerCoords);
ASSERT_EQ(OK, status)
<< "publisher publishMotionEvent should return OK";
status = mPublisher->publishMotionEvent(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
pointerCount, pointerIds, pointerCoords);
ASSERT_EQ(INVALID_OPERATION, status)
<< "publisher publishMotionEvent should return INVALID_OPERATION because ";
"the publisher was not reset";
}
TEST_F(InputPublisherAndConsumerTest, PublishMotionEvent_WhenPointerCountLessThan1_ReturnsError) {
status_t status;
ASSERT_NO_FATAL_FAILURE(Initialize());
const size_t pointerCount = 0;
int32_t pointerIds[pointerCount];
PointerCoords pointerCoords[pointerCount];
status = mPublisher->publishMotionEvent(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
pointerCount, pointerIds, pointerCoords);
ASSERT_EQ(BAD_VALUE, status)
<< "publisher publishMotionEvent should return BAD_VALUE";
}
TEST_F(InputPublisherAndConsumerTest, PublishMotionEvent_WhenPointerCountGreaterThanMax_ReturnsError) {
status_t status;
ASSERT_NO_FATAL_FAILURE(Initialize());
const size_t pointerCount = MAX_POINTERS + 1;
int32_t pointerIds[pointerCount];
PointerCoords pointerCoords[pointerCount];
status = mPublisher->publishMotionEvent(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
pointerCount, pointerIds, pointerCoords);
ASSERT_EQ(BAD_VALUE, status)
<< "publisher publishMotionEvent should return BAD_VALUE";
}
TEST_F(InputPublisherAndConsumerTest, PublishMultipleEvents_EndToEnd) {
ASSERT_NO_FATAL_FAILURE(Initialize());
ASSERT_NO_FATAL_FAILURE(PublishAndConsumeMotionEvent());
ASSERT_NO_FATAL_FAILURE(PublishAndConsumeKeyEvent());
ASSERT_NO_FATAL_FAILURE(PublishAndConsumeMotionEvent());
ASSERT_NO_FATAL_FAILURE(PublishAndConsumeMotionEvent());
ASSERT_NO_FATAL_FAILURE(PublishAndConsumeKeyEvent());
}
TEST_F(InputPublisherAndConsumerTest, AppendMotionSample_WhenCalledBeforeDispatchSignal_AppendsSamples) {
status_t status;
ASSERT_NO_FATAL_FAILURE(Initialize());
ASSERT_NO_FATAL_FAILURE(PublishAndConsumeMotionEvent(3, 0));
}
TEST_F(InputPublisherAndConsumerTest, AppendMotionSample_WhenCalledAfterDispatchSignalAndNotConsumed_AppendsSamples) {
status_t status;
ASSERT_NO_FATAL_FAILURE(Initialize());
ASSERT_NO_FATAL_FAILURE(PublishAndConsumeMotionEvent(0, 4));
}
TEST_F(InputPublisherAndConsumerTest, AppendMotionSample_WhenNoMotionEventPublished_ReturnsError) {
status_t status;
ASSERT_NO_FATAL_FAILURE(Initialize());
PointerCoords pointerCoords[1];
status = mPublisher->appendMotionSample(0, pointerCoords);
ASSERT_EQ(INVALID_OPERATION, status)
<< "publisher appendMotionSample should return INVALID_OPERATION";
}
TEST_F(InputPublisherAndConsumerTest, AppendMotionSample_WhenPublishedMotionEventIsNotAMove_ReturnsError) {
status_t status;
ASSERT_NO_FATAL_FAILURE(Initialize());
const size_t pointerCount = MAX_POINTERS;
int32_t pointerIds[pointerCount];
PointerCoords pointerCoords[pointerCount];
status = mPublisher->publishMotionEvent(0, 0, MOTION_EVENT_ACTION_DOWN,
0, 0, 0, 0, 0, 0, 0, 0, pointerCount, pointerIds, pointerCoords);
ASSERT_EQ(OK, status);
status = mPublisher->appendMotionSample(0, pointerCoords);
ASSERT_EQ(INVALID_OPERATION, status)
<< "publisher appendMotionSample should return INVALID_OPERATION";
}
TEST_F(InputPublisherAndConsumerTest, AppendMotionSample_WhenAlreadyConsumed_ReturnsError) {
status_t status;
ASSERT_NO_FATAL_FAILURE(Initialize());
const size_t pointerCount = MAX_POINTERS;
int32_t pointerIds[pointerCount];
PointerCoords pointerCoords[pointerCount];
status = mPublisher->publishMotionEvent(0, 0, MOTION_EVENT_ACTION_MOVE,
0, 0, 0, 0, 0, 0, 0, 0, pointerCount, pointerIds, pointerCoords);
ASSERT_EQ(OK, status);
status = mPublisher->sendDispatchSignal();
ASSERT_EQ(OK, status);
status = mConsumer->receiveDispatchSignal();
ASSERT_EQ(OK, status);
InputEvent* event;
status = mConsumer->consume(& mEventFactory, & event);
ASSERT_EQ(OK, status);
status = mPublisher->appendMotionSample(0, pointerCoords);
ASSERT_EQ(status_t(FAILED_TRANSACTION), status)
<< "publisher appendMotionSample should return FAILED_TRANSACTION";
}
TEST_F(InputPublisherAndConsumerTest, AppendMotionSample_WhenBufferFull_ReturnsError) {
status_t status;
ASSERT_NO_FATAL_FAILURE(Initialize());
const size_t pointerCount = MAX_POINTERS;
int32_t pointerIds[pointerCount];
PointerCoords pointerCoords[pointerCount];
status = mPublisher->publishMotionEvent(0, 0, MOTION_EVENT_ACTION_MOVE,
0, 0, 0, 0, 0, 0, 0, 0, pointerCount, pointerIds, pointerCoords);
ASSERT_EQ(OK, status);
for (int count = 1;; count++) {
ASSERT_LT(count, 100000) << "should eventually reach OOM";
status = mPublisher->appendMotionSample(0, pointerCoords);
if (status != OK) {
ASSERT_GT(count, 12) << "should be able to add at least a dozen samples";
ASSERT_EQ(NO_MEMORY, status)
<< "publisher appendMotionSample should return NO_MEMORY when buffer is full";
break;
}
}
status = mPublisher->appendMotionSample(0, pointerCoords);
ASSERT_EQ(NO_MEMORY, status)
<< "publisher appendMotionSample should return NO_MEMORY persistently until reset";
}
} // namespace android

View File

@ -11,7 +11,7 @@
#define DEBUG_POLL_AND_WAKE 0 #define DEBUG_POLL_AND_WAKE 0
// Debugs callback registration and invocation. // Debugs callback registration and invocation.
#define DEBUG_CALLBACKS 1 #define DEBUG_CALLBACKS 0
#include <cutils/log.h> #include <cutils/log.h>
#include <utils/PollLoop.h> #include <utils/PollLoop.h>
@ -22,7 +22,7 @@
namespace android { namespace android {
PollLoop::PollLoop() : PollLoop::PollLoop() :
mPolling(false) { mPolling(false), mWaiters(0) {
openWakePipe(); openWakePipe();
} }
@ -68,6 +68,9 @@ void PollLoop::closeWakePipe() {
bool PollLoop::pollOnce(int timeoutMillis) { bool PollLoop::pollOnce(int timeoutMillis) {
mLock.lock(); mLock.lock();
while (mWaiters != 0) {
mResume.wait(mLock);
}
mPolling = true; mPolling = true;
mLock.unlock(); mLock.unlock();
@ -156,7 +159,9 @@ bool PollLoop::pollOnce(int timeoutMillis) {
Done: Done:
mLock.lock(); mLock.lock();
mPolling = false; mPolling = false;
if (mWaiters != 0) {
mAwake.broadcast(); mAwake.broadcast();
}
mLock.unlock(); mLock.unlock();
if (result) { if (result) {
@ -258,10 +263,15 @@ ssize_t PollLoop::getRequestIndexLocked(int fd) {
void PollLoop::wakeAndLock() { void PollLoop::wakeAndLock() {
mLock.lock(); mLock.lock();
mWaiters += 1;
while (mPolling) { while (mPolling) {
wake(); wake();
mAwake.wait(mLock); mAwake.wait(mLock);
} }
mWaiters -= 1;
if (mWaiters == 0) {
mResume.signal();
}
} }
} // namespace android } // namespace android

View File

@ -108,7 +108,7 @@ size_t VectorImpl::capacity() const
ssize_t VectorImpl::insertVectorAt(const VectorImpl& vector, size_t index) ssize_t VectorImpl::insertVectorAt(const VectorImpl& vector, size_t index)
{ {
return insertAt(vector.arrayImpl(), index, vector.size()); return insertArrayAt(vector.arrayImpl(), index, vector.size());
} }
ssize_t VectorImpl::appendVector(const VectorImpl& vector) ssize_t VectorImpl::appendVector(const VectorImpl& vector)
@ -116,6 +116,22 @@ ssize_t VectorImpl::appendVector(const VectorImpl& vector)
return insertVectorAt(vector, size()); return insertVectorAt(vector, size());
} }
ssize_t VectorImpl::insertArrayAt(const void* array, size_t index, size_t length)
{
if (index > size())
return BAD_INDEX;
void* where = _grow(index, length);
if (where) {
_do_copy(where, array, length);
}
return where ? index : (ssize_t)NO_MEMORY;
}
ssize_t VectorImpl::appendArray(const void* array, size_t length)
{
return insertArrayAt(array, size(), length);
}
ssize_t VectorImpl::insertAt(size_t index, size_t numItems) ssize_t VectorImpl::insertAt(size_t index, size_t numItems)
{ {
return insertAt(0, index, numItems); return insertAt(0, index, numItems);
@ -220,9 +236,9 @@ ssize_t VectorImpl::add()
return add(0); return add(0);
} }
ssize_t VectorImpl::add(const void* item, size_t numItems) ssize_t VectorImpl::add(const void* item)
{ {
return insertAt(item, size(), numItems); return insertAt(item, size());
} }
ssize_t VectorImpl::replaceAt(size_t index) ssize_t VectorImpl::replaceAt(size_t index)

View File

@ -16,34 +16,6 @@
namespace android { namespace android {
class Pipe {
public:
int sendFd;
int receiveFd;
Pipe() {
int fds[2];
::pipe(fds);
receiveFd = fds[0];
sendFd = fds[1];
}
~Pipe() {
::close(sendFd);
::close(receiveFd);
}
bool writeSignal() {
return ::write(sendFd, "*", 1) == 1;
}
bool readSignal() {
char buf[1];
return ::read(receiveFd, buf, 1) == 1;
}
};
class DelayedWake : public DelayedTask { class DelayedWake : public DelayedTask {
sp<PollLoop> mPollLoop; sp<PollLoop> mPollLoop;
@ -195,7 +167,7 @@ TEST_F(PollLoopTest, PollOnce_WhenZeroTimeoutAndSignalledFD_ImmediatelyInvokesCa
Pipe pipe; Pipe pipe;
StubCallbackHandler handler(true); StubCallbackHandler handler(true);
ASSERT_TRUE(pipe.writeSignal()); ASSERT_EQ(OK, pipe.writeSignal());
handler.setCallback(mPollLoop, pipe.receiveFd, POLL_IN); handler.setCallback(mPollLoop, pipe.receiveFd, POLL_IN);
StopWatch stopWatch("pollOnce"); StopWatch stopWatch("pollOnce");
@ -243,7 +215,7 @@ TEST_F(PollLoopTest, PollOnce_WhenNonZeroTimeoutAndSignalledFDBeforeWaiting_Imme
bool result = mPollLoop->pollOnce(100); bool result = mPollLoop->pollOnce(100);
int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime()); int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
ASSERT_TRUE(pipe.readSignal()) ASSERT_EQ(OK, pipe.readSignal())
<< "signal should actually have been written"; << "signal should actually have been written";
EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS) EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS)
<< "elapsed time should be approx. zero"; << "elapsed time should be approx. zero";
@ -269,7 +241,7 @@ TEST_F(PollLoopTest, PollOnce_WhenNonZeroTimeoutAndSignalledFDWhileWaiting_Promp
bool result = mPollLoop->pollOnce(1000); bool result = mPollLoop->pollOnce(1000);
int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime()); int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
ASSERT_TRUE(pipe.readSignal()) ASSERT_EQ(OK, pipe.readSignal())
<< "signal should actually have been written"; << "signal should actually have been written";
EXPECT_NEAR(100, elapsedMillis, TIMING_TOLERANCE_MS) EXPECT_NEAR(100, elapsedMillis, TIMING_TOLERANCE_MS)
<< "elapsed time should approx. equal signal delay"; << "elapsed time should approx. equal signal delay";
@ -295,7 +267,7 @@ TEST_F(PollLoopTest, PollOnce_WhenCallbackAddedThenRemoved_CallbackShouldNotBeIn
bool result = mPollLoop->pollOnce(100); bool result = mPollLoop->pollOnce(100);
int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime()); int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
ASSERT_TRUE(pipe.readSignal()) ASSERT_EQ(OK, pipe.readSignal())
<< "signal should actually have been written"; << "signal should actually have been written";
EXPECT_NEAR(100, elapsedMillis, TIMING_TOLERANCE_MS) EXPECT_NEAR(100, elapsedMillis, TIMING_TOLERANCE_MS)
<< "elapsed time should approx. equal timeout because FD was no longer registered"; << "elapsed time should approx. equal timeout because FD was no longer registered";
@ -318,7 +290,7 @@ TEST_F(PollLoopTest, PollOnce_WhenCallbackReturnsFalse_CallbackShouldNotBeInvoke
bool result = mPollLoop->pollOnce(0); bool result = mPollLoop->pollOnce(0);
int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime()); int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
ASSERT_TRUE(pipe.readSignal()) ASSERT_EQ(OK, pipe.readSignal())
<< "signal should actually have been written"; << "signal should actually have been written";
EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS) EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS)
<< "elapsed time should approx. equal zero because FD was already signalled"; << "elapsed time should approx. equal zero because FD was already signalled";
@ -334,7 +306,7 @@ TEST_F(PollLoopTest, PollOnce_WhenCallbackReturnsFalse_CallbackShouldNotBeInvoke
result = mPollLoop->pollOnce(0); result = mPollLoop->pollOnce(0);
elapsedMillis = ns2ms(stopWatch.elapsedTime()); elapsedMillis = ns2ms(stopWatch.elapsedTime());
ASSERT_TRUE(pipe.readSignal()) ASSERT_EQ(OK, pipe.readSignal())
<< "signal should actually have been written"; << "signal should actually have been written";
EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS) EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS)
<< "elapsed time should approx. equal zero because timeout was zero"; << "elapsed time should approx. equal zero because timeout was zero";
@ -382,7 +354,7 @@ TEST_F(PollLoopTest, PollOnce_WhenCallbackAddedTwice_OnlySecondCallbackShouldBeI
bool result = mPollLoop->pollOnce(100); bool result = mPollLoop->pollOnce(100);
int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime()); int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
ASSERT_TRUE(pipe.readSignal()) ASSERT_EQ(OK, pipe.readSignal())
<< "signal should actually have been written"; << "signal should actually have been written";
EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS) EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS)
<< "elapsed time should approx. zero because FD was already signalled"; << "elapsed time should approx. zero because FD was already signalled";

View File

@ -21,6 +21,41 @@
namespace android { namespace android {
class Pipe {
public:
int sendFd;
int receiveFd;
Pipe() {
int fds[2];
::pipe(fds);
receiveFd = fds[0];
sendFd = fds[1];
}
~Pipe() {
if (sendFd != -1) {
::close(sendFd);
}
if (receiveFd != -1) {
::close(receiveFd);
}
}
status_t writeSignal() {
ssize_t nWritten = ::write(sendFd, "*", 1);
return nWritten == 1 ? 0 : -errno;
}
status_t readSignal() {
char buf[1];
ssize_t nRead = ::read(receiveFd, buf, 1);
return nRead == 1 ? 0 : nRead == 0 ? -EPIPE : -errno;
}
};
class DelayedTask : public Thread { class DelayedTask : public Thread {
int mDelayMillis; int mDelayMillis;

View File

@ -394,6 +394,18 @@ int64_t motion_event_get_down_time(const input_event_t* motion_event);
* in the java.lang.System.nanoTime() time base. */ * in the java.lang.System.nanoTime() time base. */
int64_t motion_event_get_event_time(const input_event_t* motion_event); int64_t motion_event_get_event_time(const input_event_t* motion_event);
/* Get the X coordinate offset.
* For touch events on the screen, this is the delta that was added to the raw
* screen coordinates to adjust for the absolute position of the containing windows
* and views. */
float motion_event_get_x_offset(const input_event_t* motion_event);
/* Get the precision of the Y coordinates being reported.
* For touch events on the screen, this is the delta that was added to the raw
* screen coordinates to adjust for the absolute position of the containing windows
* and views. */
float motion_event_get_y_offset(const input_event_t* motion_event);
/* Get the precision of the X coordinates being reported. /* Get the precision of the X coordinates being reported.
* You can multiply this number with an X coordinate sample to find the * You can multiply this number with an X coordinate sample to find the
* actual hardware value of the X coordinate. */ * actual hardware value of the X coordinate. */
@ -414,17 +426,17 @@ size_t motion_event_get_pointer_count(const input_event_t* motion_event);
* going up and down since the start of the current gesture. */ * going up and down since the start of the current gesture. */
int32_t motion_event_get_pointer_id(const input_event_t* motion_event, size_t pointer_index); int32_t motion_event_get_pointer_id(const input_event_t* motion_event, size_t pointer_index);
/* Get the original raw X coordinate of this event. For touch /* Get the original raw X coordinate of this event.
* events on the screen, this is the original location of the event * For touch events on the screen, this is the original location of the event
* on the screen, before it had been adjusted for the containing window * on the screen, before it had been adjusted for the containing window
* and views. */ * and views. */
float motion_event_get_raw_x(const input_event_t* motion_event); float motion_event_get_raw_x(const input_event_t* motion_event, size_t pointer_index);
/* Get the original raw X coordinate of this event. For touch /* Get the original raw X coordinate of this event.
* events on the screen, this is the original location of the event * For touch events on the screen, this is the original location of the event
* on the screen, before it had been adjusted for the containing window * on the screen, before it had been adjusted for the containing window
* and views. */ * and views. */
float motion_event_get_raw_y(const input_event_t* motion_event); float motion_event_get_raw_y(const input_event_t* motion_event, size_t pointer_index);
/* Get the current X coordinate of this event for the given pointer index. /* Get the current X coordinate of this event for the given pointer index.
* Whole numbers are pixels; the value may have a fraction for input devices * Whole numbers are pixels; the value may have a fraction for input devices
@ -461,6 +473,24 @@ size_t motion_event_get_history_size(const input_event_t* motion_event);
int64_t motion_event_get_historical_event_time(input_event_t* motion_event, int64_t motion_event_get_historical_event_time(input_event_t* motion_event,
size_t history_index); size_t history_index);
/* Get the historical raw X coordinate of this event for the given pointer index that
* occurred between this event and the previous motion event.
* For touch events on the screen, this is the original location of the event
* on the screen, before it had been adjusted for the containing window
* and views.
* Whole numbers are pixels; the value may have a fraction for input devices
* that are sub-pixel precise. */
float motion_event_get_historical_raw_x(const input_event_t* motion_event, size_t pointer_index);
/* Get the historical raw Y coordinate of this event for the given pointer index that
* occurred between this event and the previous motion event.
* For touch events on the screen, this is the original location of the event
* on the screen, before it had been adjusted for the containing window
* and views.
* Whole numbers are pixels; the value may have a fraction for input devices
* that are sub-pixel precise. */
float motion_event_get_historical_raw_y(const input_event_t* motion_event, size_t pointer_index);
/* Get the historical X coordinate of this event for the given pointer index that /* Get the historical X coordinate of this event for the given pointer index that
* occurred between this event and the previous motion event. * occurred between this event and the previous motion event.
* Whole numbers are pixels; the value may have a fraction for input devices * Whole numbers are pixels; the value may have a fraction for input devices

View File

@ -294,9 +294,7 @@ int32_t NativeInputManager::interceptKey(nsecs_t when,
if (wmActions & WM_ACTION_PASS_TO_USER) { if (wmActions & WM_ACTION_PASS_TO_USER) {
actions |= InputReaderPolicyInterface::ACTION_DISPATCH; actions |= InputReaderPolicyInterface::ACTION_DISPATCH;
}
if (! (wmActions & WM_ACTION_PASS_TO_USER)) {
if (down && isAppSwitchKey(keyCode)) { if (down && isAppSwitchKey(keyCode)) {
env->CallVoidMethod(mCallbacksObj, gCallbacksClassInfo.notifyAppSwitchComing); env->CallVoidMethod(mCallbacksObj, gCallbacksClassInfo.notifyAppSwitchComing);
checkExceptionFromCallback(env, "notifyAppSwitchComing"); checkExceptionFromCallback(env, "notifyAppSwitchComing");
@ -312,12 +310,18 @@ int32_t NativeInputManager::interceptTouch(nsecs_t when) {
LOGD("interceptTouch - when=%lld", when); LOGD("interceptTouch - when=%lld", when);
#endif #endif
if (! isScreenOn()) { int32_t actions = InputReaderPolicyInterface::ACTION_NONE;
// Touch events do not wake the device. if (isScreenOn()) {
return InputReaderPolicyInterface::ACTION_NONE; // Only dispatch touch events when the device is awake.
actions |= InputReaderPolicyInterface::ACTION_DISPATCH;
} }
return InputReaderPolicyInterface::ACTION_DISPATCH; if (! isScreenBright()) {
// Brighten the screen if dimmed.
actions |= InputReaderPolicyInterface::ACTION_BRIGHT_HERE;
}
return actions;
} }
int32_t NativeInputManager::interceptTrackball(nsecs_t when, int32_t NativeInputManager::interceptTrackball(nsecs_t when,
@ -327,12 +331,18 @@ int32_t NativeInputManager::interceptTrackball(nsecs_t when,
when, buttonChanged, buttonDown, rolled); when, buttonChanged, buttonDown, rolled);
#endif #endif
if (! isScreenOn()) { int32_t actions = InputReaderPolicyInterface::ACTION_NONE;
// Trackball motions and button presses do not wake the device. if (isScreenOn()) {
return InputReaderPolicyInterface::ACTION_NONE; // Only dispatch trackball events when the device is awake.
actions |= InputReaderPolicyInterface::ACTION_DISPATCH;
} }
return InputReaderPolicyInterface::ACTION_DISPATCH; if (! isScreenBright()) {
// Brighten the screen if dimmed.
actions |= InputReaderPolicyInterface::ACTION_BRIGHT_HERE;
}
return actions;
} }
int32_t NativeInputManager::interceptSwitch(nsecs_t when, int32_t switchCode, int32_t NativeInputManager::interceptSwitch(nsecs_t when, int32_t switchCode,