diff options
author | Jeff Brown <jeffbrown@google.com> | 2010-06-16 01:53:36 -0700 |
---|---|---|
committer | Jeff Brown <jeffbrown@google.com> | 2010-06-17 13:27:16 -0700 |
commit | 5c225b1680e696ae8bbf505a1997d6f720672f74 (patch) | |
tree | 932326fd02ee91d8a64adfcc9415027646c56563 | |
parent | 3a0146cd29fae3c5bc29d8d535d67826284f8cc9 (diff) | |
download | frameworks_base-5c225b1680e696ae8bbf505a1997d6f720672f74.zip frameworks_base-5c225b1680e696ae8bbf505a1997d6f720672f74.tar.gz frameworks_base-5c225b1680e696ae8bbf505a1997d6f720672f74.tar.bz2 |
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
-rw-r--r-- | api/current.xml | 4 | ||||
-rw-r--r-- | core/java/android/view/MotionEvent.java | 593 | ||||
-rw-r--r-- | core/jni/android_view_InputChannel.cpp | 6 | ||||
-rw-r--r-- | core/jni/android_view_MotionEvent.cpp | 183 | ||||
-rw-r--r-- | include/ui/Input.h | 49 | ||||
-rw-r--r-- | include/ui/InputTransport.h | 8 | ||||
-rw-r--r-- | include/utils/PollLoop.h | 4 | ||||
-rw-r--r-- | include/utils/Vector.h | 14 | ||||
-rw-r--r-- | include/utils/VectorImpl.h | 10 | ||||
-rw-r--r-- | libs/ui/Input.cpp | 45 | ||||
-rw-r--r-- | libs/ui/InputDispatcher.cpp | 3 | ||||
-rw-r--r-- | libs/ui/InputReader.cpp | 113 | ||||
-rw-r--r-- | libs/ui/InputTransport.cpp | 38 | ||||
-rw-r--r-- | libs/ui/tests/Android.mk | 4 | ||||
-rw-r--r-- | libs/ui/tests/InputChannel_test.cpp | 158 | ||||
-rw-r--r-- | libs/ui/tests/InputDispatcher_test.cpp | 3 | ||||
-rw-r--r-- | libs/ui/tests/InputPublisherAndConsumer_test.cpp | 449 | ||||
-rw-r--r-- | libs/utils/PollLoop.cpp | 16 | ||||
-rw-r--r-- | libs/utils/VectorImpl.cpp | 22 | ||||
-rw-r--r-- | libs/utils/tests/PollLoop_test.cpp | 42 | ||||
-rw-r--r-- | libs/utils/tests/TestHelpers.h | 35 | ||||
-rw-r--r-- | native/include/android/input.h | 42 | ||||
-rw-r--r-- | services/jni/com_android_server_InputManager.cpp | 30 |
23 files changed, 1263 insertions, 608 deletions
diff --git a/api/current.xml b/api/current.xml index 0db40ce..6847352 100644 --- a/api/current.xml +++ b/api/current.xml @@ -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" > diff --git a/core/java/android/view/MotionEvent.java b/core/java/android/view/MotionEvent.java index 1f06191..ae8c21d 100644 --- a/core/java/android/view/MotionEvent.java +++ b/core/java/android/view/MotionEvent.java @@ -27,6 +27,7 @@ import android.util.Log; * it is being used for. */ public final class MotionEvent implements Parcelable { + private static final long MS_PER_NS = 1000000; static final boolean DEBUG_POINTERS = false; /** @@ -218,31 +219,32 @@ public final class MotionEvent implements Parcelable { static private int gRecyclerUsed = 0; static private MotionEvent gRecyclerTop = null; - private long mDownTime; - private long mEventTimeNano; + private long mDownTimeNano; private int mAction; - private float mRawX; - private float mRawY; + private float mXOffset; + private float mYOffset; private float mXPrecision; private float mYPrecision; private int mDeviceId; private int mEdgeFlags; private int mMetaState; - // Here is the actual event data. Note that the order of the array - // is a little odd: the first entry is the most recent, and the ones - // following it are the historical data from oldest to newest. This - // allows us to easily retrieve the most recent data, without having - // to copy the arrays every time a new sample is added. - private int mNumPointers; private int mNumSamples; + + private int mLastDataSampleIndex; + private int mLastEventTimeNanoSampleIndex; + // Array of mNumPointers size of identifiers for each pointer of data. private int[] mPointerIdentifiers; + // Array of (mNumSamples * mNumPointers * NUM_SAMPLE_DATA) size of event data. + // Samples are ordered from oldest to newest. private float[] mDataSamples; - // Array of mNumSamples size of time stamps. - private long[] mTimeSamples; + + // Array of mNumSamples size of event time stamps in nanoseconds. + // Samples are ordered from oldest to newest. + private long[] mEventTimeNanoSamples; private MotionEvent mNext; private RuntimeException mRecycledLocation; @@ -251,26 +253,9 @@ public final class MotionEvent implements Parcelable { private MotionEvent(int pointerCount, int sampleCount) { mPointerIdentifiers = new int[pointerCount]; mDataSamples = new float[pointerCount * sampleCount * NUM_SAMPLE_DATA]; - mTimeSamples = new long[sampleCount]; + mEventTimeNanoSamples = new long[sampleCount]; } - static private MotionEvent obtain() { - final MotionEvent ev; - synchronized (gRecyclerLock) { - if (gRecyclerTop == null) { - return new MotionEvent(BASE_AVAIL_POINTERS, BASE_AVAIL_SAMPLES); - } - ev = gRecyclerTop; - gRecyclerTop = ev.mNext; - gRecyclerUsed--; - } - ev.mRecycledLocation = null; - ev.mRecycled = false; - ev.mNext = null; - return ev; - } - - @SuppressWarnings("unused") // used by native code static private MotionEvent obtain(int pointerCount, int sampleCount) { final MotionEvent ev; synchronized (gRecyclerLock) { @@ -285,7 +270,7 @@ public final class MotionEvent implements Parcelable { } ev = gRecyclerTop; gRecyclerTop = ev.mNext; - gRecyclerUsed--; + gRecyclerUsed -= 1; } ev.mRecycledLocation = null; ev.mRecycled = false; @@ -295,20 +280,18 @@ public final class MotionEvent implements Parcelable { ev.mPointerIdentifiers = new int[pointerCount]; } - final int timeSamplesLength = ev.mTimeSamples.length; - if (timeSamplesLength < sampleCount) { - ev.mTimeSamples = new long[sampleCount]; + if (ev.mEventTimeNanoSamples.length < sampleCount) { + ev.mEventTimeNanoSamples = new long[sampleCount]; } - final int dataSamplesLength = ev.mDataSamples.length; final int neededDataSamplesLength = pointerCount * sampleCount * NUM_SAMPLE_DATA; - if (dataSamplesLength < neededDataSamplesLength) { + if (ev.mDataSamples.length < neededDataSamplesLength) { ev.mDataSamples = new float[neededDataSamplesLength]; } return ev; } - + /** * Create a new MotionEvent, filling in all of the basic values that * define the motion. @@ -342,45 +325,39 @@ public final class MotionEvent implements Parcelable { static public MotionEvent obtainNano(long downTime, long eventTime, long eventTimeNano, int action, int pointers, int[] inPointerIds, float[] inData, int metaState, float xPrecision, float yPrecision, int deviceId, int edgeFlags) { - MotionEvent ev = obtain(); + MotionEvent ev = obtain(pointers, 1); ev.mDeviceId = deviceId; ev.mEdgeFlags = edgeFlags; - ev.mDownTime = downTime; - ev.mEventTimeNano = eventTimeNano; + ev.mDownTimeNano = downTime * MS_PER_NS; ev.mAction = action; ev.mMetaState = metaState; - ev.mRawX = inData[SAMPLE_X]; - ev.mRawY = inData[SAMPLE_Y]; + ev.mXOffset = 0; + ev.mYOffset = 0; ev.mXPrecision = xPrecision; ev.mYPrecision = yPrecision; + ev.mNumPointers = pointers; ev.mNumSamples = 1; - int[] pointerIdentifiers = ev.mPointerIdentifiers; - if (pointerIdentifiers.length < pointers) { - ev.mPointerIdentifiers = pointerIdentifiers = new int[pointers]; - } - System.arraycopy(inPointerIds, 0, pointerIdentifiers, 0, pointers); + ev.mLastDataSampleIndex = 0; + ev.mLastEventTimeNanoSampleIndex = 0; - final int ND = pointers * NUM_SAMPLE_DATA; - float[] dataSamples = ev.mDataSamples; - if (dataSamples.length < ND) { - ev.mDataSamples = dataSamples = new float[ND]; - } - System.arraycopy(inData, 0, dataSamples, 0, ND); + System.arraycopy(inPointerIds, 0, ev.mPointerIdentifiers, 0, pointers); - ev.mTimeSamples[0] = eventTime; + ev.mEventTimeNanoSamples[0] = eventTimeNano; + + System.arraycopy(inData, 0, ev.mDataSamples, 0, pointers * NUM_SAMPLE_DATA); if (DEBUG_POINTERS) { StringBuilder sb = new StringBuilder(128); sb.append("New:"); - for (int i=0; i<pointers; i++) { + for (int i = 0; i < pointers; i++) { sb.append(" #"); - sb.append(ev.mPointerIdentifiers[i]); + sb.append(ev.getPointerId(i)); sb.append("("); - sb.append(ev.mDataSamples[(i*NUM_SAMPLE_DATA) + SAMPLE_X]); + sb.append(ev.getX(i)); sb.append(","); - sb.append(ev.mDataSamples[(i*NUM_SAMPLE_DATA) + SAMPLE_Y]); + sb.append(ev.getY(i)); sb.append(")"); } Log.v("MotionEvent", sb.toString()); @@ -423,27 +400,32 @@ public final class MotionEvent implements Parcelable { static public MotionEvent obtain(long downTime, long eventTime, int action, float x, float y, float pressure, float size, int metaState, float xPrecision, float yPrecision, int deviceId, int edgeFlags) { - MotionEvent ev = obtain(); + MotionEvent ev = obtain(1, 1); ev.mDeviceId = deviceId; ev.mEdgeFlags = edgeFlags; - ev.mDownTime = downTime; - ev.mEventTimeNano = eventTime * 1000000; + ev.mDownTimeNano = downTime * MS_PER_NS; ev.mAction = action; ev.mMetaState = metaState; + ev.mXOffset = 0; + ev.mYOffset = 0; ev.mXPrecision = xPrecision; ev.mYPrecision = yPrecision; - + ev.mNumPointers = 1; ev.mNumSamples = 1; - int[] pointerIds = ev.mPointerIdentifiers; - pointerIds[0] = 0; - float[] data = ev.mDataSamples; - data[SAMPLE_X] = ev.mRawX = x; - data[SAMPLE_Y] = ev.mRawY = y; - data[SAMPLE_PRESSURE] = pressure; - data[SAMPLE_SIZE] = size; - ev.mTimeSamples[0] = eventTime; - + + ev.mLastDataSampleIndex = 0; + ev.mLastEventTimeNanoSampleIndex = 0; + + ev.mPointerIdentifiers[0] = 0; + + ev.mEventTimeNanoSamples[0] = eventTime * MS_PER_NS; + + float[] dataSamples = ev.mDataSamples; + dataSamples[SAMPLE_X] = x; + dataSamples[SAMPLE_Y] = y; + dataSamples[SAMPLE_PRESSURE] = pressure; + dataSamples[SAMPLE_SIZE] = size; return ev; } @@ -478,33 +460,16 @@ public final class MotionEvent implements Parcelable { * numbers are arbitrary and you shouldn't depend on the values. * @param edgeFlags A bitfield indicating which edges, if any, where touched by this * MotionEvent. + * + * @deprecated Use {@link #obtain(long, long, int, float, float, float, float, int, float, float, int, int)} + * instead. */ + @Deprecated static public MotionEvent obtain(long downTime, long eventTime, int action, int pointers, float x, float y, float pressure, float size, int metaState, float xPrecision, float yPrecision, int deviceId, int edgeFlags) { - MotionEvent ev = obtain(); - ev.mDeviceId = deviceId; - ev.mEdgeFlags = edgeFlags; - ev.mDownTime = downTime; - ev.mEventTimeNano = eventTime * 1000000; - ev.mAction = action; - ev.mNumPointers = pointers; - ev.mMetaState = metaState; - ev.mXPrecision = xPrecision; - ev.mYPrecision = yPrecision; - - ev.mNumPointers = 1; - ev.mNumSamples = 1; - int[] pointerIds = ev.mPointerIdentifiers; - pointerIds[0] = 0; - float[] data = ev.mDataSamples; - data[SAMPLE_X] = ev.mRawX = x; - data[SAMPLE_Y] = ev.mRawY = y; - data[SAMPLE_PRESSURE] = pressure; - data[SAMPLE_SIZE] = size; - ev.mTimeSamples[0] = eventTime; - - return ev; + return obtain(downTime, eventTime, action, x, y, pressure, size, + metaState, xPrecision, yPrecision, deviceId, edgeFlags); } /** @@ -526,89 +491,36 @@ public final class MotionEvent implements Parcelable { */ static public MotionEvent obtain(long downTime, long eventTime, int action, float x, float y, int metaState) { - MotionEvent ev = obtain(); - ev.mDeviceId = 0; - ev.mEdgeFlags = 0; - ev.mDownTime = downTime; - ev.mEventTimeNano = eventTime * 1000000; - ev.mAction = action; - ev.mNumPointers = 1; - ev.mMetaState = metaState; - ev.mXPrecision = 1.0f; - ev.mYPrecision = 1.0f; - - ev.mNumPointers = 1; - ev.mNumSamples = 1; - int[] pointerIds = ev.mPointerIdentifiers; - pointerIds[0] = 0; - float[] data = ev.mDataSamples; - data[SAMPLE_X] = ev.mRawX = x; - data[SAMPLE_Y] = ev.mRawY = y; - data[SAMPLE_PRESSURE] = 1.0f; - data[SAMPLE_SIZE] = 1.0f; - ev.mTimeSamples[0] = eventTime; - - return ev; - } - - /** - * Scales down the coordination of this event by the given scale. - * - * @hide - */ - public void scale(float scale) { - mRawX *= scale; - mRawY *= scale; - mXPrecision *= scale; - mYPrecision *= scale; - float[] history = mDataSamples; - final int length = mNumPointers * mNumSamples * NUM_SAMPLE_DATA; - for (int i = 0; i < length; i += NUM_SAMPLE_DATA) { - history[i + SAMPLE_X] *= scale; - history[i + SAMPLE_Y] *= scale; - // no need to scale pressure - history[i + SAMPLE_SIZE] *= scale; // TODO: square this? - } + return obtain(downTime, eventTime, action, x, y, 1.0f, 1.0f, + metaState, 1.0f, 1.0f, 0, 0); } /** * Create a new MotionEvent, copying from an existing one. */ static public MotionEvent obtain(MotionEvent o) { - MotionEvent ev = obtain(); + MotionEvent ev = obtain(o.mNumPointers, o.mNumSamples); ev.mDeviceId = o.mDeviceId; ev.mEdgeFlags = o.mEdgeFlags; - ev.mDownTime = o.mDownTime; - ev.mEventTimeNano = o.mEventTimeNano; + ev.mDownTimeNano = o.mDownTimeNano; ev.mAction = o.mAction; - ev.mNumPointers = o.mNumPointers; - ev.mRawX = o.mRawX; - ev.mRawY = o.mRawY; ev.mMetaState = o.mMetaState; + ev.mXOffset = o.mXOffset; + ev.mYOffset = o.mYOffset; ev.mXPrecision = o.mXPrecision; ev.mYPrecision = o.mYPrecision; + int numPointers = ev.mNumPointers = o.mNumPointers; + int numSamples = ev.mNumSamples = o.mNumSamples; - final int NS = ev.mNumSamples = o.mNumSamples; - if (ev.mTimeSamples.length >= NS) { - System.arraycopy(o.mTimeSamples, 0, ev.mTimeSamples, 0, NS); - } else { - ev.mTimeSamples = (long[])o.mTimeSamples.clone(); - } + ev.mLastDataSampleIndex = o.mLastDataSampleIndex; + ev.mLastEventTimeNanoSampleIndex = o.mLastEventTimeNanoSampleIndex; - final int NP = (ev.mNumPointers=o.mNumPointers); - if (ev.mPointerIdentifiers.length >= NP) { - System.arraycopy(o.mPointerIdentifiers, 0, ev.mPointerIdentifiers, 0, NP); - } else { - ev.mPointerIdentifiers = (int[])o.mPointerIdentifiers.clone(); - } + System.arraycopy(o.mPointerIdentifiers, 0, ev.mPointerIdentifiers, 0, numPointers); - final int ND = NP * NS * NUM_SAMPLE_DATA; - if (ev.mDataSamples.length >= ND) { - System.arraycopy(o.mDataSamples, 0, ev.mDataSamples, 0, ND); - } else { - ev.mDataSamples = (float[])o.mDataSamples.clone(); - } + System.arraycopy(o.mEventTimeNanoSamples, 0, ev.mEventTimeNanoSamples, 0, numSamples); + System.arraycopy(o.mDataSamples, 0, ev.mDataSamples, 0, + numPointers * numSamples * NUM_SAMPLE_DATA); return ev; } @@ -617,36 +529,29 @@ public final class MotionEvent implements Parcelable { * any historical point information. */ static public MotionEvent obtainNoHistory(MotionEvent o) { - MotionEvent ev = obtain(); + MotionEvent ev = obtain(o.mNumPointers, 1); ev.mDeviceId = o.mDeviceId; ev.mEdgeFlags = o.mEdgeFlags; - ev.mDownTime = o.mDownTime; - ev.mEventTimeNano = o.mEventTimeNano; + ev.mDownTimeNano = o.mDownTimeNano; ev.mAction = o.mAction; - ev.mNumPointers = o.mNumPointers; - ev.mRawX = o.mRawX; - ev.mRawY = o.mRawY; ev.mMetaState = o.mMetaState; + ev.mXOffset = o.mXOffset; + ev.mYOffset = o.mYOffset; ev.mXPrecision = o.mXPrecision; ev.mYPrecision = o.mYPrecision; + int numPointers = ev.mNumPointers = o.mNumPointers; ev.mNumSamples = 1; - ev.mTimeSamples[0] = o.mTimeSamples[0]; - final int NP = (ev.mNumPointers=o.mNumPointers); - if (ev.mPointerIdentifiers.length >= NP) { - System.arraycopy(o.mPointerIdentifiers, 0, ev.mPointerIdentifiers, 0, NP); - } else { - ev.mPointerIdentifiers = (int[])o.mPointerIdentifiers.clone(); - } + ev.mLastDataSampleIndex = 0; + ev.mLastEventTimeNanoSampleIndex = 0; - final int ND = NP * NUM_SAMPLE_DATA; - if (ev.mDataSamples.length >= ND) { - System.arraycopy(o.mDataSamples, 0, ev.mDataSamples, 0, ND); - } else { - ev.mDataSamples = (float[])o.mDataSamples.clone(); - } + System.arraycopy(o.mPointerIdentifiers, 0, ev.mPointerIdentifiers, 0, numPointers); + ev.mEventTimeNanoSamples[0] = o.mEventTimeNanoSamples[o.mLastEventTimeNanoSampleIndex]; + + System.arraycopy(o.mDataSamples, o.mLastDataSampleIndex, ev.mDataSamples, 0, + numPointers * NUM_SAMPLE_DATA); return ev; } @@ -654,7 +559,7 @@ public final class MotionEvent implements Parcelable { * Recycle the MotionEvent, to be re-used by a later caller. After calling * this function you must not ever touch the event again. */ - public void recycle() { + public final void recycle() { // Ensure recycle is only called once! if (TRACK_RECYCLED_LOCATION) { if (mRecycledLocation != null) { @@ -678,6 +583,27 @@ public final class MotionEvent implements Parcelable { } } } + + /** + * Scales down the coordination of this event by the given scale. + * + * @hide + */ + public final void scale(float scale) { + mXOffset *= scale; + mYOffset *= scale; + mXPrecision *= scale; + mYPrecision *= scale; + + float[] history = mDataSamples; + final int length = mNumPointers * mNumSamples * NUM_SAMPLE_DATA; + for (int i = 0; i < length; i += NUM_SAMPLE_DATA) { + history[i + SAMPLE_X] *= scale; + history[i + SAMPLE_Y] *= scale; + // no need to scale pressure + history[i + SAMPLE_SIZE] *= scale; // TODO: square this? + } + } /** * Return the kind of action being performed -- one of either @@ -719,14 +645,14 @@ public final class MotionEvent implements Parcelable { * a stream of position events. */ public final long getDownTime() { - return mDownTime; + return mDownTimeNano / MS_PER_NS; } /** * Returns the time (in ms) when this specific event was generated. */ public final long getEventTime() { - return mTimeSamples[0]; + return mEventTimeNanoSamples[mLastEventTimeNanoSampleIndex] / MS_PER_NS; } /** @@ -736,7 +662,7 @@ public final class MotionEvent implements Parcelable { * @hide */ public final long getEventTimeNano() { - return mEventTimeNano; + return mEventTimeNanoSamples[mLastEventTimeNanoSampleIndex]; } /** @@ -744,7 +670,7 @@ public final class MotionEvent implements Parcelable { * arbitrary pointer identifier). */ public final float getX() { - return mDataSamples[SAMPLE_X]; + return mDataSamples[mLastDataSampleIndex + SAMPLE_X] + mXOffset; } /** @@ -752,7 +678,7 @@ public final class MotionEvent implements Parcelable { * arbitrary pointer identifier). */ public final float getY() { - return mDataSamples[SAMPLE_Y]; + return mDataSamples[mLastDataSampleIndex + SAMPLE_Y] + mYOffset; } /** @@ -760,7 +686,7 @@ public final class MotionEvent implements Parcelable { * arbitrary pointer identifier). */ public final float getPressure() { - return mDataSamples[SAMPLE_PRESSURE]; + return mDataSamples[mLastDataSampleIndex + SAMPLE_PRESSURE]; } /** @@ -768,7 +694,7 @@ public final class MotionEvent implements Parcelable { * arbitrary pointer identifier). */ public final float getSize() { - return mDataSamples[SAMPLE_SIZE]; + return mDataSamples[mLastDataSampleIndex + SAMPLE_SIZE]; } /** @@ -820,7 +746,8 @@ public final class MotionEvent implements Parcelable { * (the first pointer that is down) to {@link #getPointerCount()}-1. */ public final float getX(int pointerIndex) { - return mDataSamples[(pointerIndex*NUM_SAMPLE_DATA) + SAMPLE_X]; + return mDataSamples[mLastDataSampleIndex + + pointerIndex * NUM_SAMPLE_DATA + SAMPLE_X] + mXOffset; } /** @@ -833,7 +760,8 @@ public final class MotionEvent implements Parcelable { * (the first pointer that is down) to {@link #getPointerCount()}-1. */ public final float getY(int pointerIndex) { - return mDataSamples[(pointerIndex*NUM_SAMPLE_DATA) + SAMPLE_Y]; + return mDataSamples[mLastDataSampleIndex + + pointerIndex * NUM_SAMPLE_DATA + SAMPLE_Y] + mYOffset; } /** @@ -848,7 +776,8 @@ public final class MotionEvent implements Parcelable { * (the first pointer that is down) to {@link #getPointerCount()}-1. */ public final float getPressure(int pointerIndex) { - return mDataSamples[(pointerIndex*NUM_SAMPLE_DATA) + SAMPLE_PRESSURE]; + return mDataSamples[mLastDataSampleIndex + + pointerIndex * NUM_SAMPLE_DATA + SAMPLE_PRESSURE]; } /** @@ -864,7 +793,8 @@ public final class MotionEvent implements Parcelable { * (the first pointer that is down) to {@link #getPointerCount()}-1. */ public final float getSize(int pointerIndex) { - return mDataSamples[(pointerIndex*NUM_SAMPLE_DATA) + SAMPLE_SIZE]; + return mDataSamples[mLastDataSampleIndex + + pointerIndex * NUM_SAMPLE_DATA + SAMPLE_SIZE]; } /** @@ -888,7 +818,7 @@ public final class MotionEvent implements Parcelable { * and views. */ public final float getRawX() { - return mRawX; + return mDataSamples[mLastDataSampleIndex + SAMPLE_X]; } /** @@ -898,7 +828,7 @@ public final class MotionEvent implements Parcelable { * and views. */ public final float getRawY() { - return mRawY; + return mDataSamples[mLastDataSampleIndex + SAMPLE_Y]; } /** @@ -930,7 +860,7 @@ public final class MotionEvent implements Parcelable { * @return Returns the number of historical points in the event. */ public final int getHistorySize() { - return mNumSamples - 1; + return mLastEventTimeNanoSampleIndex; } /** @@ -944,7 +874,7 @@ public final class MotionEvent implements Parcelable { * @see #getEventTime */ public final long getHistoricalEventTime(int pos) { - return mTimeSamples[pos + 1]; + return mEventTimeNanoSamples[pos] / MS_PER_NS; } /** @@ -952,7 +882,7 @@ public final class MotionEvent implements Parcelable { * arbitrary pointer identifier). */ public final float getHistoricalX(int pos) { - return mDataSamples[((pos + 1) * NUM_SAMPLE_DATA * mNumPointers) + SAMPLE_X]; + return mDataSamples[pos * mNumPointers * NUM_SAMPLE_DATA + SAMPLE_X] + mXOffset; } /** @@ -960,7 +890,7 @@ public final class MotionEvent implements Parcelable { * arbitrary pointer identifier). */ public final float getHistoricalY(int pos) { - return mDataSamples[((pos + 1) * NUM_SAMPLE_DATA * mNumPointers) + SAMPLE_Y]; + return mDataSamples[pos * mNumPointers * NUM_SAMPLE_DATA + SAMPLE_Y] + mYOffset; } /** @@ -968,7 +898,7 @@ public final class MotionEvent implements Parcelable { * arbitrary pointer identifier). */ public final float getHistoricalPressure(int pos) { - return mDataSamples[((pos + 1) * NUM_SAMPLE_DATA * mNumPointers) + SAMPLE_PRESSURE]; + return mDataSamples[pos * mNumPointers * NUM_SAMPLE_DATA + SAMPLE_PRESSURE]; } /** @@ -976,7 +906,7 @@ public final class MotionEvent implements Parcelable { * arbitrary pointer identifier). */ public final float getHistoricalSize(int pos) { - return mDataSamples[((pos + 1) * NUM_SAMPLE_DATA * mNumPointers) + SAMPLE_SIZE]; + return mDataSamples[pos * mNumPointers * NUM_SAMPLE_DATA + SAMPLE_SIZE]; } /** @@ -993,8 +923,8 @@ public final class MotionEvent implements Parcelable { * @see #getX */ public final float getHistoricalX(int pointerIndex, int pos) { - return mDataSamples[((pos + 1) * NUM_SAMPLE_DATA * mNumPointers) - + (pointerIndex * NUM_SAMPLE_DATA) + SAMPLE_X]; + return mDataSamples[(pos * mNumPointers + pointerIndex) + * NUM_SAMPLE_DATA + SAMPLE_X] + mXOffset; } /** @@ -1011,8 +941,8 @@ public final class MotionEvent implements Parcelable { * @see #getY */ public final float getHistoricalY(int pointerIndex, int pos) { - return mDataSamples[((pos + 1) * NUM_SAMPLE_DATA * mNumPointers) - + (pointerIndex * NUM_SAMPLE_DATA) + SAMPLE_Y]; + return mDataSamples[(pos * mNumPointers + pointerIndex) + * NUM_SAMPLE_DATA + SAMPLE_Y] + mYOffset; } /** @@ -1029,8 +959,8 @@ public final class MotionEvent implements Parcelable { * @see #getPressure */ public final float getHistoricalPressure(int pointerIndex, int pos) { - return mDataSamples[((pos + 1) * NUM_SAMPLE_DATA * mNumPointers) - + (pointerIndex * NUM_SAMPLE_DATA) + SAMPLE_PRESSURE]; + return mDataSamples[(pos * mNumPointers + pointerIndex) + * NUM_SAMPLE_DATA + SAMPLE_PRESSURE]; } /** @@ -1047,8 +977,8 @@ public final class MotionEvent implements Parcelable { * @see #getSize */ public final float getHistoricalSize(int pointerIndex, int pos) { - return mDataSamples[((pos + 1) * NUM_SAMPLE_DATA * mNumPointers) - + (pointerIndex * NUM_SAMPLE_DATA) + SAMPLE_SIZE]; + return mDataSamples[(pos * mNumPointers + pointerIndex) + * NUM_SAMPLE_DATA + SAMPLE_SIZE]; } /** @@ -1098,12 +1028,8 @@ public final class MotionEvent implements Parcelable { * @param deltaY Amount to add to the current Y coordinate of the event. */ public final void offsetLocation(float deltaX, float deltaY) { - final int N = mNumPointers*mNumSamples*4; - final float[] pos = mDataSamples; - for (int i=0; i<N; i+=NUM_SAMPLE_DATA) { - pos[i+SAMPLE_X] += deltaX; - pos[i+SAMPLE_Y] += deltaY; - } + mXOffset += deltaX; + mYOffset += deltaY; } /** @@ -1114,11 +1040,28 @@ public final class MotionEvent implements Parcelable { * @param y New absolute Y location. */ public final void setLocation(float x, float y) { - float deltaX = x-mDataSamples[SAMPLE_X]; - float deltaY = y-mDataSamples[SAMPLE_Y]; - if (deltaX != 0 || deltaY != 0) { - offsetLocation(deltaX, deltaY); + mXOffset = x - mDataSamples[mLastDataSampleIndex + SAMPLE_X]; + mYOffset = y - mDataSamples[mLastDataSampleIndex + SAMPLE_Y]; + } + + private final void incrementNumSamplesAndReserveStorage(int dataSampleStride) { + if (mNumSamples == mEventTimeNanoSamples.length) { + long[] newEventTimeNanoSamples = new long[mNumSamples + BASE_AVAIL_SAMPLES]; + System.arraycopy(mEventTimeNanoSamples, 0, newEventTimeNanoSamples, 0, mNumSamples); + mEventTimeNanoSamples = newEventTimeNanoSamples; } + + int nextDataSampleIndex = mLastDataSampleIndex + dataSampleStride; + if (nextDataSampleIndex + dataSampleStride > mDataSamples.length) { + float[] newDataSamples = new float[nextDataSampleIndex + + BASE_AVAIL_SAMPLES * dataSampleStride]; + System.arraycopy(mDataSamples, 0, newDataSamples, 0, nextDataSampleIndex); + mDataSamples = newDataSamples; + } + + mLastEventTimeNanoSampleIndex = mNumSamples; + mLastDataSampleIndex = nextDataSampleIndex; + mNumSamples += 1; } /** @@ -1136,42 +1079,16 @@ public final class MotionEvent implements Parcelable { */ public final void addBatch(long eventTime, float x, float y, float pressure, float size, int metaState) { - float[] data = mDataSamples; - long[] times = mTimeSamples; + incrementNumSamplesAndReserveStorage(NUM_SAMPLE_DATA); - final int NP = mNumPointers; - final int NS = mNumSamples; - final int NI = NP*NS; - final int ND = NI * NUM_SAMPLE_DATA; - if (data.length <= ND) { - final int NEW_ND = ND + (NP * (BASE_AVAIL_SAMPLES * NUM_SAMPLE_DATA)); - float[] newData = new float[NEW_ND]; - System.arraycopy(data, 0, newData, 0, ND); - mDataSamples = data = newData; - } - if (times.length <= NS) { - final int NEW_NS = NS + BASE_AVAIL_SAMPLES; - long[] newHistoryTimes = new long[NEW_NS]; - System.arraycopy(times, 0, newHistoryTimes, 0, NS); - mTimeSamples = times = newHistoryTimes; - } + mEventTimeNanoSamples[mLastEventTimeNanoSampleIndex] = eventTime * MS_PER_NS; - times[NS] = times[0]; - times[0] = eventTime; + float[] dataSamples = mDataSamples; + dataSamples[mLastDataSampleIndex + SAMPLE_X] = x - mXOffset; + dataSamples[mLastDataSampleIndex + SAMPLE_Y] = y - mYOffset; + dataSamples[mLastDataSampleIndex + SAMPLE_PRESSURE] = pressure; + dataSamples[mLastDataSampleIndex + SAMPLE_SIZE] = size; - final int pos = NS*NUM_SAMPLE_DATA; - data[pos+SAMPLE_X] = data[SAMPLE_X]; - data[pos+SAMPLE_Y] = data[SAMPLE_Y]; - data[pos+SAMPLE_PRESSURE] = data[SAMPLE_PRESSURE]; - data[pos+SAMPLE_SIZE] = data[SAMPLE_SIZE]; - data[SAMPLE_X] = x; - data[SAMPLE_Y] = y; - data[SAMPLE_PRESSURE] = pressure; - data[SAMPLE_SIZE] = size; - mNumSamples = NS+1; - - mRawX = x; - mRawY = y; mMetaState |= metaState; } @@ -1187,48 +1104,36 @@ public final class MotionEvent implements Parcelable { * @hide */ public final void addBatch(long eventTime, float[] inData, int metaState) { - float[] data = mDataSamples; - long[] times = mTimeSamples; + final int numPointers = mNumPointers; + final int dataSampleStride = numPointers * NUM_SAMPLE_DATA; + incrementNumSamplesAndReserveStorage(dataSampleStride); - final int NP = mNumPointers; - final int NS = mNumSamples; - final int NI = NP*NS; - final int ND = NI * NUM_SAMPLE_DATA; - if (data.length < (ND+(NP*NUM_SAMPLE_DATA))) { - final int NEW_ND = ND + (NP * (BASE_AVAIL_SAMPLES * NUM_SAMPLE_DATA)); - float[] newData = new float[NEW_ND]; - System.arraycopy(data, 0, newData, 0, ND); - mDataSamples = data = newData; - } - if (times.length < (NS+1)) { - final int NEW_NS = NS + BASE_AVAIL_SAMPLES; - long[] newHistoryTimes = new long[NEW_NS]; - System.arraycopy(times, 0, newHistoryTimes, 0, NS); - mTimeSamples = times = newHistoryTimes; - } - - times[NS] = times[0]; - times[0] = eventTime; + mEventTimeNanoSamples[mLastEventTimeNanoSampleIndex] = eventTime * MS_PER_NS; - System.arraycopy(data, 0, data, ND, mNumPointers*NUM_SAMPLE_DATA); - System.arraycopy(inData, 0, data, 0, mNumPointers*NUM_SAMPLE_DATA); + 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; + } + } - mNumSamples = NS+1; - - mRawX = inData[SAMPLE_X]; - mRawY = inData[SAMPLE_Y]; mMetaState |= metaState; if (DEBUG_POINTERS) { StringBuilder sb = new StringBuilder(128); sb.append("Add:"); - for (int i=0; i<mNumPointers; i++) { + 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); + + final int[] pointerIdentifiers = mPointerIdentifiers; + for (int i = 0; i < NP; i++) { + out.writeInt(pointerIdentifiers[i]); + } + + final long[] eventTimeNanoSamples = mEventTimeNanoSamples; + for (int i = 0; i < NS; i++) { + out.writeLong(eventTimeNanoSamples[i]); + } - private void readFromParcel(Parcel in) { - mDownTime = in.readLong(); - mEventTimeNano = in.readLong(); - mAction = in.readInt(); - mMetaState = in.readInt(); - mRawX = in.readFloat(); - mRawY = in.readFloat(); - final int NP = in.readInt(); - mNumPointers = NP; - final int NS = in.readInt(); - mNumSamples = NS; - final int NI = NP*NS; - if (NI > 0) { - int[] ids = mPointerIdentifiers; - if (ids.length < NP) { - mPointerIdentifiers = ids = new int[NP]; - } - for (int i=0; i<NP; i++) { - ids[i] = in.readInt(); - } - float[] history = mDataSamples; - final int ND = NI*NUM_SAMPLE_DATA; - if (history.length < ND) { - mDataSamples = history = new float[ND]; - } - for (int i=0; i<ND; i++) { - history[i] = in.readFloat(); - } - long[] times = mTimeSamples; - if (times == null || times.length < NS) { - mTimeSamples = times = new long[NS]; - } - for (int i=0; i<NS; i++) { - times[i] = in.readLong(); - } + final float[] dataSamples = mDataSamples; + for (int i = 0; i < NI; i++) { + out.writeFloat(dataSamples[i]); } - mXPrecision = in.readFloat(); - mYPrecision = in.readFloat(); - mDeviceId = in.readInt(); - mEdgeFlags = in.readInt(); } - } diff --git a/core/jni/android_view_InputChannel.cpp b/core/jni/android_view_InputChannel.cpp index 47bb073..4a4393a 100644 --- a/core/jni/android_view_InputChannel.cpp +++ b/core/jni/android_view_InputChannel.cpp @@ -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); diff --git a/core/jni/android_view_MotionEvent.cpp b/core/jni/android_view_MotionEvent.cpp index 629c8fe..78137e2 100644 --- a/core/jni/android_view_MotionEvent.cpp +++ b/core/jni/android_view_MotionEvent.cpp @@ -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); - - // 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. - - 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; - } + jlong* eventTimeNanoSamples = (jlong*)env->GetPrimitiveArrayCritical( + eventTimeNanoSampleArray, NULL); + + jfloat* srcDataSamples = dataSamples; + jlong* srcEventTimeNanoSamples = eventTimeNanoSamples; - 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; } diff --git a/include/ui/Input.h b/include/ui/Input.h index d45bfcf..92ff872 100644 --- a/include/ui/Input.h +++ b/include/ui/Input.h @@ -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,16 +227,20 @@ public: inline nsecs_t getEventTime() const { return mSampleEventTimes[getHistorySize()]; } - inline float getRawX() const { return mRawX; } + inline float getRawX(size_t pointerIndex) const { + return getCurrentPointerCoords(pointerIndex).x; + } - inline float getRawY() const { return mRawY; } + inline float getRawY(size_t pointerIndex) const { + return getCurrentPointerCoords(pointerIndex).y; + } inline float getX(size_t pointerIndex) const { - return getCurrentPointerCoords(pointerIndex).x; + return getRawX(pointerIndex) + mXOffset; } inline float getY(size_t pointerIndex) const { - return getCurrentPointerCoords(pointerIndex).y; + return getRawY(pointerIndex) + mYOffset; } inline float getPressure(size_t pointerIndex) const { @@ -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; diff --git a/include/ui/InputTransport.h b/include/ui/InputTransport.h index 9537523..7b182f3 100644 --- a/include/ui/InputTransport.h +++ b/include/ui/InputTransport.h @@ -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. diff --git a/include/utils/PollLoop.h b/include/utils/PollLoop.h index c9d951f..a95fb17 100644 --- a/include/utils/PollLoop.h +++ b/include/utils/PollLoop.h @@ -114,8 +114,10 @@ private: }; Mutex mLock; - Condition mAwake; bool mPolling; + uint32_t mWaiters; + Condition mAwake; + Condition mResume; int mWakeReadPipeFd; int mWakeWritePipeFd; diff --git a/include/utils/Vector.h b/include/utils/Vector.h index d40ae16..ec851bd 100644 --- a/include/utils/Vector.h +++ b/include/utils/Vector.h @@ -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 diff --git a/include/utils/VectorImpl.h b/include/utils/VectorImpl.h index 46a7bc2..c4ec2ff 100644 --- a/include/utils/VectorImpl.h +++ b/include/utils/VectorImpl.h @@ -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); diff --git a/libs/ui/Input.cpp b/libs/ui/Input.cpp index d367708..0e6f2f5 100644 --- a/libs/ui/Input.cpp +++ b/libs/ui/Input.cpp @@ -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( diff --git a/libs/ui/InputDispatcher.cpp b/libs/ui/InputDispatcher.cpp index f058271..14dcada 100644 --- a/libs/ui/InputDispatcher.cpp +++ b/libs/ui/InputDispatcher.cpp @@ -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); diff --git a/libs/ui/InputReader.cpp b/libs/ui/InputReader.cpp index 62b5f28..5a280ae 100644 --- a/libs/ui/InputReader.cpp +++ b/libs/ui/InputReader.cpp @@ -19,6 +19,9 @@ // Log debug messages about pointers. #define DEBUG_POINTERS 1 +// Log debug messages about pointer assignment calculations. +#define DEBUG_POINTER_ASSIGNMENT 0 + #include <cutils/log.h> #include <ui/InputReader.h> @@ -57,6 +60,14 @@ inline static T min(const T& a, const T& b) { return a < b ? a : b; } +template<typename T> +inline static void swap(T& a, T& b) { + T temp = a; + a = b; + b = temp; +} + + int32_t updateMetaState(int32_t keyCode, bool down, int32_t oldMetaState) { int32_t mask; switch (keyCode) { @@ -188,6 +199,12 @@ void InputDevice::TouchScreenState::reset() { jumpyTouchFilter.jumpyPointsDropped = 0; } +struct PointerDistanceHeapElement { + uint32_t currentPointerIndex : 8; + uint32_t lastPointerIndex : 8; + uint64_t distance : 48; // squared distance +}; + void InputDevice::TouchScreenState::calculatePointerIds() { uint32_t currentPointerCount = currentTouch.pointerCount; uint32_t lastPointerCount = lastTouch.pointerCount; @@ -214,11 +231,7 @@ void InputDevice::TouchScreenState::calculatePointerIds() { // We build a heap of squared euclidean distances between current and last pointers // associated with the current and last pointer indices. Then, we find the best // match (by distance) for each current pointer. - struct { - uint32_t currentPointerIndex : 8; - uint32_t lastPointerIndex : 8; - uint64_t distance : 48; // squared distance - } heap[MAX_POINTERS * MAX_POINTERS]; + PointerDistanceHeapElement heap[MAX_POINTERS * MAX_POINTERS]; uint32_t heapSize = 0; for (uint32_t currentPointerIndex = 0; currentPointerIndex < currentPointerCount; @@ -233,23 +246,45 @@ void InputDevice::TouchScreenState::calculatePointerIds() { uint64_t distance = uint64_t(deltaX * deltaX + deltaY * deltaY); // Insert new element into the heap (sift up). + heap[heapSize].currentPointerIndex = currentPointerIndex; + heap[heapSize].lastPointerIndex = lastPointerIndex; + heap[heapSize].distance = distance; heapSize += 1; - uint32_t insertionIndex = heapSize; - while (insertionIndex > 1) { - uint32_t parentIndex = (insertionIndex - 1) / 2; - if (distance < heap[parentIndex].distance) { - heap[insertionIndex] = heap[parentIndex]; - insertionIndex = parentIndex; - } else { - break; - } + } + } + + // 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; diff --git a/libs/ui/InputTransport.cpp b/libs/ui/InputTransport.cpp index a24180f..86bbd37 100644 --- a/libs/ui/InputTransport.cpp +++ b/libs/ui/InputTransport.cpp @@ -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 diff --git a/libs/ui/tests/Android.mk b/libs/ui/tests/Android.mk index 1ff896b..46d7493 100644 --- a/libs/ui/tests/Android.mk +++ b/libs/ui/tests/Android.mk @@ -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 \ diff --git a/libs/ui/tests/InputChannel_test.cpp b/libs/ui/tests/InputChannel_test.cpp new file mode 100644 index 0000000..6cec1c0 --- /dev/null +++ b/libs/ui/tests/InputChannel_test.cpp @@ -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 diff --git a/libs/ui/tests/InputDispatcher_test.cpp b/libs/ui/tests/InputDispatcher_test.cpp index 3d92043..1dc6e46 100644 --- a/libs/ui/tests/InputDispatcher_test.cpp +++ b/libs/ui/tests/InputDispatcher_test.cpp @@ -12,8 +12,7 @@ public: }; TEST_F(InputDispatcherTest, Dummy) { - SCOPED_TRACE("Trace"); - ASSERT_FALSE(true); + // TODO } } // namespace android diff --git a/libs/ui/tests/InputPublisherAndConsumer_test.cpp b/libs/ui/tests/InputPublisherAndConsumer_test.cpp new file mode 100644 index 0000000..2d6b531 --- /dev/null +++ b/libs/ui/tests/InputPublisherAndConsumer_test.cpp @@ -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 diff --git a/libs/utils/PollLoop.cpp b/libs/utils/PollLoop.cpp index 90a3e8b..20a4d13 100644 --- a/libs/utils/PollLoop.cpp +++ b/libs/utils/PollLoop.cpp @@ -11,7 +11,7 @@ #define DEBUG_POLL_AND_WAKE 0 // Debugs callback registration and invocation. -#define DEBUG_CALLBACKS 1 +#define DEBUG_CALLBACKS 0 #include <cutils/log.h> #include <utils/PollLoop.h> @@ -22,7 +22,7 @@ namespace android { PollLoop::PollLoop() : - mPolling(false) { + mPolling(false), mWaiters(0) { openWakePipe(); } @@ -68,6 +68,9 @@ void PollLoop::closeWakePipe() { bool PollLoop::pollOnce(int timeoutMillis) { mLock.lock(); + while (mWaiters != 0) { + mResume.wait(mLock); + } mPolling = true; mLock.unlock(); @@ -156,7 +159,9 @@ bool PollLoop::pollOnce(int timeoutMillis) { Done: mLock.lock(); mPolling = false; - mAwake.broadcast(); + if (mWaiters != 0) { + mAwake.broadcast(); + } mLock.unlock(); if (result) { @@ -258,10 +263,15 @@ ssize_t PollLoop::getRequestIndexLocked(int fd) { void PollLoop::wakeAndLock() { mLock.lock(); + mWaiters += 1; while (mPolling) { wake(); mAwake.wait(mLock); } + mWaiters -= 1; + if (mWaiters == 0) { + mResume.signal(); + } } } // namespace android diff --git a/libs/utils/VectorImpl.cpp b/libs/utils/VectorImpl.cpp index b09c6ca..289c826 100644 --- a/libs/utils/VectorImpl.cpp +++ b/libs/utils/VectorImpl.cpp @@ -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) diff --git a/libs/utils/tests/PollLoop_test.cpp b/libs/utils/tests/PollLoop_test.cpp index 6c719c8..4848c0f 100644 --- a/libs/utils/tests/PollLoop_test.cpp +++ b/libs/utils/tests/PollLoop_test.cpp @@ -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"; diff --git a/libs/utils/tests/TestHelpers.h b/libs/utils/tests/TestHelpers.h index e55af3c..d8e985e 100644 --- a/libs/utils/tests/TestHelpers.h +++ b/libs/utils/tests/TestHelpers.h @@ -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; diff --git a/native/include/android/input.h b/native/include/android/input.h index ee2f664..193cbf3 100644 --- a/native/include/android/input.h +++ b/native/include/android/input.h @@ -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 diff --git a/services/jni/com_android_server_InputManager.cpp b/services/jni/com_android_server_InputManager.cpp index a988a96..ab3922f 100644 --- a/services/jni/com_android_server_InputManager.cpp +++ b/services/jni/com_android_server_InputManager.cpp @@ -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, |