Even more native input dispatch work in progress.

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

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

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

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

View File

@ -176769,7 +176769,7 @@
synchronized="false"
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"
>

View File

@ -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,14 +280,12 @@ 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];
}
@ -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++) {
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) {
@ -679,6 +584,27 @@ public final class MotionEvent implements Parcelable {
}
}
/**
* Scales down the coordination of this event by the given scale.
*
* @hide
*/
public final void scale(float scale) {
mXOffset *= scale;
mYOffset *= scale;
mXPrecision *= scale;
mYPrecision *= scale;
float[] history = mDataSamples;
final int length = mNumPointers * mNumSamples * NUM_SAMPLE_DATA;
for (int i = 0; i < length; i += NUM_SAMPLE_DATA) {
history[i + SAMPLE_X] *= scale;
history[i + SAMPLE_Y] *= scale;
// no need to scale pressure
history[i + SAMPLE_SIZE] *= scale; // TODO: square this?
}
}
/**
* Return the kind of action being performed -- one of either
* {@link #ACTION_DOWN}, {@link #ACTION_MOVE}, {@link #ACTION_UP}, or
@ -719,14 +645,14 @@ public final class MotionEvent implements Parcelable {
* a stream of position events.
*/
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,36 +1104,24 @@ 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;
mEventTimeNanoSamples[mLastEventTimeNanoSampleIndex] = eventTime * MS_PER_NS;
float[] dataSamples = mDataSamples;
System.arraycopy(inData, 0, dataSamples, mLastDataSampleIndex, dataSampleStride);
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;
}
if (times.length < (NS+1)) {
final int NEW_NS = NS + BASE_AVAIL_SAMPLES;
long[] newHistoryTimes = new long[NEW_NS];
System.arraycopy(times, 0, newHistoryTimes, 0, NS);
mTimeSamples = times = newHistoryTimes;
}
times[NS] = times[0];
times[0] = eventTime;
System.arraycopy(data, 0, data, ND, mNumPointers*NUM_SAMPLE_DATA);
System.arraycopy(inData, 0, data, 0, mNumPointers*NUM_SAMPLE_DATA);
mNumSamples = NS+1;
mRawX = inData[SAMPLE_X];
mRawY = inData[SAMPLE_Y];
mMetaState |= metaState;
if (DEBUG_POINTERS) {
@ -1224,11 +1129,11 @@ public final class MotionEvent implements Parcelable {
sb.append("Add:");
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);
}
out.writeInt(mMetaState);
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];
}
final int[] pointerIdentifiers = mPointerIdentifiers;
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();
}
}
mXPrecision = in.readFloat();
mYPrecision = in.readFloat();
mDeviceId = in.readInt();
mEdgeFlags = in.readInt();
out.writeInt(pointerIdentifiers[i]);
}
final long[] eventTimeNanoSamples = mEventTimeNanoSamples;
for (int i = 0; i < NS; i++) {
out.writeLong(eventTimeNanoSamples[i]);
}
final float[] dataSamples = mDataSamples;
for (int i = 0; i < NI; i++) {
out.writeFloat(dataSamples[i]);
}
}
}

View File

@ -121,9 +121,9 @@ static jobjectArray android_view_InputChannel_nativeOpenInputChannelPair(JNIEnv*
String8 name(nameChars);
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);

View File

@ -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;
}

View File

@ -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;

View File

@ -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.

View File

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

View File

@ -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

View File

@ -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);

View File

@ -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(

View File

@ -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);

View File

@ -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 {
}
}
// 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;
}
heap[insertionIndex].currentPointerIndex = currentPointerIndex;
heap[insertionIndex].lastPointerIndex = lastPointerIndex;
heap[insertionIndex].distance = distance;
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;

View File

@ -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

View File

@ -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 \

View File

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

View File

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

View File

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

View File

@ -11,7 +11,7 @@
#define DEBUG_POLL_AND_WAKE 0
// 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;
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

View File

@ -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)

View File

@ -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";

View File

@ -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;

View File

@ -394,6 +394,18 @@ int64_t motion_event_get_down_time(const input_event_t* motion_event);
* in the java.lang.System.nanoTime() time base. */
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

View File

@ -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,