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:
@ -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"
|
||||||
>
|
>
|
||||||
|
@ -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]);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
@ -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.
|
||||||
|
@ -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;
|
||||||
|
@ -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
|
||||||
|
@ -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);
|
||||||
|
@ -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(
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
@ -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
|
||||||
|
@ -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 \
|
||||||
|
158
libs/ui/tests/InputChannel_test.cpp
Normal file
158
libs/ui/tests/InputChannel_test.cpp
Normal 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
|
@ -12,8 +12,7 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
TEST_F(InputDispatcherTest, Dummy) {
|
TEST_F(InputDispatcherTest, Dummy) {
|
||||||
SCOPED_TRACE("Trace");
|
// TODO
|
||||||
ASSERT_FALSE(true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace android
|
} // namespace android
|
||||||
|
449
libs/ui/tests/InputPublisherAndConsumer_test.cpp
Normal file
449
libs/ui/tests/InputPublisherAndConsumer_test.cpp
Normal 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
|
@ -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
|
||||||
|
@ -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)
|
||||||
|
@ -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";
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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,
|
||||||
|
Reference in New Issue
Block a user