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"
|
||||
static="true"
|
||||
final="false"
|
||||
deprecated="not deprecated"
|
||||
deprecated="deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
<parameter name="downTime" type="long">
|
||||
@ -176904,7 +176904,7 @@
|
||||
native="false"
|
||||
synchronized="false"
|
||||
static="false"
|
||||
final="false"
|
||||
final="true"
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
|
@ -27,6 +27,7 @@ import android.util.Log;
|
||||
* it is being used for.
|
||||
*/
|
||||
public final class MotionEvent implements Parcelable {
|
||||
private static final long MS_PER_NS = 1000000;
|
||||
static final boolean DEBUG_POINTERS = false;
|
||||
|
||||
/**
|
||||
@ -218,31 +219,32 @@ public final class MotionEvent implements Parcelable {
|
||||
static private int gRecyclerUsed = 0;
|
||||
static private MotionEvent gRecyclerTop = null;
|
||||
|
||||
private long mDownTime;
|
||||
private long mEventTimeNano;
|
||||
private long mDownTimeNano;
|
||||
private int mAction;
|
||||
private float mRawX;
|
||||
private float mRawY;
|
||||
private float mXOffset;
|
||||
private float mYOffset;
|
||||
private float mXPrecision;
|
||||
private float mYPrecision;
|
||||
private int mDeviceId;
|
||||
private int mEdgeFlags;
|
||||
private int mMetaState;
|
||||
|
||||
// Here is the actual event data. Note that the order of the array
|
||||
// is a little odd: the first entry is the most recent, and the ones
|
||||
// following it are the historical data from oldest to newest. This
|
||||
// allows us to easily retrieve the most recent data, without having
|
||||
// to copy the arrays every time a new sample is added.
|
||||
|
||||
private int mNumPointers;
|
||||
private int mNumSamples;
|
||||
|
||||
private int mLastDataSampleIndex;
|
||||
private int mLastEventTimeNanoSampleIndex;
|
||||
|
||||
// Array of mNumPointers size of identifiers for each pointer of data.
|
||||
private int[] mPointerIdentifiers;
|
||||
|
||||
// Array of (mNumSamples * mNumPointers * NUM_SAMPLE_DATA) size of event data.
|
||||
// Samples are ordered from oldest to newest.
|
||||
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 RuntimeException mRecycledLocation;
|
||||
@ -251,26 +253,9 @@ public final class MotionEvent implements Parcelable {
|
||||
private MotionEvent(int pointerCount, int sampleCount) {
|
||||
mPointerIdentifiers = new int[pointerCount];
|
||||
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) {
|
||||
final MotionEvent ev;
|
||||
synchronized (gRecyclerLock) {
|
||||
@ -285,7 +270,7 @@ public final class MotionEvent implements Parcelable {
|
||||
}
|
||||
ev = gRecyclerTop;
|
||||
gRecyclerTop = ev.mNext;
|
||||
gRecyclerUsed--;
|
||||
gRecyclerUsed -= 1;
|
||||
}
|
||||
ev.mRecycledLocation = null;
|
||||
ev.mRecycled = false;
|
||||
@ -295,20 +280,18 @@ public final class MotionEvent implements Parcelable {
|
||||
ev.mPointerIdentifiers = new int[pointerCount];
|
||||
}
|
||||
|
||||
final int timeSamplesLength = ev.mTimeSamples.length;
|
||||
if (timeSamplesLength < sampleCount) {
|
||||
ev.mTimeSamples = new long[sampleCount];
|
||||
if (ev.mEventTimeNanoSamples.length < sampleCount) {
|
||||
ev.mEventTimeNanoSamples = new long[sampleCount];
|
||||
}
|
||||
|
||||
final int dataSamplesLength = ev.mDataSamples.length;
|
||||
final int neededDataSamplesLength = pointerCount * sampleCount * NUM_SAMPLE_DATA;
|
||||
if (dataSamplesLength < neededDataSamplesLength) {
|
||||
if (ev.mDataSamples.length < neededDataSamplesLength) {
|
||||
ev.mDataSamples = new float[neededDataSamplesLength];
|
||||
}
|
||||
|
||||
return ev;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create a new MotionEvent, filling in all of the basic values that
|
||||
* define the motion.
|
||||
@ -342,45 +325,39 @@ public final class MotionEvent implements Parcelable {
|
||||
static public MotionEvent obtainNano(long downTime, long eventTime, long eventTimeNano,
|
||||
int action, int pointers, int[] inPointerIds, float[] inData, int metaState,
|
||||
float xPrecision, float yPrecision, int deviceId, int edgeFlags) {
|
||||
MotionEvent ev = obtain();
|
||||
MotionEvent ev = obtain(pointers, 1);
|
||||
ev.mDeviceId = deviceId;
|
||||
ev.mEdgeFlags = edgeFlags;
|
||||
ev.mDownTime = downTime;
|
||||
ev.mEventTimeNano = eventTimeNano;
|
||||
ev.mDownTimeNano = downTime * MS_PER_NS;
|
||||
ev.mAction = action;
|
||||
ev.mMetaState = metaState;
|
||||
ev.mRawX = inData[SAMPLE_X];
|
||||
ev.mRawY = inData[SAMPLE_Y];
|
||||
ev.mXOffset = 0;
|
||||
ev.mYOffset = 0;
|
||||
ev.mXPrecision = xPrecision;
|
||||
ev.mYPrecision = yPrecision;
|
||||
|
||||
ev.mNumPointers = pointers;
|
||||
ev.mNumSamples = 1;
|
||||
|
||||
int[] pointerIdentifiers = ev.mPointerIdentifiers;
|
||||
if (pointerIdentifiers.length < pointers) {
|
||||
ev.mPointerIdentifiers = pointerIdentifiers = new int[pointers];
|
||||
}
|
||||
System.arraycopy(inPointerIds, 0, pointerIdentifiers, 0, pointers);
|
||||
ev.mLastDataSampleIndex = 0;
|
||||
ev.mLastEventTimeNanoSampleIndex = 0;
|
||||
|
||||
final int ND = pointers * NUM_SAMPLE_DATA;
|
||||
float[] dataSamples = ev.mDataSamples;
|
||||
if (dataSamples.length < ND) {
|
||||
ev.mDataSamples = dataSamples = new float[ND];
|
||||
}
|
||||
System.arraycopy(inData, 0, dataSamples, 0, ND);
|
||||
System.arraycopy(inPointerIds, 0, ev.mPointerIdentifiers, 0, pointers);
|
||||
|
||||
ev.mTimeSamples[0] = eventTime;
|
||||
ev.mEventTimeNanoSamples[0] = eventTimeNano;
|
||||
|
||||
System.arraycopy(inData, 0, ev.mDataSamples, 0, pointers * NUM_SAMPLE_DATA);
|
||||
|
||||
if (DEBUG_POINTERS) {
|
||||
StringBuilder sb = new StringBuilder(128);
|
||||
sb.append("New:");
|
||||
for (int i=0; i<pointers; i++) {
|
||||
for (int i = 0; i < pointers; i++) {
|
||||
sb.append(" #");
|
||||
sb.append(ev.mPointerIdentifiers[i]);
|
||||
sb.append(ev.getPointerId(i));
|
||||
sb.append("(");
|
||||
sb.append(ev.mDataSamples[(i*NUM_SAMPLE_DATA) + SAMPLE_X]);
|
||||
sb.append(ev.getX(i));
|
||||
sb.append(",");
|
||||
sb.append(ev.mDataSamples[(i*NUM_SAMPLE_DATA) + SAMPLE_Y]);
|
||||
sb.append(ev.getY(i));
|
||||
sb.append(")");
|
||||
}
|
||||
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,
|
||||
float x, float y, float pressure, float size, int metaState,
|
||||
float xPrecision, float yPrecision, int deviceId, int edgeFlags) {
|
||||
MotionEvent ev = obtain();
|
||||
MotionEvent ev = obtain(1, 1);
|
||||
ev.mDeviceId = deviceId;
|
||||
ev.mEdgeFlags = edgeFlags;
|
||||
ev.mDownTime = downTime;
|
||||
ev.mEventTimeNano = eventTime * 1000000;
|
||||
ev.mDownTimeNano = downTime * MS_PER_NS;
|
||||
ev.mAction = action;
|
||||
ev.mMetaState = metaState;
|
||||
ev.mXOffset = 0;
|
||||
ev.mYOffset = 0;
|
||||
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;
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@ -478,33 +460,16 @@ public final class MotionEvent implements Parcelable {
|
||||
* numbers are arbitrary and you shouldn't depend on the values.
|
||||
* @param edgeFlags A bitfield indicating which edges, if any, where touched by this
|
||||
* MotionEvent.
|
||||
*
|
||||
* @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,
|
||||
int pointers, float x, float y, float pressure, float size, int metaState,
|
||||
float xPrecision, float yPrecision, int deviceId, int edgeFlags) {
|
||||
MotionEvent ev = obtain();
|
||||
ev.mDeviceId = deviceId;
|
||||
ev.mEdgeFlags = edgeFlags;
|
||||
ev.mDownTime = downTime;
|
||||
ev.mEventTimeNano = eventTime * 1000000;
|
||||
ev.mAction = action;
|
||||
ev.mNumPointers = pointers;
|
||||
ev.mMetaState = metaState;
|
||||
ev.mXPrecision = xPrecision;
|
||||
ev.mYPrecision = yPrecision;
|
||||
|
||||
ev.mNumPointers = 1;
|
||||
ev.mNumSamples = 1;
|
||||
int[] pointerIds = ev.mPointerIdentifiers;
|
||||
pointerIds[0] = 0;
|
||||
float[] data = ev.mDataSamples;
|
||||
data[SAMPLE_X] = ev.mRawX = x;
|
||||
data[SAMPLE_Y] = ev.mRawY = y;
|
||||
data[SAMPLE_PRESSURE] = pressure;
|
||||
data[SAMPLE_SIZE] = size;
|
||||
ev.mTimeSamples[0] = eventTime;
|
||||
|
||||
return ev;
|
||||
return obtain(downTime, eventTime, action, x, y, pressure, size,
|
||||
metaState, xPrecision, yPrecision, deviceId, edgeFlags);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -526,89 +491,36 @@ public final class MotionEvent implements Parcelable {
|
||||
*/
|
||||
static public MotionEvent obtain(long downTime, long eventTime, int action,
|
||||
float x, float y, int metaState) {
|
||||
MotionEvent ev = obtain();
|
||||
ev.mDeviceId = 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?
|
||||
}
|
||||
return obtain(downTime, eventTime, action, x, y, 1.0f, 1.0f,
|
||||
metaState, 1.0f, 1.0f, 0, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new MotionEvent, copying from an existing one.
|
||||
*/
|
||||
static public MotionEvent obtain(MotionEvent o) {
|
||||
MotionEvent ev = obtain();
|
||||
MotionEvent ev = obtain(o.mNumPointers, o.mNumSamples);
|
||||
ev.mDeviceId = o.mDeviceId;
|
||||
ev.mEdgeFlags = o.mEdgeFlags;
|
||||
ev.mDownTime = o.mDownTime;
|
||||
ev.mEventTimeNano = o.mEventTimeNano;
|
||||
ev.mDownTimeNano = o.mDownTimeNano;
|
||||
ev.mAction = o.mAction;
|
||||
ev.mNumPointers = o.mNumPointers;
|
||||
ev.mRawX = o.mRawX;
|
||||
ev.mRawY = o.mRawY;
|
||||
ev.mMetaState = o.mMetaState;
|
||||
ev.mXOffset = o.mXOffset;
|
||||
ev.mYOffset = o.mYOffset;
|
||||
ev.mXPrecision = o.mXPrecision;
|
||||
ev.mYPrecision = o.mYPrecision;
|
||||
int numPointers = ev.mNumPointers = o.mNumPointers;
|
||||
int numSamples = ev.mNumSamples = o.mNumSamples;
|
||||
|
||||
final int NS = ev.mNumSamples = o.mNumSamples;
|
||||
if (ev.mTimeSamples.length >= NS) {
|
||||
System.arraycopy(o.mTimeSamples, 0, ev.mTimeSamples, 0, NS);
|
||||
} else {
|
||||
ev.mTimeSamples = (long[])o.mTimeSamples.clone();
|
||||
}
|
||||
ev.mLastDataSampleIndex = o.mLastDataSampleIndex;
|
||||
ev.mLastEventTimeNanoSampleIndex = o.mLastEventTimeNanoSampleIndex;
|
||||
|
||||
final int NP = (ev.mNumPointers=o.mNumPointers);
|
||||
if (ev.mPointerIdentifiers.length >= NP) {
|
||||
System.arraycopy(o.mPointerIdentifiers, 0, ev.mPointerIdentifiers, 0, NP);
|
||||
} else {
|
||||
ev.mPointerIdentifiers = (int[])o.mPointerIdentifiers.clone();
|
||||
}
|
||||
System.arraycopy(o.mPointerIdentifiers, 0, ev.mPointerIdentifiers, 0, numPointers);
|
||||
|
||||
final int ND = NP * NS * NUM_SAMPLE_DATA;
|
||||
if (ev.mDataSamples.length >= ND) {
|
||||
System.arraycopy(o.mDataSamples, 0, ev.mDataSamples, 0, ND);
|
||||
} else {
|
||||
ev.mDataSamples = (float[])o.mDataSamples.clone();
|
||||
}
|
||||
System.arraycopy(o.mEventTimeNanoSamples, 0, ev.mEventTimeNanoSamples, 0, numSamples);
|
||||
|
||||
System.arraycopy(o.mDataSamples, 0, ev.mDataSamples, 0,
|
||||
numPointers * numSamples * NUM_SAMPLE_DATA);
|
||||
return ev;
|
||||
}
|
||||
|
||||
@ -617,36 +529,29 @@ public final class MotionEvent implements Parcelable {
|
||||
* any historical point information.
|
||||
*/
|
||||
static public MotionEvent obtainNoHistory(MotionEvent o) {
|
||||
MotionEvent ev = obtain();
|
||||
MotionEvent ev = obtain(o.mNumPointers, 1);
|
||||
ev.mDeviceId = o.mDeviceId;
|
||||
ev.mEdgeFlags = o.mEdgeFlags;
|
||||
ev.mDownTime = o.mDownTime;
|
||||
ev.mEventTimeNano = o.mEventTimeNano;
|
||||
ev.mDownTimeNano = o.mDownTimeNano;
|
||||
ev.mAction = o.mAction;
|
||||
ev.mNumPointers = o.mNumPointers;
|
||||
ev.mRawX = o.mRawX;
|
||||
ev.mRawY = o.mRawY;
|
||||
ev.mMetaState = o.mMetaState;
|
||||
ev.mXOffset = o.mXOffset;
|
||||
ev.mYOffset = o.mYOffset;
|
||||
ev.mXPrecision = o.mXPrecision;
|
||||
ev.mYPrecision = o.mYPrecision;
|
||||
|
||||
int numPointers = ev.mNumPointers = o.mNumPointers;
|
||||
ev.mNumSamples = 1;
|
||||
ev.mTimeSamples[0] = o.mTimeSamples[0];
|
||||
|
||||
final int NP = (ev.mNumPointers=o.mNumPointers);
|
||||
if (ev.mPointerIdentifiers.length >= NP) {
|
||||
System.arraycopy(o.mPointerIdentifiers, 0, ev.mPointerIdentifiers, 0, NP);
|
||||
} else {
|
||||
ev.mPointerIdentifiers = (int[])o.mPointerIdentifiers.clone();
|
||||
}
|
||||
ev.mLastDataSampleIndex = 0;
|
||||
ev.mLastEventTimeNanoSampleIndex = 0;
|
||||
|
||||
final int ND = NP * NUM_SAMPLE_DATA;
|
||||
if (ev.mDataSamples.length >= ND) {
|
||||
System.arraycopy(o.mDataSamples, 0, ev.mDataSamples, 0, ND);
|
||||
} else {
|
||||
ev.mDataSamples = (float[])o.mDataSamples.clone();
|
||||
}
|
||||
System.arraycopy(o.mPointerIdentifiers, 0, ev.mPointerIdentifiers, 0, numPointers);
|
||||
|
||||
ev.mEventTimeNanoSamples[0] = o.mEventTimeNanoSamples[o.mLastEventTimeNanoSampleIndex];
|
||||
|
||||
System.arraycopy(o.mDataSamples, o.mLastDataSampleIndex, ev.mDataSamples, 0,
|
||||
numPointers * NUM_SAMPLE_DATA);
|
||||
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
|
||||
* this function you must not ever touch the event again.
|
||||
*/
|
||||
public void recycle() {
|
||||
public final void recycle() {
|
||||
// Ensure recycle is only called once!
|
||||
if (TRACK_RECYCLED_LOCATION) {
|
||||
if (mRecycledLocation != null) {
|
||||
@ -678,6 +583,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
|
||||
@ -719,14 +645,14 @@ public final class MotionEvent implements Parcelable {
|
||||
* a stream of position events.
|
||||
*/
|
||||
public final long getDownTime() {
|
||||
return mDownTime;
|
||||
return mDownTimeNano / MS_PER_NS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the time (in ms) when this specific event was generated.
|
||||
*/
|
||||
public final long getEventTime() {
|
||||
return mTimeSamples[0];
|
||||
return mEventTimeNanoSamples[mLastEventTimeNanoSampleIndex] / MS_PER_NS;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -736,7 +662,7 @@ public final class MotionEvent implements Parcelable {
|
||||
* @hide
|
||||
*/
|
||||
public final long getEventTimeNano() {
|
||||
return mEventTimeNano;
|
||||
return mEventTimeNanoSamples[mLastEventTimeNanoSampleIndex];
|
||||
}
|
||||
|
||||
/**
|
||||
@ -744,7 +670,7 @@ public final class MotionEvent implements Parcelable {
|
||||
* arbitrary pointer identifier).
|
||||
*/
|
||||
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).
|
||||
*/
|
||||
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).
|
||||
*/
|
||||
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).
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
public final float getRawX() {
|
||||
return mRawX;
|
||||
return mDataSamples[mLastDataSampleIndex + SAMPLE_X];
|
||||
}
|
||||
|
||||
/**
|
||||
@ -898,7 +828,7 @@ public final class MotionEvent implements Parcelable {
|
||||
* and views.
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
public final int getHistorySize() {
|
||||
return mNumSamples - 1;
|
||||
return mLastEventTimeNanoSampleIndex;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -944,7 +874,7 @@ public final class MotionEvent implements Parcelable {
|
||||
* @see #getEventTime
|
||||
*/
|
||||
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).
|
||||
*/
|
||||
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).
|
||||
*/
|
||||
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).
|
||||
*/
|
||||
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).
|
||||
*/
|
||||
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
|
||||
*/
|
||||
public final float getHistoricalX(int pointerIndex, int pos) {
|
||||
return mDataSamples[((pos + 1) * NUM_SAMPLE_DATA * mNumPointers)
|
||||
+ (pointerIndex * NUM_SAMPLE_DATA) + SAMPLE_X];
|
||||
return mDataSamples[(pos * mNumPointers + pointerIndex)
|
||||
* NUM_SAMPLE_DATA + SAMPLE_X] + mXOffset;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1011,8 +941,8 @@ public final class MotionEvent implements Parcelable {
|
||||
* @see #getY
|
||||
*/
|
||||
public final float getHistoricalY(int pointerIndex, int pos) {
|
||||
return mDataSamples[((pos + 1) * NUM_SAMPLE_DATA * mNumPointers)
|
||||
+ (pointerIndex * NUM_SAMPLE_DATA) + SAMPLE_Y];
|
||||
return mDataSamples[(pos * mNumPointers + pointerIndex)
|
||||
* NUM_SAMPLE_DATA + SAMPLE_Y] + mYOffset;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1029,8 +959,8 @@ public final class MotionEvent implements Parcelable {
|
||||
* @see #getPressure
|
||||
*/
|
||||
public final float getHistoricalPressure(int pointerIndex, int pos) {
|
||||
return mDataSamples[((pos + 1) * NUM_SAMPLE_DATA * mNumPointers)
|
||||
+ (pointerIndex * NUM_SAMPLE_DATA) + SAMPLE_PRESSURE];
|
||||
return mDataSamples[(pos * mNumPointers + pointerIndex)
|
||||
* NUM_SAMPLE_DATA + SAMPLE_PRESSURE];
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1047,8 +977,8 @@ public final class MotionEvent implements Parcelable {
|
||||
* @see #getSize
|
||||
*/
|
||||
public final float getHistoricalSize(int pointerIndex, int pos) {
|
||||
return mDataSamples[((pos + 1) * NUM_SAMPLE_DATA * mNumPointers)
|
||||
+ (pointerIndex * NUM_SAMPLE_DATA) + SAMPLE_SIZE];
|
||||
return mDataSamples[(pos * mNumPointers + pointerIndex)
|
||||
* 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.
|
||||
*/
|
||||
public final void offsetLocation(float deltaX, float deltaY) {
|
||||
final int N = mNumPointers*mNumSamples*4;
|
||||
final float[] pos = mDataSamples;
|
||||
for (int i=0; i<N; i+=NUM_SAMPLE_DATA) {
|
||||
pos[i+SAMPLE_X] += deltaX;
|
||||
pos[i+SAMPLE_Y] += deltaY;
|
||||
}
|
||||
mXOffset += deltaX;
|
||||
mYOffset += deltaY;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1114,11 +1040,28 @@ public final class MotionEvent implements Parcelable {
|
||||
* @param y New absolute Y location.
|
||||
*/
|
||||
public final void setLocation(float x, float y) {
|
||||
float deltaX = x-mDataSamples[SAMPLE_X];
|
||||
float deltaY = y-mDataSamples[SAMPLE_Y];
|
||||
if (deltaX != 0 || deltaY != 0) {
|
||||
offsetLocation(deltaX, deltaY);
|
||||
mXOffset = x - mDataSamples[mLastDataSampleIndex + SAMPLE_X];
|
||||
mYOffset = y - mDataSamples[mLastDataSampleIndex + SAMPLE_Y];
|
||||
}
|
||||
|
||||
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,
|
||||
float pressure, float size, int metaState) {
|
||||
float[] data = mDataSamples;
|
||||
long[] times = mTimeSamples;
|
||||
incrementNumSamplesAndReserveStorage(NUM_SAMPLE_DATA);
|
||||
|
||||
final int NP = mNumPointers;
|
||||
final int NS = mNumSamples;
|
||||
final int NI = NP*NS;
|
||||
final int ND = NI * NUM_SAMPLE_DATA;
|
||||
if (data.length <= ND) {
|
||||
final int NEW_ND = ND + (NP * (BASE_AVAIL_SAMPLES * NUM_SAMPLE_DATA));
|
||||
float[] newData = new float[NEW_ND];
|
||||
System.arraycopy(data, 0, newData, 0, ND);
|
||||
mDataSamples = data = newData;
|
||||
}
|
||||
if (times.length <= NS) {
|
||||
final int NEW_NS = NS + BASE_AVAIL_SAMPLES;
|
||||
long[] newHistoryTimes = new long[NEW_NS];
|
||||
System.arraycopy(times, 0, newHistoryTimes, 0, NS);
|
||||
mTimeSamples = times = newHistoryTimes;
|
||||
}
|
||||
mEventTimeNanoSamples[mLastEventTimeNanoSampleIndex] = eventTime * MS_PER_NS;
|
||||
|
||||
times[NS] = times[0];
|
||||
times[0] = eventTime;
|
||||
float[] dataSamples = mDataSamples;
|
||||
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;
|
||||
}
|
||||
|
||||
@ -1187,48 +1104,36 @@ public final class MotionEvent implements Parcelable {
|
||||
* @hide
|
||||
*/
|
||||
public final void addBatch(long eventTime, float[] inData, int metaState) {
|
||||
float[] data = mDataSamples;
|
||||
long[] times = mTimeSamples;
|
||||
final int numPointers = mNumPointers;
|
||||
final int dataSampleStride = numPointers * NUM_SAMPLE_DATA;
|
||||
incrementNumSamplesAndReserveStorage(dataSampleStride);
|
||||
|
||||
final int NP = mNumPointers;
|
||||
final int NS = mNumSamples;
|
||||
final int NI = NP*NS;
|
||||
final int ND = NI * NUM_SAMPLE_DATA;
|
||||
if (data.length < (ND+(NP*NUM_SAMPLE_DATA))) {
|
||||
final int NEW_ND = ND + (NP * (BASE_AVAIL_SAMPLES * NUM_SAMPLE_DATA));
|
||||
float[] newData = new float[NEW_ND];
|
||||
System.arraycopy(data, 0, newData, 0, ND);
|
||||
mDataSamples = data = newData;
|
||||
}
|
||||
if (times.length < (NS+1)) {
|
||||
final int NEW_NS = NS + BASE_AVAIL_SAMPLES;
|
||||
long[] newHistoryTimes = new long[NEW_NS];
|
||||
System.arraycopy(times, 0, newHistoryTimes, 0, NS);
|
||||
mTimeSamples = times = newHistoryTimes;
|
||||
}
|
||||
mEventTimeNanoSamples[mLastEventTimeNanoSampleIndex] = eventTime * MS_PER_NS;
|
||||
|
||||
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;
|
||||
float[] dataSamples = mDataSamples;
|
||||
System.arraycopy(inData, 0, dataSamples, mLastDataSampleIndex, dataSampleStride);
|
||||
|
||||
mRawX = inData[SAMPLE_X];
|
||||
mRawY = inData[SAMPLE_Y];
|
||||
if (mXOffset != 0 || mYOffset != 0) {
|
||||
int index = mLastEventTimeNanoSampleIndex;
|
||||
for (int i = 0; i < numPointers; i++) {
|
||||
dataSamples[index + SAMPLE_X] -= mXOffset;
|
||||
dataSamples[index + SAMPLE_Y] -= mYOffset;
|
||||
index += NUM_SAMPLE_DATA;
|
||||
}
|
||||
}
|
||||
|
||||
mMetaState |= metaState;
|
||||
|
||||
if (DEBUG_POINTERS) {
|
||||
StringBuilder sb = new StringBuilder(128);
|
||||
sb.append("Add:");
|
||||
for (int i=0; i<mNumPointers; i++) {
|
||||
for (int i = 0; i < mNumPointers; i++) {
|
||||
sb.append(" #");
|
||||
sb.append(mPointerIdentifiers[i]);
|
||||
sb.append(getPointerId(i));
|
||||
sb.append("(");
|
||||
sb.append(mDataSamples[(i*NUM_SAMPLE_DATA) + SAMPLE_X]);
|
||||
sb.append(getX(i));
|
||||
sb.append(",");
|
||||
sb.append(mDataSamples[(i*NUM_SAMPLE_DATA) + SAMPLE_Y]);
|
||||
sb.append(getY(i));
|
||||
sb.append(")");
|
||||
}
|
||||
Log.v("MotionEvent", sb.toString());
|
||||
@ -1245,8 +1150,41 @@ public final class MotionEvent implements Parcelable {
|
||||
public static final Parcelable.Creator<MotionEvent> CREATOR
|
||||
= new Parcelable.Creator<MotionEvent>() {
|
||||
public MotionEvent createFromParcel(Parcel in) {
|
||||
MotionEvent ev = obtain();
|
||||
ev.readFromParcel(in);
|
||||
final int NP = in.readInt();
|
||||
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;
|
||||
}
|
||||
|
||||
@ -1260,79 +1198,36 @@ public final class MotionEvent implements Parcelable {
|
||||
}
|
||||
|
||||
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;
|
||||
out.writeInt(NP);
|
||||
final int NS = mNumSamples;
|
||||
final int NI = NP * NS * NUM_SAMPLE_DATA;
|
||||
|
||||
out.writeInt(NP);
|
||||
out.writeInt(NS);
|
||||
final int NI = NP*NS;
|
||||
if (NI > 0) {
|
||||
int i;
|
||||
int[] state = mPointerIdentifiers;
|
||||
for (i=0; i<NP; i++) {
|
||||
out.writeInt(state[i]);
|
||||
}
|
||||
final int ND = NI*NUM_SAMPLE_DATA;
|
||||
float[] history = mDataSamples;
|
||||
for (i=0; i<ND; i++) {
|
||||
out.writeFloat(history[i]);
|
||||
}
|
||||
long[] times = mTimeSamples;
|
||||
for (i=0; i<NS; i++) {
|
||||
out.writeLong(times[i]);
|
||||
}
|
||||
}
|
||||
|
||||
out.writeLong(mDownTimeNano);
|
||||
out.writeInt(mAction);
|
||||
out.writeFloat(mXOffset);
|
||||
out.writeFloat(mYOffset);
|
||||
out.writeFloat(mXPrecision);
|
||||
out.writeFloat(mYPrecision);
|
||||
out.writeInt(mDeviceId);
|
||||
out.writeInt(mEdgeFlags);
|
||||
}
|
||||
|
||||
private void readFromParcel(Parcel in) {
|
||||
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++) {
|
||||
ids[i] = in.readInt();
|
||||
}
|
||||
float[] history = mDataSamples;
|
||||
final int ND = NI*NUM_SAMPLE_DATA;
|
||||
if (history.length < ND) {
|
||||
mDataSamples = history = new float[ND];
|
||||
}
|
||||
for (int i=0; i<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();
|
||||
}
|
||||
out.writeInt(mMetaState);
|
||||
|
||||
final int[] pointerIdentifiers = mPointerIdentifiers;
|
||||
for (int i = 0; i < NP; i++) {
|
||||
out.writeInt(pointerIdentifiers[i]);
|
||||
}
|
||||
|
||||
final long[] eventTimeNanoSamples = mEventTimeNanoSamples;
|
||||
for (int i = 0; i < NS; i++) {
|
||||
out.writeLong(eventTimeNanoSamples[i]);
|
||||
}
|
||||
mXPrecision = in.readFloat();
|
||||
mYPrecision = in.readFloat();
|
||||
mDeviceId = in.readInt();
|
||||
mEdgeFlags = in.readInt();
|
||||
}
|
||||
|
||||
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);
|
||||
env->ReleaseStringUTFChars(nameObj, nameChars);
|
||||
|
||||
InputChannel* serverChannel;
|
||||
InputChannel* clientChannel;
|
||||
status_t result = InputChannel::openInputChannelPair(name, & serverChannel, & clientChannel);
|
||||
sp<InputChannel> serverChannel;
|
||||
sp<InputChannel> clientChannel;
|
||||
status_t result = InputChannel::openInputChannelPair(name, serverChannel, clientChannel);
|
||||
|
||||
if (result) {
|
||||
LOGE("Could not open input channel pair. status=%d", result);
|
||||
|
@ -36,11 +36,10 @@ static struct {
|
||||
jmethodID obtain;
|
||||
jmethodID recycle;
|
||||
|
||||
jfieldID mDownTime;
|
||||
jfieldID mEventTimeNano;
|
||||
jfieldID mDownTimeNano;
|
||||
jfieldID mAction;
|
||||
jfieldID mRawX;
|
||||
jfieldID mRawY;
|
||||
jfieldID mXOffset;
|
||||
jfieldID mYOffset;
|
||||
jfieldID mXPrecision;
|
||||
jfieldID mYPrecision;
|
||||
jfieldID mDeviceId;
|
||||
@ -50,7 +49,9 @@ static struct {
|
||||
jfieldID mNumSamples;
|
||||
jfieldID mPointerIdentifiers;
|
||||
jfieldID mDataSamples;
|
||||
jfieldID mTimeSamples;
|
||||
jfieldID mEventTimeNanoSamples;
|
||||
jfieldID mLastDataSampleIndex;
|
||||
jfieldID mLastEventTimeNanoSampleIndex;
|
||||
} gMotionEventClassInfo;
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
@ -69,22 +70,14 @@ jobject android_view_MotionEvent_fromNative(JNIEnv* env, const MotionEvent* even
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// MotionEvent.mEventTimeNano is the time of the oldest sample because
|
||||
// MotionEvent.addBatch does not update it as successive samples are added.
|
||||
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->SetLongField(eventObj, gMotionEventClassInfo.mDownTimeNano,
|
||||
event->getDownTime());
|
||||
env->SetIntField(eventObj, gMotionEventClassInfo.mAction,
|
||||
event->getAction());
|
||||
env->SetFloatField(eventObj, gMotionEventClassInfo.mRawX,
|
||||
event->getRawX());
|
||||
env->SetFloatField(eventObj, gMotionEventClassInfo.mRawY,
|
||||
event->getRawY());
|
||||
env->SetFloatField(eventObj, gMotionEventClassInfo.mXOffset,
|
||||
event->getXOffset());
|
||||
env->SetFloatField(eventObj, gMotionEventClassInfo.mYOffset,
|
||||
event->getYOffset());
|
||||
env->SetFloatField(eventObj, gMotionEventClassInfo.mXPrecision,
|
||||
event->getXPrecision());
|
||||
env->SetFloatField(eventObj, gMotionEventClassInfo.mYPrecision,
|
||||
@ -99,65 +92,62 @@ jobject android_view_MotionEvent_fromNative(JNIEnv* env, const MotionEvent* even
|
||||
numPointers);
|
||||
env->SetIntField(eventObj, gMotionEventClassInfo.mNumSamples,
|
||||
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,
|
||||
gMotionEventClassInfo.mPointerIdentifiers));
|
||||
jfloatArray dataSampleArray = jfloatArray(env->GetObjectField(eventObj,
|
||||
gMotionEventClassInfo.mDataSamples));
|
||||
jlongArray timeSampleArray = jlongArray(env->GetObjectField(eventObj,
|
||||
gMotionEventClassInfo.mTimeSamples));
|
||||
jlongArray eventTimeNanoSampleArray = jlongArray(env->GetObjectField(eventObj,
|
||||
gMotionEventClassInfo.mEventTimeNanoSamples));
|
||||
|
||||
jint* pointerIdentifiers = (jint*)env->GetPrimitiveArrayCritical(pointerIdentifierArray, 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++) {
|
||||
pointerIdentifiers[i] = event->getPointerId(i);
|
||||
*(destPointerIdentifiers++) = *(srcPointerIdentifiers++);
|
||||
}
|
||||
|
||||
// Most recent data is in first slot of the DVM array, followed by the oldest,
|
||||
// and then all others are in order.
|
||||
|
||||
jfloat* currentDataSample = dataSamples;
|
||||
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);
|
||||
const nsecs_t* srcSampleEventTimes = event->getSampleEventTimes();
|
||||
jlong* destEventTimeNanoSamples = eventTimeNanoSamples;
|
||||
for (jint i = 0; i < numSamples; i++) {
|
||||
*(destEventTimeNanoSamples++) = *(srcSampleEventTimes++);
|
||||
}
|
||||
|
||||
for (jint i = 0; i < numHistoricalSamples; i++) {
|
||||
*(currentTimeSample++) = nanoseconds_to_milliseconds(event->getHistoricalEventTime(i));
|
||||
for (jint j = 0; j < numPointers; j++) {
|
||||
*(currentDataSample++) = event->getHistoricalX(j, i);
|
||||
*(currentDataSample++) = event->getHistoricalY(j, i);
|
||||
*(currentDataSample++) = event->getHistoricalPressure(j, i);
|
||||
*(currentDataSample++) = event->getHistoricalSize(j, i);
|
||||
}
|
||||
const PointerCoords* srcSamplePointerCoords = event->getSamplePointerCoords();
|
||||
jfloat* destDataSamples = dataSamples;
|
||||
jint numItems = numSamples * numPointers;
|
||||
for (jint i = 0; i < numItems; i++) {
|
||||
*(destDataSamples++) = srcSamplePointerCoords->x;
|
||||
*(destDataSamples++) = srcSamplePointerCoords->y;
|
||||
*(destDataSamples++) = srcSamplePointerCoords->pressure;
|
||||
*(destDataSamples++) = srcSamplePointerCoords->size;
|
||||
srcSamplePointerCoords += 1;
|
||||
}
|
||||
|
||||
env->ReleasePrimitiveArrayCritical(pointerIdentifierArray, pointerIdentifiers, 0);
|
||||
env->ReleasePrimitiveArrayCritical(dataSampleArray, dataSamples, 0);
|
||||
env->ReleasePrimitiveArrayCritical(timeSampleArray, timeSamples, 0);
|
||||
env->ReleasePrimitiveArrayCritical(eventTimeNanoSampleArray, eventTimeNanoSamples, 0);
|
||||
|
||||
env->DeleteLocalRef(pointerIdentifierArray);
|
||||
env->DeleteLocalRef(dataSampleArray);
|
||||
env->DeleteLocalRef(timeSampleArray);
|
||||
env->DeleteLocalRef(eventTimeNanoSampleArray);
|
||||
return eventObj;
|
||||
}
|
||||
|
||||
void android_view_MotionEvent_toNative(JNIEnv* env, jobject eventObj, int32_t nature,
|
||||
MotionEvent* event) {
|
||||
// MotionEvent.mEventTimeNano is the time of the oldest sample because
|
||||
// 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);
|
||||
jlong downTimeNano = env->GetLongField(eventObj, gMotionEventClassInfo.mDownTimeNano);
|
||||
jint action = env->GetIntField(eventObj, gMotionEventClassInfo.mAction);
|
||||
jfloat rawX = env->GetFloatField(eventObj, gMotionEventClassInfo.mRawX);
|
||||
jfloat rawY = env->GetFloatField(eventObj, gMotionEventClassInfo.mRawY);
|
||||
jfloat xOffset = env->GetFloatField(eventObj, gMotionEventClassInfo.mXOffset);
|
||||
jfloat yOffset = env->GetFloatField(eventObj, gMotionEventClassInfo.mYOffset);
|
||||
jfloat xPrecision = env->GetFloatField(eventObj, gMotionEventClassInfo.mXPrecision);
|
||||
jfloat yPrecision = env->GetFloatField(eventObj, gMotionEventClassInfo.mYPrecision);
|
||||
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));
|
||||
jfloatArray dataSampleArray = jfloatArray(env->GetObjectField(eventObj,
|
||||
gMotionEventClassInfo.mDataSamples));
|
||||
jlongArray timeSampleArray = jlongArray(env->GetObjectField(eventObj,
|
||||
gMotionEventClassInfo.mTimeSamples));
|
||||
jlongArray eventTimeNanoSampleArray = jlongArray(env->GetObjectField(eventObj,
|
||||
gMotionEventClassInfo.mEventTimeNanoSamples));
|
||||
|
||||
LOG_FATAL_IF(numPointers == 0, "numPointers was zero");
|
||||
LOG_FATAL_IF(numSamples == 0, "numSamples was zero");
|
||||
|
||||
jint* pointerIdentifiers = (jint*)env->GetPrimitiveArrayCritical(pointerIdentifierArray, 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,
|
||||
// and then all others are in order. eventTimeNano is the time of the oldest sample
|
||||
// since MotionEvent.addBatch does not update it.
|
||||
jfloat* srcDataSamples = dataSamples;
|
||||
jlong* srcEventTimeNanoSamples = eventTimeNanoSamples;
|
||||
|
||||
jint numHistoricalSamples = numSamples - 1;
|
||||
jint dataSampleStride = numPointers * NUM_SAMPLE_DATA;
|
||||
|
||||
const jfloat* currentDataSample;
|
||||
const jlong* currentTimeSample;
|
||||
if (numHistoricalSamples == 0) {
|
||||
currentDataSample = dataSamples;
|
||||
currentTimeSample = timeSamples;
|
||||
} else {
|
||||
currentDataSample = dataSamples + dataSampleStride;
|
||||
currentTimeSample = timeSamples + 1;
|
||||
}
|
||||
|
||||
PointerCoords pointerCoords[MAX_POINTERS];
|
||||
jlong sampleEventTime = *(srcEventTimeNanoSamples++);
|
||||
PointerCoords samplePointerCoords[MAX_POINTERS];
|
||||
for (jint j = 0; j < numPointers; j++) {
|
||||
pointerCoords[j].x = *(currentDataSample++);
|
||||
pointerCoords[j].y = *(currentDataSample++);
|
||||
pointerCoords[j].pressure = *(currentDataSample++);
|
||||
pointerCoords[j].size = *(currentDataSample++);
|
||||
samplePointerCoords[j].x = *(srcDataSamples++);
|
||||
samplePointerCoords[j].y = *(srcDataSamples++);
|
||||
samplePointerCoords[j].pressure = *(srcDataSamples++);
|
||||
samplePointerCoords[j].size = *(srcDataSamples++);
|
||||
}
|
||||
|
||||
event->initialize(deviceId, nature, action, edgeFlags, metaState,
|
||||
rawX, rawY, xPrecision, yPrecision,
|
||||
milliseconds_to_nanoseconds(downTime), eventTimeNano,
|
||||
numPointers, pointerIdentifiers, pointerCoords);
|
||||
|
||||
while (numHistoricalSamples > 0) {
|
||||
numHistoricalSamples -= 1;
|
||||
if (numHistoricalSamples == 0) {
|
||||
currentDataSample = dataSamples;
|
||||
currentTimeSample = timeSamples;
|
||||
}
|
||||
|
||||
nsecs_t sampleEventTime = milliseconds_to_nanoseconds(*(currentTimeSample++));
|
||||
xOffset, yOffset, xPrecision, yPrecision, downTimeNano, sampleEventTime,
|
||||
numPointers, pointerIdentifiers, samplePointerCoords);
|
||||
|
||||
for (jint i = 1; i < numSamples; i++) {
|
||||
sampleEventTime = *(srcEventTimeNanoSamples++);
|
||||
for (jint j = 0; j < numPointers; j++) {
|
||||
pointerCoords[j].x = *(currentDataSample++);
|
||||
pointerCoords[j].y = *(currentDataSample++);
|
||||
pointerCoords[j].pressure = *(currentDataSample++);
|
||||
pointerCoords[j].size = *(currentDataSample++);
|
||||
samplePointerCoords[j].x = *(srcDataSamples++);
|
||||
samplePointerCoords[j].y = *(srcDataSamples++);
|
||||
samplePointerCoords[j].pressure = *(srcDataSamples++);
|
||||
samplePointerCoords[j].size = *(srcDataSamples++);
|
||||
}
|
||||
|
||||
event->addSample(sampleEventTime, pointerCoords);
|
||||
event->addSample(sampleEventTime, samplePointerCoords);
|
||||
}
|
||||
|
||||
env->ReleasePrimitiveArrayCritical(pointerIdentifierArray, pointerIdentifiers, 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(dataSampleArray);
|
||||
env->DeleteLocalRef(timeSampleArray);
|
||||
env->DeleteLocalRef(eventTimeNanoSampleArray);
|
||||
}
|
||||
|
||||
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,
|
||||
"recycle", "()V");
|
||||
|
||||
GET_FIELD_ID(gMotionEventClassInfo.mDownTime, gMotionEventClassInfo.clazz,
|
||||
"mDownTime", "J");
|
||||
GET_FIELD_ID(gMotionEventClassInfo.mEventTimeNano, gMotionEventClassInfo.clazz,
|
||||
"mEventTimeNano", "J");
|
||||
GET_FIELD_ID(gMotionEventClassInfo.mDownTimeNano, gMotionEventClassInfo.clazz,
|
||||
"mDownTimeNano", "J");
|
||||
GET_FIELD_ID(gMotionEventClassInfo.mAction, gMotionEventClassInfo.clazz,
|
||||
"mAction", "I");
|
||||
GET_FIELD_ID(gMotionEventClassInfo.mRawX, gMotionEventClassInfo.clazz,
|
||||
"mRawX", "F");
|
||||
GET_FIELD_ID(gMotionEventClassInfo.mRawY, gMotionEventClassInfo.clazz,
|
||||
"mRawY", "F");
|
||||
GET_FIELD_ID(gMotionEventClassInfo.mXOffset, gMotionEventClassInfo.clazz,
|
||||
"mXOffset", "F");
|
||||
GET_FIELD_ID(gMotionEventClassInfo.mYOffset, gMotionEventClassInfo.clazz,
|
||||
"mYOffset", "F");
|
||||
GET_FIELD_ID(gMotionEventClassInfo.mXPrecision, gMotionEventClassInfo.clazz,
|
||||
"mXPrecision", "F");
|
||||
GET_FIELD_ID(gMotionEventClassInfo.mYPrecision, gMotionEventClassInfo.clazz,
|
||||
@ -301,8 +268,12 @@ int register_android_view_MotionEvent(JNIEnv* env) {
|
||||
"mPointerIdentifiers", "[I");
|
||||
GET_FIELD_ID(gMotionEventClassInfo.mDataSamples, gMotionEventClassInfo.clazz,
|
||||
"mDataSamples", "[F");
|
||||
GET_FIELD_ID(gMotionEventClassInfo.mTimeSamples, gMotionEventClassInfo.clazz,
|
||||
"mTimeSamples", "[J");
|
||||
GET_FIELD_ID(gMotionEventClassInfo.mEventTimeNanoSamples, gMotionEventClassInfo.clazz,
|
||||
"mEventTimeNanoSamples", "[J");
|
||||
GET_FIELD_ID(gMotionEventClassInfo.mLastDataSampleIndex, gMotionEventClassInfo.clazz,
|
||||
"mLastDataSampleIndex", "I");
|
||||
GET_FIELD_ID(gMotionEventClassInfo.mLastEventTimeNanoSampleIndex, gMotionEventClassInfo.clazz,
|
||||
"mLastEventTimeNanoSampleIndex", "I");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -148,6 +148,9 @@ private:
|
||||
int32_t mNature;
|
||||
};
|
||||
|
||||
/*
|
||||
* Key events.
|
||||
*/
|
||||
class KeyEvent : public InputEvent {
|
||||
public:
|
||||
virtual ~KeyEvent() { }
|
||||
@ -193,6 +196,9 @@ private:
|
||||
nsecs_t mEventTime;
|
||||
};
|
||||
|
||||
/*
|
||||
* Motion events.
|
||||
*/
|
||||
class MotionEvent : public InputEvent {
|
||||
public:
|
||||
virtual ~MotionEvent() { }
|
||||
@ -205,6 +211,10 @@ public:
|
||||
|
||||
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 getYPrecision() const { return mYPrecision; }
|
||||
@ -217,18 +227,22 @@ public:
|
||||
|
||||
inline nsecs_t getEventTime() const { return mSampleEventTimes[getHistorySize()]; }
|
||||
|
||||
inline float getRawX() const { return mRawX; }
|
||||
|
||||
inline float getRawY() const { return mRawY; }
|
||||
|
||||
inline float getX(size_t pointerIndex) const {
|
||||
inline float getRawX(size_t pointerIndex) const {
|
||||
return getCurrentPointerCoords(pointerIndex).x;
|
||||
}
|
||||
|
||||
inline float getY(size_t pointerIndex) const {
|
||||
inline float getRawY(size_t pointerIndex) const {
|
||||
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 {
|
||||
return getCurrentPointerCoords(pointerIndex).pressure;
|
||||
}
|
||||
@ -243,14 +257,22 @@ public:
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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 {
|
||||
return getHistoricalPointerCoords(pointerIndex, historicalIndex).pressure;
|
||||
}
|
||||
@ -265,8 +287,8 @@ public:
|
||||
int32_t action,
|
||||
int32_t edgeFlags,
|
||||
int32_t metaState,
|
||||
float rawX,
|
||||
float rawY,
|
||||
float xOffset,
|
||||
float yOffset,
|
||||
float xPrecision,
|
||||
float yPrecision,
|
||||
nsecs_t downTime,
|
||||
@ -281,12 +303,19 @@ public:
|
||||
|
||||
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:
|
||||
int32_t mAction;
|
||||
int32_t mEdgeFlags;
|
||||
int32_t mMetaState;
|
||||
float mRawX;
|
||||
float mRawY;
|
||||
float mXOffset;
|
||||
float mYOffset;
|
||||
float mXPrecision;
|
||||
float mYPrecision;
|
||||
nsecs_t mDownTime;
|
||||
|
@ -62,7 +62,7 @@ public:
|
||||
* Returns OK on success.
|
||||
*/
|
||||
static status_t openInputChannelPair(const String8& name,
|
||||
InputChannel** outServerChannel, InputChannel** outClientChannel);
|
||||
sp<InputChannel>& outServerChannel, sp<InputChannel>& outClientChannel);
|
||||
|
||||
inline String8 getName() const { return mName; }
|
||||
inline int32_t getAshmemFd() const { return mAshmemFd; }
|
||||
@ -72,7 +72,8 @@ public:
|
||||
/* Sends a signal to the other endpoint.
|
||||
*
|
||||
* 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);
|
||||
|
||||
@ -81,6 +82,7 @@ public:
|
||||
*
|
||||
* Returns OK on success.
|
||||
* 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.
|
||||
*/
|
||||
status_t receiveSignal(char* outSignal);
|
||||
@ -298,7 +300,7 @@ public:
|
||||
* Returns INVALID_OPERATION if there is no currently published event.
|
||||
* 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
|
||||
* finished processing.
|
||||
|
@ -114,8 +114,10 @@ private:
|
||||
};
|
||||
|
||||
Mutex mLock;
|
||||
Condition mAwake;
|
||||
bool mPolling;
|
||||
uint32_t mWaiters;
|
||||
Condition mAwake;
|
||||
Condition mResume;
|
||||
|
||||
int mWakeReadPipeFd;
|
||||
int mWakeWritePipeFd;
|
||||
|
@ -115,10 +115,10 @@ public:
|
||||
|
||||
|
||||
//! 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
|
||||
ssize_t appendArray(const TYPE* array, size_t numItems);
|
||||
ssize_t appendArray(const TYPE* array, size_t length);
|
||||
|
||||
/*!
|
||||
* add/insert/replace items
|
||||
@ -126,7 +126,7 @@ public:
|
||||
|
||||
//! insert one or several items initialized with their default constructor
|
||||
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);
|
||||
//! pop the top of the stack (removes the last element). No-op if the stack's empty
|
||||
inline void pop();
|
||||
@ -265,13 +265,13 @@ ssize_t Vector<TYPE>::appendVector(const Vector<TYPE>& vector) {
|
||||
}
|
||||
|
||||
template<class TYPE> inline
|
||||
ssize_t Vector<TYPE>::insertArrayAt(const TYPE* array, size_t index, size_t numItems) {
|
||||
return VectorImpl::insertAt(array, index, numItems);
|
||||
ssize_t Vector<TYPE>::insertArrayAt(const TYPE* array, size_t index, size_t length) {
|
||||
return VectorImpl::insertArrayAt(array, index, length);
|
||||
}
|
||||
|
||||
template<class TYPE> inline
|
||||
ssize_t Vector<TYPE>::appendArray(const TYPE* array, size_t numItems) {
|
||||
return VectorImpl::add(array, numItems);
|
||||
ssize_t Vector<TYPE>::appendArray(const TYPE* array, size_t length) {
|
||||
return VectorImpl::appendArray(array, length);
|
||||
}
|
||||
|
||||
template<class TYPE> inline
|
||||
|
@ -65,9 +65,11 @@ public:
|
||||
size_t capacity() const;
|
||||
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 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 */
|
||||
ssize_t insertAt(size_t where, size_t numItems = 1);
|
||||
@ -76,7 +78,7 @@ public:
|
||||
void push();
|
||||
void push(const void* item);
|
||||
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(const void* item, size_t index);
|
||||
|
||||
@ -184,8 +186,8 @@ private:
|
||||
void push(const void* item);
|
||||
ssize_t insertVectorAt(const VectorImpl& vector, size_t index);
|
||||
ssize_t appendVector(const VectorImpl& vector);
|
||||
ssize_t insertArrayAt(const void* array, size_t index, size_t numItems);
|
||||
ssize_t appendArray(const void* array, size_t numItems);
|
||||
ssize_t insertArrayAt(const void* array, size_t index, size_t length);
|
||||
ssize_t appendArray(const void* array, size_t length);
|
||||
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 replaceAt(size_t index);
|
||||
|
@ -50,8 +50,8 @@ void MotionEvent::initialize(
|
||||
int32_t action,
|
||||
int32_t edgeFlags,
|
||||
int32_t metaState,
|
||||
float rawX,
|
||||
float rawY,
|
||||
float xOffset,
|
||||
float yOffset,
|
||||
float xPrecision,
|
||||
float yPrecision,
|
||||
nsecs_t downTime,
|
||||
@ -63,8 +63,8 @@ void MotionEvent::initialize(
|
||||
mAction = action;
|
||||
mEdgeFlags = edgeFlags;
|
||||
mMetaState = metaState;
|
||||
mRawX = rawX;
|
||||
mRawY = rawY;
|
||||
mXOffset = xOffset;
|
||||
mYOffset = yOffset;
|
||||
mXPrecision = xPrecision;
|
||||
mYPrecision = yPrecision;
|
||||
mDownTime = downTime;
|
||||
@ -83,13 +83,8 @@ void MotionEvent::addSample(
|
||||
}
|
||||
|
||||
void MotionEvent::offsetLocation(float xOffset, float yOffset) {
|
||||
if (xOffset != 0 || yOffset != 0) {
|
||||
for (size_t i = 0; i < mSamplePointerCoords.size(); i++) {
|
||||
PointerCoords& pointerCoords = mSamplePointerCoords.editItemAt(i);
|
||||
pointerCoords.x += xOffset;
|
||||
pointerCoords.y += yOffset;
|
||||
}
|
||||
}
|
||||
mXOffset += xOffset;
|
||||
mYOffset += yOffset;
|
||||
}
|
||||
|
||||
} // 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();
|
||||
}
|
||||
|
||||
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) {
|
||||
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);
|
||||
}
|
||||
|
||||
float motion_event_get_raw_x(const input_event_t* motion_event) {
|
||||
return reinterpret_cast<const MotionEvent*>(motion_event)->getRawX();
|
||||
float motion_event_get_raw_x(const input_event_t* motion_event, size_t pointer_index) {
|
||||
return reinterpret_cast<const MotionEvent*>(motion_event)->getRawX(pointer_index);
|
||||
}
|
||||
|
||||
float motion_event_get_raw_y(const input_event_t* motion_event) {
|
||||
return reinterpret_cast<const MotionEvent*>(motion_event)->getRawY();
|
||||
float motion_event_get_raw_y(const input_event_t* motion_event, size_t pointer_index) {
|
||||
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) {
|
||||
@ -213,6 +216,18 @@ int64_t motion_event_get_historical_event_time(input_event_t* motion_event,
|
||||
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,
|
||||
size_t history_index) {
|
||||
return reinterpret_cast<const MotionEvent*>(motion_event)->getHistoricalX(
|
||||
|
@ -379,8 +379,7 @@ void InputDispatcher::identifyInputTargetsAndDispatchMotionLockedInterruptible(
|
||||
|
||||
mReusableMotionEvent.initialize(entry->deviceId, entry->nature, entry->action,
|
||||
entry->edgeFlags, entry->metaState,
|
||||
entry->firstSample.pointerCoords[0].x, entry->firstSample.pointerCoords[0].y,
|
||||
entry->xPrecision, entry->yPrecision,
|
||||
0, 0, entry->xPrecision, entry->yPrecision,
|
||||
entry->downTime, entry->eventTime, entry->pointerCount, entry->pointerIds,
|
||||
entry->firstSample.pointerCoords);
|
||||
|
||||
|
@ -19,6 +19,9 @@
|
||||
// Log debug messages about pointers.
|
||||
#define DEBUG_POINTERS 1
|
||||
|
||||
// Log debug messages about pointer assignment calculations.
|
||||
#define DEBUG_POINTER_ASSIGNMENT 0
|
||||
|
||||
#include <cutils/log.h>
|
||||
#include <ui/InputReader.h>
|
||||
|
||||
@ -57,6 +60,14 @@ inline static T min(const T& a, const T& 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 mask;
|
||||
switch (keyCode) {
|
||||
@ -188,6 +199,12 @@ void InputDevice::TouchScreenState::reset() {
|
||||
jumpyTouchFilter.jumpyPointsDropped = 0;
|
||||
}
|
||||
|
||||
struct PointerDistanceHeapElement {
|
||||
uint32_t currentPointerIndex : 8;
|
||||
uint32_t lastPointerIndex : 8;
|
||||
uint64_t distance : 48; // squared distance
|
||||
};
|
||||
|
||||
void InputDevice::TouchScreenState::calculatePointerIds() {
|
||||
uint32_t currentPointerCount = currentTouch.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
|
||||
// associated with the current and last pointer indices. Then, we find the best
|
||||
// match (by distance) for each current pointer.
|
||||
struct {
|
||||
uint32_t currentPointerIndex : 8;
|
||||
uint32_t lastPointerIndex : 8;
|
||||
uint64_t distance : 48; // squared distance
|
||||
} heap[MAX_POINTERS * MAX_POINTERS];
|
||||
PointerDistanceHeapElement heap[MAX_POINTERS * MAX_POINTERS];
|
||||
|
||||
uint32_t heapSize = 0;
|
||||
for (uint32_t currentPointerIndex = 0; currentPointerIndex < currentPointerCount;
|
||||
@ -233,23 +246,45 @@ void InputDevice::TouchScreenState::calculatePointerIds() {
|
||||
uint64_t distance = uint64_t(deltaX * deltaX + deltaY * deltaY);
|
||||
|
||||
// Insert new element into the heap (sift up).
|
||||
heap[heapSize].currentPointerIndex = currentPointerIndex;
|
||||
heap[heapSize].lastPointerIndex = lastPointerIndex;
|
||||
heap[heapSize].distance = distance;
|
||||
heapSize += 1;
|
||||
uint32_t insertionIndex = heapSize;
|
||||
while (insertionIndex > 1) {
|
||||
uint32_t parentIndex = (insertionIndex - 1) / 2;
|
||||
if (distance < heap[parentIndex].distance) {
|
||||
heap[insertionIndex] = heap[parentIndex];
|
||||
insertionIndex = parentIndex;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
heap[insertionIndex].currentPointerIndex = currentPointerIndex;
|
||||
heap[insertionIndex].lastPointerIndex = lastPointerIndex;
|
||||
heap[insertionIndex].distance = distance;
|
||||
}
|
||||
}
|
||||
|
||||
// Heapify
|
||||
for (uint32_t startIndex = heapSize / 2; startIndex != 0; ) {
|
||||
startIndex -= 1;
|
||||
for (uint32_t parentIndex = startIndex; ;) {
|
||||
uint32_t childIndex = parentIndex * 2 + 1;
|
||||
if (childIndex >= heapSize) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (childIndex + 1 < heapSize
|
||||
&& heap[childIndex + 1].distance < heap[childIndex].distance) {
|
||||
childIndex += 1;
|
||||
}
|
||||
|
||||
if (heap[parentIndex].distance <= heap[childIndex].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.
|
||||
// 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.
|
||||
@ -262,7 +297,7 @@ void InputDevice::TouchScreenState::calculatePointerIds() {
|
||||
for (;;) {
|
||||
if (first) {
|
||||
// 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;
|
||||
} else {
|
||||
// Previous iterations consumed the root element of the heap.
|
||||
@ -270,10 +305,10 @@ void InputDevice::TouchScreenState::calculatePointerIds() {
|
||||
heapSize -= 1;
|
||||
assert(heapSize > 0);
|
||||
|
||||
// Sift down to find where the element at index heapSize needs to be moved.
|
||||
uint32_t rootIndex = 0;
|
||||
for (;;) {
|
||||
uint32_t childIndex = rootIndex * 2 + 1;
|
||||
// Sift down.
|
||||
heap[0] = heap[heapSize];
|
||||
for (uint32_t parentIndex = 0; ;) {
|
||||
uint32_t childIndex = parentIndex * 2 + 1;
|
||||
if (childIndex >= heapSize) {
|
||||
break;
|
||||
}
|
||||
@ -283,14 +318,22 @@ void InputDevice::TouchScreenState::calculatePointerIds() {
|
||||
childIndex += 1;
|
||||
}
|
||||
|
||||
if (heap[heapSize].distance < heap[childIndex].distance) {
|
||||
if (heap[parentIndex].distance <= heap[childIndex].distance) {
|
||||
break;
|
||||
}
|
||||
|
||||
heap[rootIndex] = heap[childIndex];
|
||||
rootIndex = childIndex;
|
||||
swap(heap[parentIndex], heap[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;
|
||||
@ -306,6 +349,11 @@ void InputDevice::TouchScreenState::calculatePointerIds() {
|
||||
currentTouch.pointers[currentPointerIndex].id = id;
|
||||
currentTouch.idToIndex[id] = currentPointerIndex;
|
||||
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;
|
||||
}
|
||||
}
|
||||
@ -320,6 +368,11 @@ void InputDevice::TouchScreenState::calculatePointerIds() {
|
||||
currentTouch.idToIndex[id] = currentPointerIndex;
|
||||
usedIdBits.markBit(id);
|
||||
|
||||
#if DEBUG_POINTER_ASSIGNMENT
|
||||
LOGD("calculatePointerIds - assigned: cur=%d, id=%d",
|
||||
currentPointerIndex, id);
|
||||
#endif
|
||||
|
||||
if (--i == 0) break; // done
|
||||
matchedCurrentBits.markBit(currentPointerIndex);
|
||||
}
|
||||
@ -1208,8 +1261,10 @@ bool InputReader::consumeVirtualKeyTouches(nsecs_t when,
|
||||
|
||||
int32_t x = device->touchScreen.currentTouch.pointers[0].x;
|
||||
int32_t y = device->touchScreen.currentTouch.pointers[0].y;
|
||||
if (device->touchScreen.isPointInsideDisplay(x, y)) {
|
||||
// Pointer moved inside the display area. Send key cancellation.
|
||||
if (device->touchScreen.isPointInsideDisplay(x, y)
|
||||
|| 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;
|
||||
|
||||
#if DEBUG_VIRTUAL_KEYS
|
||||
@ -1227,7 +1282,7 @@ bool InputReader::consumeVirtualKeyTouches(nsecs_t when,
|
||||
device->touchScreen.lastTouch.clear();
|
||||
return false; // not consumed
|
||||
}
|
||||
} else if (device->touchScreen.currentTouch.pointerCount > 0
|
||||
} else if (device->touchScreen.currentTouch.pointerCount == 1
|
||||
&& device->touchScreen.lastTouch.pointerCount == 0) {
|
||||
int32_t x = device->touchScreen.currentTouch.pointers[0].x;
|
||||
int32_t y = device->touchScreen.currentTouch.pointers[0].y;
|
||||
|
@ -8,13 +8,13 @@
|
||||
//#define LOG_NDEBUG 0
|
||||
|
||||
// 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
|
||||
#define DEBUG_CHANNEL_LIFECYCLE 1
|
||||
#define DEBUG_CHANNEL_LIFECYCLE 0
|
||||
|
||||
// Log debug messages about transport actions (initialize, reset, publish, ...)
|
||||
#define DEBUG_TRANSPORT_ACTIONS 1
|
||||
#define DEBUG_TRANSPORT_ACTIONS 0
|
||||
|
||||
|
||||
#include <cutils/ashmem.h>
|
||||
@ -70,7 +70,7 @@ InputChannel::~InputChannel() {
|
||||
}
|
||||
|
||||
status_t InputChannel::openInputChannelPair(const String8& name,
|
||||
InputChannel** outServerChannel, InputChannel** outClientChannel) {
|
||||
sp<InputChannel>& outServerChannel, sp<InputChannel>& outClientChannel) {
|
||||
status_t result;
|
||||
|
||||
int serverAshmemFd = ashmem_create_region(name.string(), DEFAULT_MESSAGE_BUFFER_SIZE);
|
||||
@ -107,12 +107,12 @@ status_t InputChannel::openInputChannelPair(const String8& name,
|
||||
} else {
|
||||
String8 serverChannelName = name;
|
||||
serverChannelName.append(" (server)");
|
||||
*outServerChannel = new InputChannel(serverChannelName,
|
||||
outServerChannel = new InputChannel(serverChannelName,
|
||||
serverAshmemFd, reverse[0], forward[1]);
|
||||
|
||||
String8 clientChannelName = name;
|
||||
clientChannelName.append(" (client)");
|
||||
*outClientChannel = new InputChannel(clientChannelName,
|
||||
outClientChannel = new InputChannel(clientChannelName,
|
||||
clientAshmemFd, forward[0], reverse[1]);
|
||||
return OK;
|
||||
}
|
||||
@ -125,8 +125,8 @@ status_t InputChannel::openInputChannelPair(const String8& name,
|
||||
::close(serverAshmemFd);
|
||||
}
|
||||
|
||||
*outServerChannel = NULL;
|
||||
*outClientChannel = NULL;
|
||||
outServerChannel.clear();
|
||||
outClientChannel.clear();
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -155,6 +155,13 @@ status_t InputChannel::receiveSignal(char* outSignal) {
|
||||
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 DEBUG_CHANNEL_SIGNALS
|
||||
LOGD("channel '%s' ~ receive signal failed because no signal available", mName.string());
|
||||
@ -535,13 +542,13 @@ status_t InputConsumer::initialize() {
|
||||
return OK;
|
||||
}
|
||||
|
||||
status_t InputConsumer::consume(InputEventFactoryInterface* factory, InputEvent** event) {
|
||||
status_t InputConsumer::consume(InputEventFactoryInterface* factory, InputEvent** outEvent) {
|
||||
#if DEBUG_TRANSPORT_ACTIONS
|
||||
LOGD("channel '%s' consumer ~ consume",
|
||||
mChannel->getName().string());
|
||||
#endif
|
||||
|
||||
*event = NULL;
|
||||
*outEvent = NULL;
|
||||
|
||||
int ashmemFd = mChannel->getAshmemFd();
|
||||
int result = ashmem_pin_region(ashmemFd, 0, 0);
|
||||
@ -583,7 +590,7 @@ status_t InputConsumer::consume(InputEventFactoryInterface* factory, InputEvent*
|
||||
|
||||
populateKeyEvent(keyEvent);
|
||||
|
||||
*event = keyEvent;
|
||||
*outEvent = keyEvent;
|
||||
break;
|
||||
}
|
||||
|
||||
@ -593,7 +600,7 @@ status_t InputConsumer::consume(InputEventFactoryInterface* factory, InputEvent*
|
||||
|
||||
populateMotionEvent(motionEvent);
|
||||
|
||||
*event = motionEvent;
|
||||
*outEvent = motionEvent;
|
||||
break;
|
||||
}
|
||||
|
||||
@ -655,8 +662,8 @@ void InputConsumer::populateMotionEvent(MotionEvent* motionEvent) const {
|
||||
mSharedMessage->motion.action,
|
||||
mSharedMessage->motion.edgeFlags,
|
||||
mSharedMessage->motion.metaState,
|
||||
mSharedMessage->motion.sampleData[0].coords[0].x,
|
||||
mSharedMessage->motion.sampleData[0].coords[0].y,
|
||||
mSharedMessage->motion.xOffset,
|
||||
mSharedMessage->motion.yOffset,
|
||||
mSharedMessage->motion.xPrecision,
|
||||
mSharedMessage->motion.yPrecision,
|
||||
mSharedMessage->motion.downTime,
|
||||
@ -676,9 +683,6 @@ void InputConsumer::populateMotionEvent(MotionEvent* motionEvent) const {
|
||||
motionEvent->addSample(sampleData->eventTime, sampleData->coords);
|
||||
}
|
||||
}
|
||||
|
||||
motionEvent->offsetLocation(mSharedMessage->motion.xOffset,
|
||||
mSharedMessage->motion.yOffset);
|
||||
}
|
||||
|
||||
} // namespace android
|
||||
|
@ -3,7 +3,9 @@ LOCAL_PATH:= $(call my-dir)
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
test_src_files := \
|
||||
InputDispatcher_test.cpp
|
||||
InputChannel_test.cpp \
|
||||
InputDispatcher_test.cpp \
|
||||
InputPublisherAndConsumer_test.cpp
|
||||
|
||||
shared_libraries := \
|
||||
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) {
|
||||
SCOPED_TRACE("Trace");
|
||||
ASSERT_FALSE(true);
|
||||
// TODO
|
||||
}
|
||||
|
||||
} // 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
|
||||
|
||||
// Debugs callback registration and invocation.
|
||||
#define DEBUG_CALLBACKS 1
|
||||
#define DEBUG_CALLBACKS 0
|
||||
|
||||
#include <cutils/log.h>
|
||||
#include <utils/PollLoop.h>
|
||||
@ -22,7 +22,7 @@
|
||||
namespace android {
|
||||
|
||||
PollLoop::PollLoop() :
|
||||
mPolling(false) {
|
||||
mPolling(false), mWaiters(0) {
|
||||
openWakePipe();
|
||||
}
|
||||
|
||||
@ -68,6 +68,9 @@ void PollLoop::closeWakePipe() {
|
||||
|
||||
bool PollLoop::pollOnce(int timeoutMillis) {
|
||||
mLock.lock();
|
||||
while (mWaiters != 0) {
|
||||
mResume.wait(mLock);
|
||||
}
|
||||
mPolling = true;
|
||||
mLock.unlock();
|
||||
|
||||
@ -156,7 +159,9 @@ bool PollLoop::pollOnce(int timeoutMillis) {
|
||||
Done:
|
||||
mLock.lock();
|
||||
mPolling = false;
|
||||
mAwake.broadcast();
|
||||
if (mWaiters != 0) {
|
||||
mAwake.broadcast();
|
||||
}
|
||||
mLock.unlock();
|
||||
|
||||
if (result) {
|
||||
@ -258,10 +263,15 @@ ssize_t PollLoop::getRequestIndexLocked(int fd) {
|
||||
|
||||
void PollLoop::wakeAndLock() {
|
||||
mLock.lock();
|
||||
mWaiters += 1;
|
||||
while (mPolling) {
|
||||
wake();
|
||||
mAwake.wait(mLock);
|
||||
}
|
||||
mWaiters -= 1;
|
||||
if (mWaiters == 0) {
|
||||
mResume.signal();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace android
|
||||
|
@ -108,7 +108,7 @@ size_t VectorImpl::capacity() const
|
||||
|
||||
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)
|
||||
@ -116,6 +116,22 @@ ssize_t VectorImpl::appendVector(const VectorImpl& vector)
|
||||
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)
|
||||
{
|
||||
return insertAt(0, index, numItems);
|
||||
@ -220,9 +236,9 @@ ssize_t VectorImpl::add()
|
||||
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)
|
||||
|
@ -16,34 +16,6 @@
|
||||
|
||||
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 {
|
||||
sp<PollLoop> mPollLoop;
|
||||
|
||||
@ -195,7 +167,7 @@ TEST_F(PollLoopTest, PollOnce_WhenZeroTimeoutAndSignalledFD_ImmediatelyInvokesCa
|
||||
Pipe pipe;
|
||||
StubCallbackHandler handler(true);
|
||||
|
||||
ASSERT_TRUE(pipe.writeSignal());
|
||||
ASSERT_EQ(OK, pipe.writeSignal());
|
||||
handler.setCallback(mPollLoop, pipe.receiveFd, POLL_IN);
|
||||
|
||||
StopWatch stopWatch("pollOnce");
|
||||
@ -243,7 +215,7 @@ TEST_F(PollLoopTest, PollOnce_WhenNonZeroTimeoutAndSignalledFDBeforeWaiting_Imme
|
||||
bool result = mPollLoop->pollOnce(100);
|
||||
int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
|
||||
|
||||
ASSERT_TRUE(pipe.readSignal())
|
||||
ASSERT_EQ(OK, pipe.readSignal())
|
||||
<< "signal should actually have been written";
|
||||
EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS)
|
||||
<< "elapsed time should be approx. zero";
|
||||
@ -269,7 +241,7 @@ TEST_F(PollLoopTest, PollOnce_WhenNonZeroTimeoutAndSignalledFDWhileWaiting_Promp
|
||||
bool result = mPollLoop->pollOnce(1000);
|
||||
int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
|
||||
|
||||
ASSERT_TRUE(pipe.readSignal())
|
||||
ASSERT_EQ(OK, pipe.readSignal())
|
||||
<< "signal should actually have been written";
|
||||
EXPECT_NEAR(100, elapsedMillis, TIMING_TOLERANCE_MS)
|
||||
<< "elapsed time should approx. equal signal delay";
|
||||
@ -295,7 +267,7 @@ TEST_F(PollLoopTest, PollOnce_WhenCallbackAddedThenRemoved_CallbackShouldNotBeIn
|
||||
bool result = mPollLoop->pollOnce(100);
|
||||
int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
|
||||
|
||||
ASSERT_TRUE(pipe.readSignal())
|
||||
ASSERT_EQ(OK, pipe.readSignal())
|
||||
<< "signal should actually have been written";
|
||||
EXPECT_NEAR(100, elapsedMillis, TIMING_TOLERANCE_MS)
|
||||
<< "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);
|
||||
int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
|
||||
|
||||
ASSERT_TRUE(pipe.readSignal())
|
||||
ASSERT_EQ(OK, pipe.readSignal())
|
||||
<< "signal should actually have been written";
|
||||
EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS)
|
||||
<< "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);
|
||||
elapsedMillis = ns2ms(stopWatch.elapsedTime());
|
||||
|
||||
ASSERT_TRUE(pipe.readSignal())
|
||||
ASSERT_EQ(OK, pipe.readSignal())
|
||||
<< "signal should actually have been written";
|
||||
EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS)
|
||||
<< "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);
|
||||
int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
|
||||
|
||||
ASSERT_TRUE(pipe.readSignal())
|
||||
ASSERT_EQ(OK, pipe.readSignal())
|
||||
<< "signal should actually have been written";
|
||||
EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS)
|
||||
<< "elapsed time should approx. zero because FD was already signalled";
|
||||
|
@ -21,6 +21,41 @@
|
||||
|
||||
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 {
|
||||
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. */
|
||||
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.
|
||||
* You can multiply this number with an X coordinate sample to find the
|
||||
* 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. */
|
||||
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
|
||||
* events on the screen, this is the original location of the event
|
||||
/* Get the original raw X coordinate of this 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. */
|
||||
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
|
||||
* events on the screen, this is the original location of the event
|
||||
/* Get the original raw X coordinate of this 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. */
|
||||
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.
|
||||
* 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,
|
||||
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
|
||||
* occurred between this event and the previous motion event.
|
||||
* 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) {
|
||||
actions |= InputReaderPolicyInterface::ACTION_DISPATCH;
|
||||
}
|
||||
|
||||
if (! (wmActions & WM_ACTION_PASS_TO_USER)) {
|
||||
if (down && isAppSwitchKey(keyCode)) {
|
||||
env->CallVoidMethod(mCallbacksObj, gCallbacksClassInfo.notifyAppSwitchComing);
|
||||
checkExceptionFromCallback(env, "notifyAppSwitchComing");
|
||||
@ -312,12 +310,18 @@ int32_t NativeInputManager::interceptTouch(nsecs_t when) {
|
||||
LOGD("interceptTouch - when=%lld", when);
|
||||
#endif
|
||||
|
||||
if (! isScreenOn()) {
|
||||
// Touch events do not wake the device.
|
||||
return InputReaderPolicyInterface::ACTION_NONE;
|
||||
int32_t actions = InputReaderPolicyInterface::ACTION_NONE;
|
||||
if (isScreenOn()) {
|
||||
// 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,
|
||||
@ -327,12 +331,18 @@ int32_t NativeInputManager::interceptTrackball(nsecs_t when,
|
||||
when, buttonChanged, buttonDown, rolled);
|
||||
#endif
|
||||
|
||||
if (! isScreenOn()) {
|
||||
// Trackball motions and button presses do not wake the device.
|
||||
return InputReaderPolicyInterface::ACTION_NONE;
|
||||
int32_t actions = InputReaderPolicyInterface::ACTION_NONE;
|
||||
if (isScreenOn()) {
|
||||
// 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,
|
||||
|
Reference in New Issue
Block a user