diff options
| -rw-r--r-- | api/current.xml | 46 | ||||
| -rw-r--r-- | core/java/android/view/MotionEvent.java | 367 | ||||
| -rw-r--r-- | core/java/android/view/RawInputEvent.java | 15 | ||||
| -rw-r--r-- | include/ui/EventHub.h | 5 | ||||
| -rw-r--r-- | libs/ui/EventHub.cpp | 90 | ||||
| -rw-r--r-- | services/java/com/android/server/InputDevice.java | 442 | ||||
| -rw-r--r-- | services/java/com/android/server/KeyInputQueue.java | 352 |
7 files changed, 906 insertions, 411 deletions
diff --git a/api/current.xml b/api/current.xml index f65b5ce..c4cac83 100644 --- a/api/current.xml +++ b/api/current.xml @@ -145940,6 +145940,19 @@ visibility="public" > </method> +<method name="findPointerIndex" + return="int" + abstract="false" + native="false" + synchronized="false" + static="false" + final="true" + deprecated="not deprecated" + visibility="public" +> +<parameter name="pointerId" type="int"> +</parameter> +</method> <method name="getAction" return="int" abstract="false" @@ -146031,7 +146044,7 @@ deprecated="not deprecated" visibility="public" > -<parameter name="pointer" type="int"> +<parameter name="pointerIndex" type="int"> </parameter> <parameter name="pos" type="int"> </parameter> @@ -146059,7 +146072,7 @@ deprecated="not deprecated" visibility="public" > -<parameter name="pointer" type="int"> +<parameter name="pointerIndex" type="int"> </parameter> <parameter name="pos" type="int"> </parameter> @@ -146087,7 +146100,7 @@ deprecated="not deprecated" visibility="public" > -<parameter name="pointer" type="int"> +<parameter name="pointerIndex" type="int"> </parameter> <parameter name="pos" type="int"> </parameter> @@ -146115,7 +146128,7 @@ deprecated="not deprecated" visibility="public" > -<parameter name="pointer" type="int"> +<parameter name="pointerIndex" type="int"> </parameter> <parameter name="pos" type="int"> </parameter> @@ -146153,6 +146166,19 @@ visibility="public" > </method> +<method name="getPointerId" + return="int" + abstract="false" + native="false" + synchronized="false" + static="false" + final="true" + deprecated="not deprecated" + visibility="public" +> +<parameter name="index" type="int"> +</parameter> +</method> <method name="getPressure" return="float" abstract="false" @@ -146174,7 +146200,7 @@ deprecated="not deprecated" visibility="public" > -<parameter name="pointer" type="int"> +<parameter name="pointerIndex" type="int"> </parameter> </method> <method name="getRawX" @@ -146220,7 +146246,7 @@ deprecated="not deprecated" visibility="public" > -<parameter name="pointer" type="int"> +<parameter name="pointerIndex" type="int"> </parameter> </method> <method name="getX" @@ -146244,7 +146270,7 @@ deprecated="not deprecated" visibility="public" > -<parameter name="pointer" type="int"> +<parameter name="pointerIndex" type="int"> </parameter> </method> <method name="getXPrecision" @@ -146279,7 +146305,7 @@ deprecated="not deprecated" visibility="public" > -<parameter name="pointer" type="int"> +<parameter name="pointerIndex" type="int"> </parameter> </method> <method name="getYPrecision" @@ -146615,7 +146641,7 @@ visibility="public" > </field> -<field name="ACTION_POINTER_MASK" +<field name="ACTION_POINTER_ID_MASK" type="int" transient="false" volatile="false" @@ -146626,7 +146652,7 @@ visibility="public" > </field> -<field name="ACTION_POINTER_SHIFT" +<field name="ACTION_POINTER_ID_SHIFT" type="int" transient="false" volatile="false" diff --git a/core/java/android/view/MotionEvent.java b/core/java/android/view/MotionEvent.java index ae84e1e..d41d2d1 100644 --- a/core/java/android/view/MotionEvent.java +++ b/core/java/android/view/MotionEvent.java @@ -19,6 +19,7 @@ package android.view; import android.os.Parcel; import android.os.Parcelable; import android.os.SystemClock; +import android.util.Log; /** * Object used to report movement (mouse, pen, finger, trackball) events. This @@ -26,6 +27,8 @@ import android.os.SystemClock; * it is being used for. */ public final class MotionEvent implements Parcelable { + static final boolean DEBUG_POINTERS = false; + /** * Bit mask of the parts of the action code that are the action itself. */ @@ -68,58 +71,67 @@ public final class MotionEvent implements Parcelable { /** * A non-primary pointer has gone down. The bits in - * {@link #ACTION_POINTER_MASK} indicate which pointer changed. + * {@link #ACTION_POINTER_ID_MASK} indicate which pointer changed. */ public static final int ACTION_POINTER_DOWN = 5; /** - * The primary pointer has gone done. + * Synonym for {@link #ACTION_POINTER_DOWN} with + * {@link #ACTION_POINTER_ID_MASK} of 0: the primary pointer has gone done. */ public static final int ACTION_POINTER_1_DOWN = ACTION_POINTER_DOWN | 0x0000; /** - * The secondary pointer has gone done. + * Synonym for {@link #ACTION_POINTER_DOWN} with + * {@link #ACTION_POINTER_ID_MASK} of 1: the secondary pointer has gone done. */ public static final int ACTION_POINTER_2_DOWN = ACTION_POINTER_DOWN | 0x0100; /** - * The tertiary pointer has gone done. + * Synonym for {@link #ACTION_POINTER_DOWN} with + * {@link #ACTION_POINTER_ID_MASK} of 2: the tertiary pointer has gone done. */ public static final int ACTION_POINTER_3_DOWN = ACTION_POINTER_DOWN | 0x0200; /** * A non-primary pointer has gone up. The bits in - * {@link #ACTION_POINTER_MASK} indicate which pointer changed. + * {@link #ACTION_POINTER_ID_MASK} indicate which pointer changed. */ public static final int ACTION_POINTER_UP = 6; /** - * The primary pointer has gone up. + * Synonym for {@link #ACTION_POINTER_UP} with + * {@link #ACTION_POINTER_ID_MASK} of 0: the primary pointer has gone up. */ public static final int ACTION_POINTER_1_UP = ACTION_POINTER_UP | 0x0000; /** - * The secondary pointer has gone up. + * Synonym for {@link #ACTION_POINTER_UP} with + * {@link #ACTION_POINTER_ID_MASK} of 1: the secondary pointer has gone up. */ public static final int ACTION_POINTER_2_UP = ACTION_POINTER_UP | 0x0100; /** - * The tertiary pointer has gone up. + * Synonym for {@link #ACTION_POINTER_UP} with + * {@link #ACTION_POINTER_ID_MASK} of 2: the tertiary pointer has gone up. */ public static final int ACTION_POINTER_3_UP = ACTION_POINTER_UP | 0x0200; /** * Bits in the action code that represent a pointer ID, used with * {@link #ACTION_POINTER_DOWN} and {@link #ACTION_POINTER_UP}. Pointer IDs - * start at 0, with 0 being the primary (first) pointer in the motion. + * start at 0, with 0 being the primary (first) pointer in the motion. Note + * that this not <em>not</em> an index into the array of pointer values, + * which is compacted to only contain pointers that are down; the pointer + * ID for a particular index can be found with {@link #findPointerIndex}. */ - public static final int ACTION_POINTER_MASK = 0xff00; + public static final int ACTION_POINTER_ID_MASK = 0xff00; /** * Bit shift for the action bits holding the pointer identifier as - * defined by {@link #ACTION_POINTER_MASK}. + * defined by {@link #ACTION_POINTER_ID_MASK}. */ - public static final int ACTION_POINTER_SHIFT = 8; + public static final int ACTION_POINTER_ID_SHIFT = 8; private static final boolean TRACK_RECYCLED_LOCATION = false; @@ -144,18 +156,6 @@ public final class MotionEvent implements Parcelable { public static final int EDGE_RIGHT = 0x00000008; /** - * This is the part of the state data that holds the finger identifier - * for the sample. - */ - static private final int STATE_FINGER_ID_MASK = 0xff; - - /** - * Special value for STATE_FINGER_ID_MASK indicating that the finger - * is not down in that sample. - */ - static private final int STATE_FINGER_ID_NONE = 0xff; - - /** * Offset for the sample's X coordinate. * @hide */ @@ -212,8 +212,8 @@ public final class MotionEvent implements Parcelable { private int mNumPointers; private int mNumSamples; - // Array of (mNumSamples * mNumPointers) size of control data. - private int[] mStateSamples; + // 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. private float[] mDataSamples; // Array of mNumSamples size of time stamps. @@ -224,7 +224,7 @@ public final class MotionEvent implements Parcelable { private boolean mRecycled; private MotionEvent() { - mStateSamples = new int[BASE_AVAIL_POINTERS*BASE_AVAIL_SAMPLES]; + mPointerIdentifiers = new int[BASE_AVAIL_POINTERS]; mDataSamples = new float[BASE_AVAIL_POINTERS*BASE_AVAIL_SAMPLES*NUM_SAMPLE_DATA]; mTimeSamples = new long[BASE_AVAIL_SAMPLES]; } @@ -256,16 +256,11 @@ public final class MotionEvent implements Parcelable { * @param action The kind of action being performed -- one of either * {@link #ACTION_DOWN}, {@link #ACTION_MOVE}, {@link #ACTION_UP}, or * {@link #ACTION_CANCEL}. - * @param x The X coordinate of this event. - * @param y The Y coordinate of this event. - * @param pressure The current pressure of this event. The pressure generally - * ranges from 0 (no pressure at all) to 1 (normal pressure), however - * values higher than 1 may be generated depending on the calibration of - * the input device. - * @param size A scaled value of the approximate size of the area being pressed when - * touched with the finger. The actual value in pixels corresponding to the finger - * touch is normalized with a device specific range of values - * and scaled to a value between 0 and 1. + * @param pointers The number of points that will be in this event. + * @param inPointerIds An array of <em>pointers</em> values providing + * an identifier for each pointer. + * @param inData An array of <em>pointers*NUM_SAMPLE_DATA</em> of initial + * data samples for the event. * @param metaState The state of any meta / modifier keys that were in effect when * the event was generated. * @param xPrecision The precision of the X coordinate being reported. @@ -279,7 +274,7 @@ public final class MotionEvent implements Parcelable { * @hide */ static public MotionEvent obtainNano(long downTime, long eventTime, long eventTimeNano, - int action, int pointers, float[] inData, int metaState, + int action, int pointers, int[] inPointerIds, float[] inData, int metaState, float xPrecision, float yPrecision, int deviceId, int edgeFlags) { MotionEvent ev = obtain(); ev.mDeviceId = deviceId; @@ -295,17 +290,25 @@ public final class MotionEvent implements Parcelable { ev.mNumPointers = pointers; ev.mNumSamples = 1; - float[] data = ev.mDataSamples; - System.arraycopy(inData, 0, data, 0, pointers * NUM_SAMPLE_DATA); - - int[] state = ev.mStateSamples; - while (pointers > 0) { - pointers--; - state[pointers] = pointers; - } - + System.arraycopy(inPointerIds, 0, ev.mPointerIdentifiers, 0, pointers); + System.arraycopy(inData, 0, ev.mDataSamples, 0, pointers * NUM_SAMPLE_DATA); ev.mTimeSamples[0] = eventTime; + if (DEBUG_POINTERS) { + StringBuilder sb = new StringBuilder(128); + sb.append("New:"); + for (int i=0; i<pointers; i++) { + sb.append(" #"); + sb.append(ev.mPointerIdentifiers[i]); + sb.append("("); + sb.append(ev.mDataSamples[(i*NUM_SAMPLE_DATA) + SAMPLE_X]); + sb.append(","); + sb.append(ev.mDataSamples[(i*NUM_SAMPLE_DATA) + SAMPLE_Y]); + sb.append(")"); + } + Log.v("MotionEvent", sb.toString()); + } + return ev; } @@ -355,8 +358,8 @@ public final class MotionEvent implements Parcelable { ev.mNumPointers = 1; ev.mNumSamples = 1; - int[] state = ev.mStateSamples; - state[0] = 0; + int[] pointerIds = ev.mPointerIdentifiers; + pointerIds[0] = 0; float[] data = ev.mDataSamples; data[SAMPLE_X] = ev.mRawX = x; data[SAMPLE_Y] = ev.mRawY = y; @@ -415,8 +418,8 @@ public final class MotionEvent implements Parcelable { ev.mNumPointers = 1; ev.mNumSamples = 1; - int[] state = ev.mStateSamples; - state[0] = 0; + int[] pointerIds = ev.mPointerIdentifiers; + pointerIds[0] = 0; float[] data = ev.mDataSamples; data[SAMPLE_X] = ev.mRawX = x; data[SAMPLE_Y] = ev.mRawY = y; @@ -459,8 +462,8 @@ public final class MotionEvent implements Parcelable { ev.mNumPointers = 1; ev.mNumSamples = 1; - int[] state = ev.mStateSamples; - state[0] = 0; + int[] pointerIds = ev.mPointerIdentifiers; + pointerIds[0] = 0; float[] data = ev.mDataSamples; data[SAMPLE_X] = ev.mRawX = x; data[SAMPLE_Y] = ev.mRawY = y; @@ -508,21 +511,21 @@ public final class MotionEvent implements Parcelable { ev.mXPrecision = o.mXPrecision; ev.mYPrecision = o.mYPrecision; - final int NT = ev.mNumSamples = o.mNumSamples; - if (ev.mTimeSamples.length >= NT) { - System.arraycopy(o.mTimeSamples, 0, ev.mTimeSamples, 0, NT); + 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(); } - final int NS = (ev.mNumPointers=o.mNumPointers) * NT; - if (ev.mStateSamples.length >= NS) { - System.arraycopy(o.mStateSamples, 0, ev.mStateSamples, 0, NS); + final int NP = (ev.mNumPointers=o.mNumPointers); + if (ev.mPointerIdentifiers.length >= NP) { + System.arraycopy(o.mPointerIdentifiers, 0, ev.mPointerIdentifiers, 0, NP); } else { - ev.mStateSamples = (int[])o.mStateSamples.clone(); + ev.mPointerIdentifiers = (int[])o.mPointerIdentifiers.clone(); } - final int ND = NS * NUM_SAMPLE_DATA; + final int ND = NP * NS * NUM_SAMPLE_DATA; if (ev.mDataSamples.length >= ND) { System.arraycopy(o.mDataSamples, 0, ev.mDataSamples, 0, ND); } else { @@ -593,88 +596,131 @@ public final class MotionEvent implements Parcelable { } /** - * The number of pointers of data contained in this event. Always - * >= 1. - */ - public final int getPointerCount() { - return mNumPointers; - } - - /** - * {@link #getX(int)} for the first pointer (pointer 0). + * {@link #getX(int)} for the first pointer index (may be an + * arbitrary pointer identifier). */ public final float getX() { return mDataSamples[SAMPLE_X]; } /** - * {@link #getY(int)} for the first pointer (pointer 0). + * {@link #getY(int)} for the first pointer index (may be an + * arbitrary pointer identifier). */ public final float getY() { return mDataSamples[SAMPLE_Y]; } /** - * {@link #getPressure(int)} for the first pointer (pointer 0). + * {@link #getPressure(int)} for the first pointer index (may be an + * arbitrary pointer identifier). */ public final float getPressure() { return mDataSamples[SAMPLE_PRESSURE]; } /** - * {@link #getSize(int)} for the first pointer (pointer 0). + * {@link #getSize(int)} for the first pointer index (may be an + * arbitrary pointer identifier). */ public final float getSize() { return mDataSamples[SAMPLE_SIZE]; } /** - * Returns the X coordinate of this event for the given pointer. + * The number of pointers of data contained in this event. Always + * >= 1. + */ + public final int getPointerCount() { + return mNumPointers; + } + + /** + * Return the pointer identifier associated with a particular pointer + * data index is this event. The identifier tells you the actual pointer + * number associated with the data, accounting for individual pointers + * going up and down since the start of the current gesture. + * @param pointerIndex Raw index of pointer to retrieve. Value may be from 0 + * (the first pointer that is down) to {@link #getPointerCount()}-1. + */ + public final int getPointerId(int index) { + return mPointerIdentifiers[index]; + } + + /** + * Given a pointer identifier, find the index of its data in the event. + * + * @param pointerId The identifier of the pointer to be found. + * @return Returns either the index of the pointer (for use with + * {@link #getX(int) et al.), or -1 if there is no data available for + * that pointer identifier. + */ + public final int findPointerIndex(int pointerId) { + int i = mNumPointers; + while (i > 0) { + i--; + if (mPointerIdentifiers[i] == pointerId) { + return i; + } + } + return -1; + } + + /** + * Returns the X coordinate of this event for the given pointer + * <em>index</em> (use {@link #getPointerId(int)} to find the pointer + * identifier for this index). * Whole numbers are pixels; the * value may have a fraction for input devices that are sub-pixel precise. - * @param pointer The desired pointer to retrieve. Value may be from 0 - * (the first pointer) to {@link #getPointerCount()}-1. + * @param pointerIndex Raw index of pointer to retrieve. Value may be from 0 + * (the first pointer that is down) to {@link #getPointerCount()}-1. */ - public final float getX(int pointer) { - return mDataSamples[(pointer*NUM_SAMPLE_DATA) + SAMPLE_X]; + public final float getX(int pointerIndex) { + return mDataSamples[(pointerIndex*NUM_SAMPLE_DATA) + SAMPLE_X]; } /** - * Returns the Y coordinate of this event for the given pointer. + * Returns the Y coordinate of this event for the given pointer + * <em>index</em> (use {@link #getPointerId(int)} to find the pointer + * identifier for this index). * Whole numbers are pixels; the * value may have a fraction for input devices that are sub-pixel precise. - * @param pointer The desired pointer to retrieve. Value may be from 0 - * (the first pointer) to {@link #getPointerCount()}-1. + * @param pointerIndex Raw index of pointer to retrieve. Value may be from 0 + * (the first pointer that is down) to {@link #getPointerCount()}-1. */ - public final float getY(int pointer) { - return mDataSamples[(pointer*NUM_SAMPLE_DATA) + SAMPLE_Y]; + public final float getY(int pointerIndex) { + return mDataSamples[(pointerIndex*NUM_SAMPLE_DATA) + SAMPLE_Y]; } /** - * Returns the current pressure of this event for the given pointer. + * Returns the current pressure of this event for the given pointer + * <em>index</em> (use {@link #getPointerId(int)} to find the pointer + * identifier for this index). * The pressure generally * ranges from 0 (no pressure at all) to 1 (normal pressure), however * values higher than 1 may be generated depending on the calibration of * the input device. - * @param pointer The desired pointer to retrieve. Value may be from 0 - * (the first pointer) to {@link #getPointerCount()}-1. + * @param pointerIndex Raw index of pointer to retrieve. Value may be from 0 + * (the first pointer that is down) to {@link #getPointerCount()}-1. */ - public final float getPressure(int pointer) { - return mDataSamples[(pointer*NUM_SAMPLE_DATA) + SAMPLE_PRESSURE]; + public final float getPressure(int pointerIndex) { + return mDataSamples[(pointerIndex*NUM_SAMPLE_DATA) + SAMPLE_PRESSURE]; } /** - * Returns a scaled value of the approximate size for the given pointer, - * representing the area of the screen being pressed. - * The actual value in pixels corresponding to the + * Returns a scaled value of the approximate size for the given pointer + * <em>index</em> (use {@link #getPointerId(int)} to find the pointer + * identifier for this index). + * This represents some approximation of the area of the screen being + * pressed; the actual value in pixels corresponding to the * touch is normalized with the device specific range of values * and scaled to a value between 0 and 1. The value of size can be used to * determine fat touch events. - * @param pointer The desired pointer to retrieve. Value may be from 0 - * (the first pointer) to {@link #getPointerCount()}-1. + * @param pointerIndex Raw index of pointer to retrieve. Value may be from 0 + * (the first pointer that is down) to {@link #getPointerCount()}-1. */ - public final float getSize(int pointer) { - return mDataSamples[(pointer*NUM_SAMPLE_DATA) + SAMPLE_SIZE]; + public final float getSize(int pointerIndex) { + return mDataSamples[(pointerIndex*NUM_SAMPLE_DATA) + SAMPLE_SIZE]; } /** @@ -758,99 +804,107 @@ public final class MotionEvent implements Parcelable { } /** - * {@link #getHistoricalX(int)} for the first pointer (pointer 0). + * {@link #getHistoricalX(int)} for the first pointer index (may be an + * arbitrary pointer identifier). */ public final float getHistoricalX(int pos) { return mDataSamples[((pos + 1) * NUM_SAMPLE_DATA * mNumPointers) + SAMPLE_X]; } /** - * {@link #getHistoricalY(int)} for the first pointer (pointer 0). + * {@link #getHistoricalY(int)} for the first pointer index (may be an + * arbitrary pointer identifier). */ public final float getHistoricalY(int pos) { return mDataSamples[((pos + 1) * NUM_SAMPLE_DATA * mNumPointers) + SAMPLE_Y]; } /** - * {@link #getHistoricalPressure(int)} for the first pointer (pointer 0). + * {@link #getHistoricalPressure(int)} for the first pointer index (may be an + * arbitrary pointer identifier). */ public final float getHistoricalPressure(int pos) { return mDataSamples[((pos + 1) * NUM_SAMPLE_DATA * mNumPointers) + SAMPLE_PRESSURE]; } /** - * {@link #getHistoricalSize(int)} for the first pointer (pointer 0). + * {@link #getHistoricalSize(int)} for the first pointer index (may be an + * arbitrary pointer identifier). */ public final float getHistoricalSize(int pos) { return mDataSamples[((pos + 1) * NUM_SAMPLE_DATA * mNumPointers) + SAMPLE_SIZE]; } /** - * Returns a historical X coordinate that occurred between this event - * and the previous event for the given pointer. Only applies to ACTION_MOVE events. + * Returns a historical X coordinate, as per {@link #getX(int)}, that + * occurred between this event and the previous event for the given pointer. + * Only applies to ACTION_MOVE events. * - * @param pointer The desired pointer to retrieve. Value may be from 0 - * (the first pointer) to {@link #getPointerCount()}-1. + * @param pointerIndex Raw index of pointer to retrieve. Value may be from 0 + * (the first pointer that is down) to {@link #getPointerCount()}-1. * @param pos Which historical value to return; must be less than * {@link #getHistorySize} * * @see #getHistorySize * @see #getX */ - public final float getHistoricalX(int pointer, int pos) { + public final float getHistoricalX(int pointerIndex, int pos) { return mDataSamples[((pos + 1) * NUM_SAMPLE_DATA * mNumPointers) - + (pointer * NUM_SAMPLE_DATA) + SAMPLE_X]; + + (pointerIndex * NUM_SAMPLE_DATA) + SAMPLE_X]; } /** - * Returns a historical Y coordinate that occurred between this event - * and the previous event for the given pointer. Only applies to ACTION_MOVE events. + * Returns a historical Y coordinate, as per {@link #getY(int)}, that + * occurred between this event and the previous event for the given pointer. + * Only applies to ACTION_MOVE events. * - * @param pointer The desired pointer to retrieve. Value may be from 0 - * (the first pointer) to {@link #getPointerCount()}-1. + * @param pointerIndex Raw index of pointer to retrieve. Value may be from 0 + * (the first pointer that is down) to {@link #getPointerCount()}-1. * @param pos Which historical value to return; must be less than * {@link #getHistorySize} * * @see #getHistorySize * @see #getY */ - public final float getHistoricalY(int pointer, int pos) { + public final float getHistoricalY(int pointerIndex, int pos) { return mDataSamples[((pos + 1) * NUM_SAMPLE_DATA * mNumPointers) - + (pointer * NUM_SAMPLE_DATA) + SAMPLE_Y]; + + (pointerIndex * NUM_SAMPLE_DATA) + SAMPLE_Y]; } /** - * Returns a historical pressure coordinate that occurred between this event - * and the previous event for the given pointer. Only applies to ACTION_MOVE events. + * Returns a historical pressure coordinate, as per {@link #getPressure(int)}, + * that occurred between this event and the previous event for the given + * pointer. Only applies to ACTION_MOVE events. * + * @param pointerIndex Raw index of pointer to retrieve. Value may be from 0 + * (the first pointer that is down) to {@link #getPointerCount()}-1. * @param pos Which historical value to return; must be less than * {@link #getHistorySize} - * - * @param pointer The desired pointer to retrieve. Value may be from 0 - * (the first pointer) to {@link #getPointerCount()}-1. + * * @see #getHistorySize * @see #getPressure */ - public final float getHistoricalPressure(int pointer, int pos) { + public final float getHistoricalPressure(int pointerIndex, int pos) { return mDataSamples[((pos + 1) * NUM_SAMPLE_DATA * mNumPointers) - + (pointer * NUM_SAMPLE_DATA) + SAMPLE_PRESSURE]; + + (pointerIndex * NUM_SAMPLE_DATA) + SAMPLE_PRESSURE]; } /** - * Returns a historical size coordinate that occurred between this event - * and the previous event for the given pointer. Only applies to ACTION_MOVE events. + * Returns a historical size coordinate, as per {@link #getSize(int)}, that + * occurred between this event and the previous event for the given pointer. + * Only applies to ACTION_MOVE events. * + * @param pointerIndex Raw index of pointer to retrieve. Value may be from 0 + * (the first pointer that is down) to {@link #getPointerCount()}-1. * @param pos Which historical value to return; must be less than * {@link #getHistorySize} - * - * @param pointer The desired pointer to retrieve. Value may be from 0 - * (the first pointer) to {@link #getPointerCount()}-1. + * * @see #getHistorySize * @see #getSize */ - public final float getHistoricalSize(int pointer, int pos) { + public final float getHistoricalSize(int pointerIndex, int pos) { return mDataSamples[((pos + 1) * NUM_SAMPLE_DATA * mNumPointers) - + (pointer * NUM_SAMPLE_DATA) + SAMPLE_SIZE]; + + (pointerIndex * NUM_SAMPLE_DATA) + SAMPLE_SIZE]; } /** @@ -938,7 +992,6 @@ public final class MotionEvent implements Parcelable { */ public final void addBatch(long eventTime, float x, float y, float pressure, float size, int metaState) { - int[] states = mStateSamples; float[] data = mDataSamples; long[] times = mTimeSamples; @@ -946,14 +999,8 @@ public final class MotionEvent implements Parcelable { final int NS = mNumSamples; final int NI = NP*NS; final int ND = NI * NUM_SAMPLE_DATA; - if (states.length < (NI+NP)) { - // The state and data arrays are sized together, since their - // size is always a fixed factor from each other. - final int NEW_NI = NP * (NS+BASE_AVAIL_SAMPLES); - int[] newState = new int[NEW_NI]; - System.arraycopy(states, 0, newState, 0, NI); - mStateSamples = states = newState; - final int NEW_ND = NEW_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; @@ -996,7 +1043,6 @@ public final class MotionEvent implements Parcelable { * @hide */ public final void addBatch(long eventTime, float[] inData, int metaState) { - int[] states = mStateSamples; float[] data = mDataSamples; long[] times = mTimeSamples; @@ -1004,14 +1050,8 @@ public final class MotionEvent implements Parcelable { final int NS = mNumSamples; final int NI = NP*NS; final int ND = NI * NUM_SAMPLE_DATA; - if (states.length < (NI+NP)) { - // The state and data arrays are sized together, since their - // size is always a fixed factor from each other. - final int NEW_NI = NP * (NS+BASE_AVAIL_SAMPLES); - int[] newState = new int[NEW_NI]; - System.arraycopy(states, 0, newState, 0, NI); - mStateSamples = states = newState; - final int NEW_ND = NEW_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; @@ -1034,6 +1074,21 @@ public final class MotionEvent implements Parcelable { 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++) { + sb.append(" #"); + sb.append(mPointerIdentifiers[i]); + sb.append("("); + sb.append(mDataSamples[(i*NUM_SAMPLE_DATA) + SAMPLE_X]); + sb.append(","); + sb.append(mDataSamples[(i*NUM_SAMPLE_DATA) + SAMPLE_Y]); + sb.append(")"); + } + Log.v("MotionEvent", sb.toString()); + } } @Override @@ -1074,13 +1129,13 @@ public final class MotionEvent implements Parcelable { final int NI = NP*NS; if (NI > 0) { int i; - int[] state = mStateSamples; - for (i=0; i<NI; i++) { + int[] state = mPointerIdentifiers; + for (i=0; i<NP; i++) { out.writeInt(state[i]); } - final int NI4 = NI*NUM_SAMPLE_DATA; + final int ND = NI*NUM_SAMPLE_DATA; float[] history = mDataSamples; - for (i=0; i<NI4; i++) { + for (i=0; i<ND; i++) { out.writeFloat(history[i]); } long[] times = mTimeSamples; @@ -1107,19 +1162,19 @@ public final class MotionEvent implements Parcelable { mNumSamples = NS; final int NI = NP*NS; if (NI > 0) { - final int NI4 = NI*4; - int[] state = mStateSamples; - if (state.length < NI) { - mStateSamples = state = new int[NI]; + int[] ids = mPointerIdentifiers; + if (ids.length < NP) { + mPointerIdentifiers = ids = new int[NP]; } - for (int i=0; i<NI; i++) { - state[i] = in.readInt(); + for (int i=0; i<NP; i++) { + ids[i] = in.readInt(); } float[] history = mDataSamples; - if (history.length < NI4) { - mDataSamples = history = new float[NI4]; + final int ND = NI*NUM_SAMPLE_DATA; + if (history.length < ND) { + mDataSamples = history = new float[ND]; } - for (int i=0; i<NI4; i++) { + for (int i=0; i<ND; i++) { history[i] = in.readFloat(); } long[] times = mTimeSamples; diff --git a/core/java/android/view/RawInputEvent.java b/core/java/android/view/RawInputEvent.java index 30da83e..db024b4 100644 --- a/core/java/android/view/RawInputEvent.java +++ b/core/java/android/view/RawInputEvent.java @@ -13,6 +13,8 @@ public class RawInputEvent { public static final int CLASS_ALPHAKEY = 0x00000002; public static final int CLASS_TOUCHSCREEN = 0x00000004; public static final int CLASS_TRACKBALL = 0x00000008; + public static final int CLASS_TOUCHSCREEN_MT = 0x00000010; + public static final int CLASS_DPAD = 0x00000020; // More special classes for QueuedEvent below. public static final int CLASS_CONFIGURATION_CHANGED = 0x10000000; @@ -158,8 +160,21 @@ public class RawInputEvent { public static final int ABS_TOOL_WIDTH = 0x1c; public static final int ABS_VOLUME = 0x20; public static final int ABS_MISC = 0x28; + public static final int ABS_MT_TOUCH_MAJOR = 0x30; + public static final int ABS_MT_TOUCH_MINOR = 0x31; + public static final int ABS_MT_WIDTH_MAJOR = 0x32; + public static final int ABS_MT_WIDTH_MINOR = 0x33; + public static final int ABS_MT_ORIENTATION = 0x34; + public static final int ABS_MT_POSITION_X = 0x35; + public static final int ABS_MT_POSITION_Y = 0x36; + public static final int ABS_MT_TOOL_TYPE = 0x37; + public static final int ABS_MT_BLOB_ID = 0x38; public static final int ABS_MAX = 0x3f; + public static final int SYN_REPORT = 0; + public static final int SYN_CONFIG = 1; + public static final int SYN_MT_REPORT = 2; + public int deviceId; public int type; public int scancode; diff --git a/include/ui/EventHub.h b/include/ui/EventHub.h index d62fd7d..bffba07 100644 --- a/include/ui/EventHub.h +++ b/include/ui/EventHub.h @@ -55,7 +55,9 @@ public: CLASS_KEYBOARD = 0x00000001, CLASS_ALPHAKEY = 0x00000002, CLASS_TOUCHSCREEN = 0x00000004, - CLASS_TRACKBALL = 0x00000008 + CLASS_TRACKBALL = 0x00000008, + CLASS_TOUCHSCREEN_MT= 0x00000010, + CLASS_DPAD = 0x00000020 }; uint32_t getDeviceClasses(int32_t deviceId) const; @@ -122,6 +124,7 @@ private: }; device_t* getDevice(int32_t deviceId) const; + bool hasKeycode(device_t* device, int keycode) const; // Protect all internal state. mutable Mutex mLock; diff --git a/libs/ui/EventHub.cpp b/libs/ui/EventHub.cpp index 59c9476..27334b7 100644 --- a/libs/ui/EventHub.cpp +++ b/libs/ui/EventHub.cpp @@ -16,6 +16,7 @@ //#define LOG_NDEBUG 0 #include <ui/EventHub.h> +#include <ui/KeycodeLabels.h> #include <hardware_legacy/power.h> #include <cutils/properties.h> @@ -58,6 +59,18 @@ #define SEQ_SHIFT 16 #define id_to_index(id) ((id&ID_MASK)+1) +#ifndef ABS_MT_TOUCH_MAJOR +#define ABS_MT_TOUCH_MAJOR 0x30 /* Major axis of touching ellipse */ +#endif + +#ifndef ABS_MT_POSITION_X +#define ABS_MT_POSITION_X 0x35 /* Center X ellipse position */ +#endif + +#ifndef ABS_MT_POSITION_Y +#define ABS_MT_POSITION_Y 0x36 /* Center Y ellipse position */ +#endif + namespace android { static const char *WAKE_LOCK_ID = "KeyEvents"; @@ -590,6 +603,8 @@ int EventHub::open_device(const char *deviceName) mFDs[mFDCount].events = POLLIN; // figure out the kinds of events the device reports + + // See if this is a keyboard, and classify it. uint8_t key_bitmask[(KEY_MAX+1)/8]; memset(key_bitmask, 0, sizeof(key_bitmask)); LOGV("Getting keys..."); @@ -601,15 +616,11 @@ int EventHub::open_device(const char *deviceName) for (int i=0; i<((BTN_MISC+7)/8); i++) { if (key_bitmask[i] != 0) { device->classes |= CLASS_KEYBOARD; - // 'Q' key support = cheap test of whether this is an alpha-capable kbd - if (test_bit(KEY_Q, key_bitmask)) { - device->classes |= CLASS_ALPHAKEY; - } break; } } if ((device->classes & CLASS_KEYBOARD) != 0) { - device->keyBitmask = new uint8_t[(KEY_MAX+1)/8]; + device->keyBitmask = new uint8_t[sizeof(key_bitmask)]; if (device->keyBitmask != NULL) { memcpy(device->keyBitmask, key_bitmask, sizeof(key_bitmask)); } else { @@ -619,6 +630,8 @@ int EventHub::open_device(const char *deviceName) } } } + + // See if this is a trackball. if (test_bit(BTN_MOUSE, key_bitmask)) { uint8_t rel_bitmask[(REL_MAX+1)/8]; memset(rel_bitmask, 0, sizeof(rel_bitmask)); @@ -630,16 +643,22 @@ int EventHub::open_device(const char *deviceName) } } } - if (test_bit(BTN_TOUCH, key_bitmask)) { - uint8_t abs_bitmask[(ABS_MAX+1)/8]; - memset(abs_bitmask, 0, sizeof(abs_bitmask)); - LOGV("Getting absolute controllers..."); - if (ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(abs_bitmask)), abs_bitmask) >= 0) - { - if (test_bit(ABS_X, abs_bitmask) && test_bit(ABS_Y, abs_bitmask)) { - device->classes |= CLASS_TOUCHSCREEN; - } - } + + uint8_t abs_bitmask[(ABS_MAX+1)/8]; + memset(abs_bitmask, 0, sizeof(abs_bitmask)); + LOGV("Getting absolute controllers..."); + ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(abs_bitmask)), abs_bitmask); + + // Is this a new modern multi-touch driver? + if (test_bit(ABS_MT_TOUCH_MAJOR, abs_bitmask) + && test_bit(ABS_MT_POSITION_X, abs_bitmask) + && test_bit(ABS_MT_POSITION_Y, abs_bitmask)) { + device->classes |= CLASS_TOUCHSCREEN | CLASS_TOUCHSCREEN_MT; + + // Is this an old style single-touch driver? + } else if (test_bit(BTN_TOUCH, key_bitmask) + && test_bit(ABS_X, abs_bitmask) && test_bit(ABS_Y, abs_bitmask)) { + device->classes |= CLASS_TOUCHSCREEN; } #ifdef EV_SW @@ -658,9 +677,6 @@ int EventHub::open_device(const char *deviceName) } #endif - LOGI("New device: path=%s name=%s id=0x%x (of 0x%x) index=%d fd=%d classes=0x%x\n", - deviceName, name, device->id, mNumDevicesById, mFDCount, fd, device->classes); - if ((device->classes&CLASS_KEYBOARD) != 0) { char devname[101]; char tmpfn[101]; @@ -707,10 +723,27 @@ int EventHub::open_device(const char *deviceName) sprintf(propName, "hw.keyboards.%u.devname", publicID); property_set(propName, devname); - LOGI("New keyboard: publicID=%d device->id=%d devname='%s' propName='%s' keylayout='%s'\n", + // 'Q' key support = cheap test of whether this is an alpha-capable kbd + if (hasKeycode(device, kKeyCodeQ)) { + device->classes |= CLASS_ALPHAKEY; + } + + // See if this has a DPAD. + if (hasKeycode(device, kKeyCodeDpadUp) && + hasKeycode(device, kKeyCodeDpadDown) && + hasKeycode(device, kKeyCodeDpadLeft) && + hasKeycode(device, kKeyCodeDpadRight) && + hasKeycode(device, kKeyCodeDpadCenter)) { + device->classes |= CLASS_DPAD; + } + + LOGI("New keyboard: publicID=%d device->id=0x%x devname='%s' propName='%s' keylayout='%s'\n", publicID, device->id, devname, propName, keylayoutFilename); } + LOGI("New device: path=%s name=%s id=0x%x (of 0x%x) index=%d fd=%d classes=0x%x\n", + deviceName, name, device->id, mNumDevicesById, mFDCount, fd, device->classes); + LOGV("Adding device %s %p at %d, id = %d, classes = 0x%x\n", deviceName, device, mFDCount, devid, device->classes); @@ -723,6 +756,25 @@ int EventHub::open_device(const char *deviceName) return 0; } +bool EventHub::hasKeycode(device_t* device, int keycode) const +{ + if (device->keyBitmask == NULL || device->layoutMap == NULL) { + return false; + } + + Vector<int32_t> scanCodes; + device->layoutMap->findScancodes(keycode, &scanCodes); + const size_t N = scanCodes.size(); + for (size_t i=0; i<N && i<=KEY_MAX; i++) { + int32_t sc = scanCodes.itemAt(i); + if (sc >= 0 && sc <= KEY_MAX && test_bit(sc, device->keyBitmask)) { + return true; + } + } + + return false; +} + int EventHub::close_device(const char *deviceName) { AutoMutex _l(mLock); diff --git a/services/java/com/android/server/InputDevice.java b/services/java/com/android/server/InputDevice.java index 0ac5740..cb23c45 100644 --- a/services/java/com/android/server/InputDevice.java +++ b/services/java/com/android/server/InputDevice.java @@ -23,11 +23,13 @@ import android.view.Surface; import android.view.WindowManagerPolicy; public class InputDevice { + static final boolean DEBUG_POINTERS = false; + /** Amount that trackball needs to move in order to generate a key event. */ static final int TRACKBALL_MOVEMENT_THRESHOLD = 6; /** Maximum number of pointers we will track and report. */ - static final int MAX_POINTERS = 2; + static final int MAX_POINTERS = 10; final int id; final int classes; @@ -51,100 +53,316 @@ public class InputDevice { float yMoveScale; MotionEvent currentMove = null; boolean changed = false; - boolean mLastAnyDown = false; long mDownTime = 0; - final boolean[] mLastDown = new boolean[MAX_POINTERS]; - final boolean[] mDown = new boolean[MAX_POINTERS]; + + // The currently assigned pointer IDs, corresponding to the last data. + int[] mPointerIds = new int[MAX_POINTERS]; + + // This is the last generated pointer data, ordered to match + // mPointerIds. + int mLastNumPointers = 0; final int[] mLastData = new int[MotionEvent.NUM_SAMPLE_DATA * MAX_POINTERS]; - final int[] mCurData = new int[MotionEvent.NUM_SAMPLE_DATA * MAX_POINTERS]; + + // This is the next set of pointer data being generated. It is not + // in any known order, and will be propagated in to mLastData + // as part of mapping it to the appropriate pointer IDs. + // Note that we have one extra sample of data here, to help clients + // avoid doing bounds checking. + int mNextNumPointers = 0; + final int[] mNextData = new int[(MotionEvent.NUM_SAMPLE_DATA * MAX_POINTERS) + + MotionEvent.NUM_SAMPLE_DATA]; + + // Temporary data structures for doing the pointer ID mapping. + final int[] mLast2Next = new int[MAX_POINTERS]; + final int[] mNext2Last = new int[MAX_POINTERS]; + final long[] mNext2LastDistance = new long[MAX_POINTERS]; + + // Temporary data structure for generating the final motion data. final float[] mReportData = new float[MotionEvent.NUM_SAMPLE_DATA * MAX_POINTERS]; + // This is not used here, but can be used by callers for state tracking. + int mAddingPointerOffset = 0; + final boolean[] mDown = new boolean[MAX_POINTERS]; + MotionState(int mx, int my) { xPrecision = mx; yPrecision = my; xMoveScale = mx != 0 ? (1.0f/mx) : 1.0f; yMoveScale = my != 0 ? (1.0f/my) : 1.0f; + for (int i=0; i<MAX_POINTERS; i++) { + mPointerIds[i] = i; + } } - MotionEvent generateAbsMotion(InputDevice device, long curTime, - long curTimeNano, Display display, int orientation, - int metaState) { + private boolean assignPointer(int nextIndex, boolean allowOverlap) { + final int lastNumPointers = mLastNumPointers; + final int[] next2Last = mNext2Last; + final long[] next2LastDistance = mNext2LastDistance; + final int[] last2Next = mLast2Next; + final int[] lastData = mLastData; + final int[] nextData = mNextData; + final int id = nextIndex * MotionEvent.NUM_SAMPLE_DATA; - final float[] scaled = mReportData; - final int[] cur = mCurData; + if (DEBUG_POINTERS) Log.v("InputDevice", "assignPointer: nextIndex=" + + nextIndex + " dataOff=" + id); + final int x1 = nextData[id + MotionEvent.SAMPLE_X]; + final int y1 = nextData[id + MotionEvent.SAMPLE_Y]; - boolean anyDown = false; - int firstDownChanged = -1; - int numPointers = 0; - for (int i=0; i<MAX_POINTERS; i++) { - boolean d = mDown[i]; - anyDown |= d; - if (d != mLastDown[i] && firstDownChanged < 0) { - firstDownChanged = i; - mLastDown[i] = mDown[i]; - d = true; + long bestDistance = -1; + int bestIndex = -1; + for (int j=0; j<lastNumPointers; j++) { + if (!allowOverlap && last2Next[j] < 0) { + continue; + } + final int jd = j * MotionEvent.NUM_SAMPLE_DATA; + final int xd = lastData[jd + MotionEvent.SAMPLE_X] - x1; + final int yd = lastData[jd + MotionEvent.SAMPLE_Y] - y1; + final long distance = xd*(long)xd + yd*(long)yd; + if (j == 0 || distance < bestDistance) { + bestDistance = distance; + bestIndex = j; + } + } + + if (DEBUG_POINTERS) Log.v("InputDevice", "New index " + nextIndex + + " best old index=" + bestIndex + " (distance=" + + bestDistance + ")"); + next2Last[nextIndex] = bestIndex; + next2LastDistance[nextIndex] = bestDistance; + + if (bestIndex < 0) { + return true; + } + + if (last2Next[bestIndex] == -1) { + last2Next[bestIndex] = nextIndex; + return false; + } + + if (DEBUG_POINTERS) Log.v("InputDevice", "Old index " + bestIndex + + " has multiple best new pointers!"); + + last2Next[bestIndex] = -2; + return true; + } + + private int updatePointerIdentifiers() { + final int[] lastData = mLastData; + final int[] nextData = mNextData; + final int nextNumPointers = mNextNumPointers; + final int lastNumPointers = mLastNumPointers; + + if (nextNumPointers == 1 && lastNumPointers == 1) { + System.arraycopy(nextData, 0, lastData, 0, + MotionEvent.NUM_SAMPLE_DATA); + return -1; + } + + // Clear our old state. + final int[] last2Next = mLast2Next; + for (int i=0; i<lastNumPointers; i++) { + last2Next[i] = -1; + } + + if (DEBUG_POINTERS) Log.v("InputDevice", + "Update pointers: lastNumPointers=" + lastNumPointers + + " nextNumPointers=" + nextNumPointers); + + // Figure out the closes new points to the previous points. + final int[] next2Last = mNext2Last; + final long[] next2LastDistance = mNext2LastDistance; + boolean conflicts = false; + for (int i=0; i<nextNumPointers; i++) { + conflicts |= assignPointer(i, true); + } + + // Resolve ambiguities in pointer mappings, when two or more + // new pointer locations find their best previous location is + // the same. + if (conflicts) { + if (DEBUG_POINTERS) Log.v("InputDevice", "Resolving conflicts"); + + for (int i=0; i<lastNumPointers; i++) { + if (last2Next[i] != -2) { + continue; + } + + // Note that this algorithm is far from perfect. Ideally + // we should do something like the one described at + // http://portal.acm.org/citation.cfm?id=997856 + + if (DEBUG_POINTERS) Log.v("InputDevice", + "Resolving last index #" + i); + + int numFound; + do { + numFound = 0; + long worstDistance = 0; + int worstJ = -1; + for (int j=0; j<nextNumPointers; j++) { + if (next2Last[j] != i) { + continue; + } + numFound++; + if (worstDistance < next2LastDistance[j]) { + worstDistance = next2LastDistance[j]; + worstJ = j; + } + } + + if (worstJ >= 0) { + if (DEBUG_POINTERS) Log.v("InputDevice", + "Worst new pointer: " + worstJ + + " (distance=" + worstDistance + ")"); + if (assignPointer(worstJ, false)) { + // In this case there is no last pointer + // remaining for this new one! + next2Last[worstJ] = -1; + } + } + } while (numFound > 2); + } + } + + int retIndex = -1; + + if (lastNumPointers < nextNumPointers) { + // We have one or more new pointers that are down. Create a + // new pointer identifier for one of them. + if (DEBUG_POINTERS) Log.v("InputDevice", "Adding new pointer"); + int nextId = 0; + int i=0; + while (i < lastNumPointers) { + if (mPointerIds[i] > nextId) { + // Found a hole, insert the pointer here. + if (DEBUG_POINTERS) Log.v("InputDevice", + "Inserting new pointer at hole " + i); + System.arraycopy(mPointerIds, i, mPointerIds, + i+1, lastNumPointers-i); + System.arraycopy(lastData, i*MotionEvent.NUM_SAMPLE_DATA, + lastData, (i+1)*MotionEvent.NUM_SAMPLE_DATA, + (lastNumPointers-i)*MotionEvent.NUM_SAMPLE_DATA); + break; + } + i++; + nextId++; } - if (d) { - final int src = i * MotionEvent.NUM_SAMPLE_DATA; - final int dest = numPointers * MotionEvent.NUM_SAMPLE_DATA; - numPointers++; - scaled[dest + MotionEvent.SAMPLE_X] = cur[src + MotionEvent.SAMPLE_X]; - scaled[dest + MotionEvent.SAMPLE_Y] = cur[src + MotionEvent.SAMPLE_Y]; - scaled[dest + MotionEvent.SAMPLE_PRESSURE] = cur[src + MotionEvent.SAMPLE_PRESSURE]; - scaled[dest + MotionEvent.SAMPLE_SIZE] = cur[src + MotionEvent.SAMPLE_SIZE]; + if (DEBUG_POINTERS) Log.v("InputDevice", + "New pointer id " + nextId + " at index " + i); + + mLastNumPointers++; + retIndex = i; + mPointerIds[i] = nextId; + + // And assign this identifier to the first new pointer. + for (int j=0; j<nextNumPointers; j++) { + if (next2Last[j] < 0) { + if (DEBUG_POINTERS) Log.v("InputDevice", + "Assigning new id to new pointer index " + j); + next2Last[j] = i; + break; + } } } - if (numPointers <= 0) { + // Propagate all of the current data into the appropriate + // location in the old data to match the pointer ID that was + // assigned to it. + for (int i=0; i<nextNumPointers; i++) { + int lastIndex = next2Last[i]; + if (lastIndex >= 0) { + if (DEBUG_POINTERS) Log.v("InputDevice", + "Copying next pointer index " + i + + " to last index " + lastIndex); + System.arraycopy(nextData, i*MotionEvent.NUM_SAMPLE_DATA, + lastData, lastIndex*MotionEvent.NUM_SAMPLE_DATA, + MotionEvent.NUM_SAMPLE_DATA); + } + } + + if (lastNumPointers > nextNumPointers) { + // One or more pointers has gone up. Find the first one, + // and adjust accordingly. + if (DEBUG_POINTERS) Log.v("InputDevice", "Removing old pointer"); + for (int i=0; i<lastNumPointers; i++) { + if (last2Next[i] == -1) { + if (DEBUG_POINTERS) Log.v("InputDevice", + "Removing old pointer at index " + i); + retIndex = i; + break; + } + } + } + + return retIndex; + } + + void removeOldPointer(int index) { + final int lastNumPointers = mLastNumPointers; + if (index >= 0 && index < lastNumPointers) { + System.arraycopy(mPointerIds, index+1, mPointerIds, + index, lastNumPointers-index-1); + System.arraycopy(mLastData, (index+1)*MotionEvent.NUM_SAMPLE_DATA, + mLastData, (index)*MotionEvent.NUM_SAMPLE_DATA, + (lastNumPointers-index-1)*MotionEvent.NUM_SAMPLE_DATA); + mLastNumPointers--; + } + } + + MotionEvent generateAbsMotion(InputDevice device, long curTime, + long curTimeNano, Display display, int orientation, + int metaState) { + + if (mNextNumPointers <= 0 && mLastNumPointers <= 0) { return null; } + final int lastNumPointers = mLastNumPointers; + final int nextNumPointers = mNextNumPointers; + if (mNextNumPointers > MAX_POINTERS) { + Log.w("InputDevice", "Number of pointers " + mNextNumPointers + + " exceeded maximum of " + MAX_POINTERS); + mNextNumPointers = MAX_POINTERS; + } + + int upOrDownPointer = updatePointerIdentifiers(); + + final float[] reportData = mReportData; + final int[] rawData = mLastData; + + final int numPointers = mLastNumPointers; + + if (DEBUG_POINTERS) Log.v("InputDevice", "Processing " + + numPointers + " pointers (going from " + lastNumPointers + + " to " + nextNumPointers + ")"); + + for (int i=0; i<numPointers; i++) { + final int pos = i * MotionEvent.NUM_SAMPLE_DATA; + reportData[pos + MotionEvent.SAMPLE_X] = rawData[pos + MotionEvent.SAMPLE_X]; + reportData[pos + MotionEvent.SAMPLE_Y] = rawData[pos + MotionEvent.SAMPLE_Y]; + reportData[pos + MotionEvent.SAMPLE_PRESSURE] = rawData[pos + MotionEvent.SAMPLE_PRESSURE]; + reportData[pos + MotionEvent.SAMPLE_SIZE] = rawData[pos + MotionEvent.SAMPLE_SIZE]; + } + int action; int edgeFlags = 0; - if (anyDown != mLastAnyDown) { - final AbsoluteInfo absX = device.absX; - final AbsoluteInfo absY = device.absY; - if (anyDown && absX != null && absY != null) { - // We don't let downs start unless we are - // inside of the screen. There are two reasons for - // this: to avoid spurious touches when holding - // the edges of the device near the touchscreen, - // and to avoid reporting events if there are virtual - // keys on the touchscreen outside of the display - // area. - // Note that we are only looking at the first pointer, - // since what we are handling here is the first pointer - // going down, and this is the coordinate that will be - // used to dispatch the event. - if (cur[MotionEvent.SAMPLE_X] < absX.minValue - || cur[MotionEvent.SAMPLE_X] > absX.maxValue - || cur[MotionEvent.SAMPLE_Y] < absY.minValue - || cur[MotionEvent.SAMPLE_Y] > absY.maxValue) { - if (false) Log.v("InputDevice", "Rejecting (" - + cur[MotionEvent.SAMPLE_X] + "," - + cur[MotionEvent.SAMPLE_Y] + "): outside of (" - + absX.minValue + "," + absY.minValue - + ")-(" + absX.maxValue + "," - + absY.maxValue + ")"); - return null; + if (nextNumPointers != lastNumPointers) { + if (nextNumPointers > lastNumPointers) { + if (lastNumPointers == 0) { + action = MotionEvent.ACTION_DOWN; + mDownTime = curTime; + } else { + action = MotionEvent.ACTION_POINTER_DOWN + | (upOrDownPointer << MotionEvent.ACTION_POINTER_ID_SHIFT); } - } - mLastAnyDown = anyDown; - if (anyDown) { - action = MotionEvent.ACTION_DOWN; - mDownTime = curTime; - } else { - action = MotionEvent.ACTION_UP; - } - currentMove = null; - } else if (firstDownChanged >= 0) { - if (mDown[firstDownChanged]) { - action = MotionEvent.ACTION_POINTER_DOWN - | (firstDownChanged << MotionEvent.ACTION_POINTER_SHIFT); } else { - action = MotionEvent.ACTION_POINTER_UP - | (firstDownChanged << MotionEvent.ACTION_POINTER_SHIFT); + if (numPointers == 1) { + action = MotionEvent.ACTION_UP; + } else { + action = MotionEvent.ACTION_POINTER_UP + | (upOrDownPointer << MotionEvent.ACTION_POINTER_ID_SHIFT); + } } currentMove = null; } else { @@ -170,42 +388,42 @@ public class InputDevice { final int j = i * MotionEvent.NUM_SAMPLE_DATA; if (absX != null) { - scaled[j + MotionEvent.SAMPLE_X] = - ((scaled[j + MotionEvent.SAMPLE_X]-absX.minValue) + reportData[j + MotionEvent.SAMPLE_X] = + ((reportData[j + MotionEvent.SAMPLE_X]-absX.minValue) / absX.range) * w; } if (absY != null) { - scaled[j + MotionEvent.SAMPLE_Y] = - ((scaled[j + MotionEvent.SAMPLE_Y]-absY.minValue) + reportData[j + MotionEvent.SAMPLE_Y] = + ((reportData[j + MotionEvent.SAMPLE_Y]-absY.minValue) / absY.range) * h; } if (absPressure != null) { - scaled[j + MotionEvent.SAMPLE_PRESSURE] = - ((scaled[j + MotionEvent.SAMPLE_PRESSURE]-absPressure.minValue) + reportData[j + MotionEvent.SAMPLE_PRESSURE] = + ((reportData[j + MotionEvent.SAMPLE_PRESSURE]-absPressure.minValue) / (float)absPressure.range); } if (absSize != null) { - scaled[j + MotionEvent.SAMPLE_SIZE] = - ((scaled[j + MotionEvent.SAMPLE_SIZE]-absSize.minValue) + reportData[j + MotionEvent.SAMPLE_SIZE] = + ((reportData[j + MotionEvent.SAMPLE_SIZE]-absSize.minValue) / (float)absSize.range); } switch (orientation) { case Surface.ROTATION_90: { - final float temp = scaled[MotionEvent.SAMPLE_X]; - scaled[j + MotionEvent.SAMPLE_X] = scaled[j + MotionEvent.SAMPLE_Y]; - scaled[j + MotionEvent.SAMPLE_Y] = w-temp; + final float temp = reportData[MotionEvent.SAMPLE_X]; + reportData[j + MotionEvent.SAMPLE_X] = reportData[j + MotionEvent.SAMPLE_Y]; + reportData[j + MotionEvent.SAMPLE_Y] = w-temp; break; } case Surface.ROTATION_180: { - scaled[j + MotionEvent.SAMPLE_X] = w-scaled[j + MotionEvent.SAMPLE_X]; - scaled[j + MotionEvent.SAMPLE_Y] = h-scaled[j + MotionEvent.SAMPLE_Y]; + reportData[j + MotionEvent.SAMPLE_X] = w-reportData[j + MotionEvent.SAMPLE_X]; + reportData[j + MotionEvent.SAMPLE_Y] = h-reportData[j + MotionEvent.SAMPLE_Y]; break; } case Surface.ROTATION_270: { - final float temp = scaled[i + MotionEvent.SAMPLE_X]; - scaled[j + MotionEvent.SAMPLE_X] = h-scaled[j + MotionEvent.SAMPLE_Y]; - scaled[j + MotionEvent.SAMPLE_Y] = temp; + final float temp = reportData[i + MotionEvent.SAMPLE_X]; + reportData[j + MotionEvent.SAMPLE_X] = h-reportData[j + MotionEvent.SAMPLE_Y]; + reportData[j + MotionEvent.SAMPLE_Y] = temp; break; } } @@ -214,24 +432,24 @@ public class InputDevice { // We only consider the first pointer when computing the edge // flags, since they are global to the event. if (action == MotionEvent.ACTION_DOWN) { - if (scaled[MotionEvent.SAMPLE_X] <= 0) { + if (reportData[MotionEvent.SAMPLE_X] <= 0) { edgeFlags |= MotionEvent.EDGE_LEFT; - } else if (scaled[MotionEvent.SAMPLE_X] >= dispW) { + } else if (reportData[MotionEvent.SAMPLE_X] >= dispW) { edgeFlags |= MotionEvent.EDGE_RIGHT; } - if (scaled[MotionEvent.SAMPLE_Y] <= 0) { + if (reportData[MotionEvent.SAMPLE_Y] <= 0) { edgeFlags |= MotionEvent.EDGE_TOP; - } else if (scaled[MotionEvent.SAMPLE_Y] >= dispH) { + } else if (reportData[MotionEvent.SAMPLE_Y] >= dispH) { edgeFlags |= MotionEvent.EDGE_BOTTOM; } } if (currentMove != null) { if (false) Log.i("InputDevice", "Adding batch x=" - + scaled[MotionEvent.SAMPLE_X] - + " y=" + scaled[MotionEvent.SAMPLE_Y] + + reportData[MotionEvent.SAMPLE_X] + + " y=" + reportData[MotionEvent.SAMPLE_Y] + " to " + currentMove); - currentMove.addBatch(curTime, scaled, metaState); + currentMove.addBatch(curTime, reportData, metaState); if (WindowManagerPolicy.WATCH_POINTER) { Log.i("KeyInputQueue", "Updating: " + currentMove); } @@ -239,37 +457,53 @@ public class InputDevice { } MotionEvent me = MotionEvent.obtainNano(mDownTime, curTime, - curTimeNano, action, numPointers, scaled, metaState, - xPrecision, yPrecision, device.id, edgeFlags); + curTimeNano, action, numPointers, mPointerIds, reportData, + metaState, xPrecision, yPrecision, device.id, edgeFlags); if (action == MotionEvent.ACTION_MOVE) { currentMove = me; } + + if (nextNumPointers < lastNumPointers) { + removeOldPointer(upOrDownPointer); + } + return me; } + boolean hasMore() { + return mLastNumPointers != mNextNumPointers; + } + + void finish() { + mNextNumPointers = mAddingPointerOffset = 0; + mNextData[MotionEvent.SAMPLE_PRESSURE] = 0; + } + MotionEvent generateRelMotion(InputDevice device, long curTime, long curTimeNano, int orientation, int metaState) { final float[] scaled = mReportData; // For now we only support 1 pointer with relative motions. - scaled[MotionEvent.SAMPLE_X] = mCurData[MotionEvent.SAMPLE_X]; - scaled[MotionEvent.SAMPLE_Y] = mCurData[MotionEvent.SAMPLE_Y]; + scaled[MotionEvent.SAMPLE_X] = mNextData[MotionEvent.SAMPLE_X]; + scaled[MotionEvent.SAMPLE_Y] = mNextData[MotionEvent.SAMPLE_Y]; scaled[MotionEvent.SAMPLE_PRESSURE] = 1.0f; scaled[MotionEvent.SAMPLE_SIZE] = 0; int edgeFlags = 0; int action; - if (mDown[0] != mLastDown[0]) { - mCurData[MotionEvent.SAMPLE_X] = - mCurData[MotionEvent.SAMPLE_Y] = 0; - mLastDown[0] = mDown[0]; - if (mDown[0]) { + if (mNextNumPointers != mLastNumPointers) { + mNextData[MotionEvent.SAMPLE_X] = + mNextData[MotionEvent.SAMPLE_Y] = 0; + if (mNextNumPointers > 0 && mLastNumPointers == 0) { action = MotionEvent.ACTION_DOWN; mDownTime = curTime; - } else { + } else if (mNextNumPointers == 0) { action = MotionEvent.ACTION_UP; + } else { + action = MotionEvent.ACTION_MOVE; } + mLastNumPointers = mNextNumPointers; currentMove = null; } else { action = MotionEvent.ACTION_MOVE; @@ -310,7 +544,7 @@ public class InputDevice { } MotionEvent me = MotionEvent.obtainNano(mDownTime, curTime, - curTimeNano, action, 1, scaled, metaState, + curTimeNano, action, 1, mPointerIds, scaled, metaState, xPrecision, yPrecision, device.id, edgeFlags); if (action == MotionEvent.ACTION_MOVE) { currentMove = me; diff --git a/services/java/com/android/server/KeyInputQueue.java b/services/java/com/android/server/KeyInputQueue.java index e0ee7ed..cfb3e35 100644 --- a/services/java/com/android/server/KeyInputQueue.java +++ b/services/java/com/android/server/KeyInputQueue.java @@ -49,6 +49,7 @@ public abstract class KeyInputQueue { static final String TAG = "KeyInputQueue"; static final boolean DEBUG_VIRTUAL_KEYS = false; + static final boolean DEBUG_POINTERS = false; private static final String EXCLUDED_DEVICES_PATH = "etc/excluded-input-devices.xml"; @@ -326,6 +327,10 @@ public abstract class KeyInputQueue { config.navigation = Configuration.NAVIGATION_TRACKBALL; //Log.i("foo", "***** HAVE TRACKBALL!"); + } else if ((d.classes&RawInputEvent.CLASS_DPAD) != 0) { + config.navigation + = Configuration.NAVIGATION_DPAD; + //Log.i("foo", "***** HAVE DPAD!"); } } } @@ -364,9 +369,9 @@ public abstract class KeyInputQueue { android.os.Process.setThreadPriority( android.os.Process.THREAD_PRIORITY_URGENT_DISPLAY); - try { - RawInputEvent ev = new RawInputEvent(); - while (true) { + RawInputEvent ev = new RawInputEvent(); + while (true) { + try { InputDevice di; // block, doesn't release the monitor @@ -465,49 +470,81 @@ public abstract class KeyInputQueue { ? KeyEvent.FLAG_WOKE_HERE : 0)); } else if (ev.type == RawInputEvent.EV_KEY) { if (ev.scancode == RawInputEvent.BTN_TOUCH && - (classes&RawInputEvent.CLASS_TOUCHSCREEN) != 0) { + (classes&(RawInputEvent.CLASS_TOUCHSCREEN + |RawInputEvent.CLASS_TOUCHSCREEN_MT)) + == RawInputEvent.CLASS_TOUCHSCREEN) { di.mAbs.changed = true; di.mAbs.mDown[0] = ev.value != 0; } else if (ev.scancode == RawInputEvent.BTN_2 && - (classes&RawInputEvent.CLASS_TOUCHSCREEN) != 0) { + (classes&(RawInputEvent.CLASS_TOUCHSCREEN + |RawInputEvent.CLASS_TOUCHSCREEN_MT)) + == RawInputEvent.CLASS_TOUCHSCREEN) { di.mAbs.changed = true; di.mAbs.mDown[1] = ev.value != 0; } else if (ev.scancode == RawInputEvent.BTN_MOUSE && (classes&RawInputEvent.CLASS_TRACKBALL) != 0) { di.mRel.changed = true; - di.mRel.mDown[0] = ev.value != 0; + di.mRel.mNextNumPointers = ev.value != 0 ? 1 : 0; send = true; } } else if (ev.type == RawInputEvent.EV_ABS && + (classes&RawInputEvent.CLASS_TOUCHSCREEN_MT) != 0) { + if (ev.scancode == RawInputEvent.ABS_MT_TOUCH_MAJOR) { + di.mAbs.changed = true; + di.mAbs.mNextData[di.mAbs.mAddingPointerOffset + + MotionEvent.SAMPLE_PRESSURE] = ev.value; + } else if (ev.scancode == RawInputEvent.ABS_MT_POSITION_X) { + di.mAbs.changed = true; + di.mAbs.mNextData[di.mAbs.mAddingPointerOffset + + MotionEvent.SAMPLE_X] = ev.value; + if (DEBUG_POINTERS) Log.v(TAG, "MT @" + + di.mAbs.mAddingPointerOffset + + " X:" + ev.value); + } else if (ev.scancode == RawInputEvent.ABS_MT_POSITION_Y) { + di.mAbs.changed = true; + di.mAbs.mNextData[di.mAbs.mAddingPointerOffset + + MotionEvent.SAMPLE_Y] = ev.value; + if (DEBUG_POINTERS) Log.v(TAG, "MT @" + + di.mAbs.mAddingPointerOffset + + " Y:" + ev.value); + } else if (ev.scancode == RawInputEvent.ABS_MT_WIDTH_MAJOR) { + di.mAbs.changed = true; + di.mAbs.mNextData[di.mAbs.mAddingPointerOffset + + MotionEvent.SAMPLE_SIZE] = ev.value; + } + + } else if (ev.type == RawInputEvent.EV_ABS && (classes&RawInputEvent.CLASS_TOUCHSCREEN) != 0) { // Finger 1 if (ev.scancode == RawInputEvent.ABS_X) { di.mAbs.changed = true; - di.mAbs.mCurData[MotionEvent.SAMPLE_X] = ev.value; + di.mAbs.mNextData[MotionEvent.SAMPLE_X] = ev.value; } else if (ev.scancode == RawInputEvent.ABS_Y) { di.mAbs.changed = true; - di.mAbs.mCurData[MotionEvent.SAMPLE_Y] = ev.value; + di.mAbs.mNextData[MotionEvent.SAMPLE_Y] = ev.value; } else if (ev.scancode == RawInputEvent.ABS_PRESSURE) { di.mAbs.changed = true; - di.mAbs.mCurData[MotionEvent.SAMPLE_PRESSURE] = ev.value; - di.mAbs.mCurData[MotionEvent.NUM_SAMPLE_DATA + di.mAbs.mNextData[MotionEvent.SAMPLE_PRESSURE] = ev.value; + di.mAbs.mNextData[MotionEvent.NUM_SAMPLE_DATA + MotionEvent.SAMPLE_PRESSURE] = ev.value; } else if (ev.scancode == RawInputEvent.ABS_TOOL_WIDTH) { di.mAbs.changed = true; - di.mAbs.mCurData[MotionEvent.SAMPLE_SIZE] = ev.value; - di.mAbs.mCurData[MotionEvent.NUM_SAMPLE_DATA + di.mAbs.mNextData[MotionEvent.SAMPLE_SIZE] = ev.value; + di.mAbs.mNextData[MotionEvent.NUM_SAMPLE_DATA + MotionEvent.SAMPLE_SIZE] = ev.value; // Finger 2 } else if (ev.scancode == RawInputEvent.ABS_HAT0X) { di.mAbs.changed = true; - di.mAbs.mCurData[MotionEvent.NUM_SAMPLE_DATA - + MotionEvent.SAMPLE_X] = ev.value; + di.mAbs.mNextData[(di.mAbs.mDown[0] ? + MotionEvent.NUM_SAMPLE_DATA : 0) + + MotionEvent.SAMPLE_X] = ev.value; } else if (ev.scancode == RawInputEvent.ABS_HAT0Y) { di.mAbs.changed = true; - di.mAbs.mCurData[MotionEvent.NUM_SAMPLE_DATA - + MotionEvent.SAMPLE_Y] = ev.value; + di.mAbs.mNextData[(di.mAbs.mDown[0] ? + MotionEvent.NUM_SAMPLE_DATA : 0) + + MotionEvent.SAMPLE_Y] = ev.value; } } else if (ev.type == RawInputEvent.EV_REL && @@ -515,14 +552,40 @@ public abstract class KeyInputQueue { // Add this relative movement into our totals. if (ev.scancode == RawInputEvent.REL_X) { di.mRel.changed = true; - di.mRel.mCurData[MotionEvent.SAMPLE_X] += ev.value; + di.mRel.mNextData[MotionEvent.SAMPLE_X] += ev.value; } else if (ev.scancode == RawInputEvent.REL_Y) { di.mRel.changed = true; - di.mRel.mCurData[MotionEvent.SAMPLE_Y] += ev.value; + di.mRel.mNextData[MotionEvent.SAMPLE_Y] += ev.value; } } - if (send || ev.type == RawInputEvent.EV_SYN) { + if (ev.type == RawInputEvent.EV_SYN + && ev.scancode == RawInputEvent.SYN_MT_REPORT + && di.mAbs != null) { + di.mAbs.changed = true; + if (di.mAbs.mNextData[MotionEvent.SAMPLE_PRESSURE] > 0) { + // If the value is <= 0, the pointer is not + // down, so keep it in the count. + + if (di.mAbs.mNextData[di.mAbs.mAddingPointerOffset + + MotionEvent.SAMPLE_PRESSURE] != 0) { + final int num = di.mAbs.mNextNumPointers+1; + di.mAbs.mNextNumPointers = num; + if (DEBUG_POINTERS) Log.v(TAG, + "MT_REPORT: now have " + num + " pointers"); + final int newOffset = (num <= InputDevice.MAX_POINTERS) + ? (num * MotionEvent.NUM_SAMPLE_DATA) + : (InputDevice.MAX_POINTERS * + MotionEvent.NUM_SAMPLE_DATA); + di.mAbs.mAddingPointerOffset = newOffset; + di.mAbs.mNextData[newOffset + + MotionEvent.SAMPLE_PRESSURE] = 0; + } else { + if (DEBUG_POINTERS) Log.v(TAG, "MT_REPORT: no pointer"); + } + } + } else if (send || (ev.type == RawInputEvent.EV_SYN + && ev.scancode == RawInputEvent.SYN_REPORT)) { if (mDisplay != null) { if (!mHaveGlobalMetaState) { computeGlobalMetaStateLocked(); @@ -534,72 +597,21 @@ public abstract class KeyInputQueue { if (ms.changed) { ms.changed = false; - boolean doMotion = true; - - // Look for virtual buttons. - VirtualKey vk = mPressedVirtualKey; - if (vk != null) { - doMotion = false; - if (!ms.mDown[0]) { - mPressedVirtualKey = null; - ms.mLastDown[0] = ms.mDown[0]; - if (DEBUG_VIRTUAL_KEYS) Log.v(TAG, - "Generate key up for: " + vk.scancode); - KeyEvent event = newKeyEvent(di, - di.mKeyDownTime, curTime, false, - vk.lastKeycode, - 0, vk.scancode, - KeyEvent.FLAG_VIRTUAL_HARD_KEY); - mHapticFeedbackCallback.virtualKeyFeedback(event); - addLocked(di, curTimeNano, ev.flags, - RawInputEvent.CLASS_KEYBOARD, - event); - } else if (isInsideDisplay(di)) { - // Whoops the pointer has moved into - // the display area! Cancel the - // virtual key and start a pointer - // motion. - mPressedVirtualKey = null; - if (DEBUG_VIRTUAL_KEYS) Log.v(TAG, - "Cancel key up for: " + vk.scancode); - KeyEvent event = newKeyEvent(di, - di.mKeyDownTime, curTime, false, - vk.lastKeycode, - 0, vk.scancode, - KeyEvent.FLAG_CANCELED | - KeyEvent.FLAG_VIRTUAL_HARD_KEY); - mHapticFeedbackCallback.virtualKeyFeedback(event); - addLocked(di, curTimeNano, ev.flags, - RawInputEvent.CLASS_KEYBOARD, - event); - doMotion = true; - for (int i=InputDevice.MAX_POINTERS-1; i>=0; i--) { - ms.mLastDown[i] = false; - } - } + if ((classes&(RawInputEvent.CLASS_TOUCHSCREEN + |RawInputEvent.CLASS_TOUCHSCREEN_MT)) + == RawInputEvent.CLASS_TOUCHSCREEN) { + ms.mNextNumPointers = 0; + if (ms.mDown[0]) ms.mNextNumPointers++; + if (ms.mDown[1]) ms.mNextNumPointers++; } - if (doMotion && ms.mDown[0] && !ms.mLastDown[0]) { - vk = findSoftButton(di); - if (vk != null) { - doMotion = false; - mPressedVirtualKey = vk; - vk.lastKeycode = scancodeToKeycode( - di.id, vk.scancode); - ms.mLastDown[0] = ms.mDown[0]; - di.mKeyDownTime = curTime; - if (DEBUG_VIRTUAL_KEYS) Log.v(TAG, - "Generate key down for: " + vk.scancode - + " (keycode=" + vk.lastKeycode + ")"); - KeyEvent event = newKeyEvent(di, - di.mKeyDownTime, curTime, true, - vk.lastKeycode, 0, - vk.scancode, - KeyEvent.FLAG_VIRTUAL_HARD_KEY); - mHapticFeedbackCallback.virtualKeyFeedback(event); - addLocked(di, curTimeNano, ev.flags, - RawInputEvent.CLASS_KEYBOARD, - event); - } + + boolean doMotion = !monitorVirtualKey(di, + ev, curTime, curTimeNano); + + if (doMotion && ms.mNextNumPointers > 0 + && ms.mLastNumPointers == 0) { + doMotion = !generateVirtualKeyDown(di, + ev, curTime, curTimeNano); } if (doMotion) { @@ -607,22 +619,26 @@ public abstract class KeyInputQueue { // multiple events here, for example // if two fingers change up/down state // at the same time. - me = ms.generateAbsMotion(di, curTime, - curTimeNano, mDisplay, - mOrientation, mGlobalMetaState); - if (false) Log.v(TAG, "Absolute: x=" - + di.mAbs.mCurData[MotionEvent.SAMPLE_X] - + " y=" - + di.mAbs.mCurData[MotionEvent.SAMPLE_Y] - + " ev=" + me); - if (me != null) { - if (WindowManagerPolicy.WATCH_POINTER) { - Log.i(TAG, "Enqueueing: " + me); + do { + me = ms.generateAbsMotion(di, curTime, + curTimeNano, mDisplay, + mOrientation, mGlobalMetaState); + if (false) Log.v(TAG, "Absolute: x=" + + di.mAbs.mNextData[MotionEvent.SAMPLE_X] + + " y=" + + di.mAbs.mNextData[MotionEvent.SAMPLE_Y] + + " ev=" + me); + if (me != null) { + if (WindowManagerPolicy.WATCH_POINTER) { + Log.i(TAG, "Enqueueing: " + me); + } + addLocked(di, curTimeNano, ev.flags, + RawInputEvent.CLASS_TOUCHSCREEN, me); } - addLocked(di, curTimeNano, ev.flags, - RawInputEvent.CLASS_TOUCHSCREEN, me); - } + } while (ms.hasMore()); } + + ms.finish(); } ms = di.mRel; @@ -633,22 +649,24 @@ public abstract class KeyInputQueue { curTimeNano, mOrientation, mGlobalMetaState); if (false) Log.v(TAG, "Relative: x=" - + di.mRel.mCurData[MotionEvent.SAMPLE_X] + + di.mRel.mNextData[MotionEvent.SAMPLE_X] + " y=" - + di.mRel.mCurData[MotionEvent.SAMPLE_Y] + + di.mRel.mNextData[MotionEvent.SAMPLE_Y] + " ev=" + me); if (me != null) { addLocked(di, curTimeNano, ev.flags, RawInputEvent.CLASS_TRACKBALL, me); } + + ms.finish(); } } } } - } - } catch (RuntimeException exc) { - Log.e(TAG, "InputReaderThread uncaught exception", exc); + } catch (RuntimeException exc) { + Log.e(TAG, "InputReaderThread uncaught exception", exc); + } } } }; @@ -661,13 +679,13 @@ public abstract class KeyInputQueue { return true; } - if (absm.mCurData[MotionEvent.SAMPLE_X] >= absx.minValue - && absm.mCurData[MotionEvent.SAMPLE_X] <= absx.maxValue - && absm.mCurData[MotionEvent.SAMPLE_Y] >= absy.minValue - && absm.mCurData[MotionEvent.SAMPLE_Y] <= absy.maxValue) { + if (absm.mNextData[MotionEvent.SAMPLE_X] >= absx.minValue + && absm.mNextData[MotionEvent.SAMPLE_X] <= absx.maxValue + && absm.mNextData[MotionEvent.SAMPLE_Y] >= absy.minValue + && absm.mNextData[MotionEvent.SAMPLE_Y] <= absy.maxValue) { if (DEBUG_VIRTUAL_KEYS) Log.v(TAG, "Input (" - + absm.mCurData[MotionEvent.SAMPLE_X] - + "," + absm.mCurData[MotionEvent.SAMPLE_Y] + + absm.mNextData[MotionEvent.SAMPLE_X] + + "," + absm.mNextData[MotionEvent.SAMPLE_Y] + ") inside of display"); return true; } @@ -675,28 +693,24 @@ public abstract class KeyInputQueue { return false; } - private VirtualKey findSoftButton(InputDevice dev) { + private VirtualKey findVirtualKey(InputDevice dev) { final int N = mVirtualKeys.size(); if (N <= 0) { return null; } - if (isInsideDisplay(dev)) { - return null; - } - final InputDevice.MotionState absm = dev.mAbs; for (int i=0; i<N; i++) { VirtualKey sb = mVirtualKeys.get(i); sb.computeHitRect(dev, mDisplayWidth, mDisplayHeight); if (DEBUG_VIRTUAL_KEYS) Log.v(TAG, "Hit test (" - + absm.mCurData[MotionEvent.SAMPLE_X] + "," - + absm.mCurData[MotionEvent.SAMPLE_Y] + ") in code " + + absm.mNextData[MotionEvent.SAMPLE_X] + "," + + absm.mNextData[MotionEvent.SAMPLE_Y] + ") in code " + sb.scancode + " - (" + sb.hitLeft + "," + sb.hitTop + ")-(" + sb.hitRight + "," + sb.hitBottom + ")"); - if (sb.checkHit(absm.mCurData[MotionEvent.SAMPLE_X], - absm.mCurData[MotionEvent.SAMPLE_Y])) { + if (sb.checkHit(absm.mNextData[MotionEvent.SAMPLE_X], + absm.mNextData[MotionEvent.SAMPLE_Y])) { if (DEBUG_VIRTUAL_KEYS) Log.v(TAG, "Hit!"); return sb; } @@ -705,6 +719,97 @@ public abstract class KeyInputQueue { return null; } + private boolean generateVirtualKeyDown(InputDevice di, RawInputEvent ev, + long curTime, long curTimeNano) { + if (isInsideDisplay(di)) { + // Didn't consume event. + return false; + } + + + VirtualKey vk = findVirtualKey(di); + if (vk != null) { + final InputDevice.MotionState ms = di.mAbs; + mPressedVirtualKey = vk; + vk.lastKeycode = scancodeToKeycode(di.id, vk.scancode); + ms.mLastNumPointers = ms.mNextNumPointers; + di.mKeyDownTime = curTime; + if (DEBUG_VIRTUAL_KEYS) Log.v(TAG, + "Generate key down for: " + vk.scancode + + " (keycode=" + vk.lastKeycode + ")"); + KeyEvent event = newKeyEvent(di, di.mKeyDownTime, curTime, true, + vk.lastKeycode, 0, vk.scancode, + KeyEvent.FLAG_VIRTUAL_HARD_KEY); + mHapticFeedbackCallback.virtualKeyFeedback(event); + addLocked(di, curTimeNano, ev.flags, RawInputEvent.CLASS_KEYBOARD, + event); + } + + // We always consume the event, even if we didn't + // generate a key event. There are two reasons for + // this: to avoid spurious touches when holding + // the edges of the device near the touchscreen, + // and to avoid reporting events if there are virtual + // keys on the touchscreen outside of the display + // area. + // Note that for all of this we are only looking at the + // first pointer, since what we are handling here is the + // first pointer going down, and this is the coordinate + // that will be used to dispatch the event. + if (false) { + final InputDevice.AbsoluteInfo absx = di.absX; + final InputDevice.AbsoluteInfo absy = di.absY; + final InputDevice.MotionState absm = di.mAbs; + Log.v(TAG, "Rejecting (" + + absm.mNextData[MotionEvent.SAMPLE_X] + "," + + absm.mNextData[MotionEvent.SAMPLE_Y] + "): outside of (" + + absx.minValue + "," + absy.minValue + + ")-(" + absx.maxValue + "," + + absx.maxValue + ")"); + } + return true; + } + + private boolean monitorVirtualKey(InputDevice di, RawInputEvent ev, + long curTime, long curTimeNano) { + VirtualKey vk = mPressedVirtualKey; + if (vk == null) { + return false; + } + + final InputDevice.MotionState ms = di.mAbs; + if (ms.mNextNumPointers <= 0) { + mPressedVirtualKey = null; + ms.mLastNumPointers = 0; + if (DEBUG_VIRTUAL_KEYS) Log.v(TAG, "Generate key up for: " + vk.scancode); + KeyEvent event = newKeyEvent(di, di.mKeyDownTime, curTime, false, + vk.lastKeycode, 0, vk.scancode, + KeyEvent.FLAG_VIRTUAL_HARD_KEY); + mHapticFeedbackCallback.virtualKeyFeedback(event); + addLocked(di, curTimeNano, ev.flags, RawInputEvent.CLASS_KEYBOARD, + event); + return true; + + } else if (isInsideDisplay(di)) { + // Whoops the pointer has moved into + // the display area! Cancel the + // virtual key and start a pointer + // motion. + mPressedVirtualKey = null; + if (DEBUG_VIRTUAL_KEYS) Log.v(TAG, "Cancel key up for: " + vk.scancode); + KeyEvent event = newKeyEvent(di, di.mKeyDownTime, curTime, false, + vk.lastKeycode, 0, vk.scancode, + KeyEvent.FLAG_CANCELED | KeyEvent.FLAG_VIRTUAL_HARD_KEY); + mHapticFeedbackCallback.virtualKeyFeedback(event); + addLocked(di, curTimeNano, ev.flags, RawInputEvent.CLASS_KEYBOARD, + event); + ms.mLastNumPointers = 0; + return false; + } + + return true; + } + /** * Returns a new meta state for the given keys and old state. */ @@ -851,8 +956,8 @@ public abstract class KeyInputQueue { if (ev.event == ev.inputDevice.mRel.currentMove) { if (false) Log.i(TAG, "Detach rel " + ev.event); ev.inputDevice.mRel.currentMove = null; - ev.inputDevice.mRel.mCurData[MotionEvent.SAMPLE_X] = 0; - ev.inputDevice.mRel.mCurData[MotionEvent.SAMPLE_Y] = 0; + ev.inputDevice.mRel.mNextData[MotionEvent.SAMPLE_X] = 0; + ev.inputDevice.mRel.mNextData[MotionEvent.SAMPLE_Y] = 0; } recycleLocked(ev); } @@ -945,7 +1050,12 @@ public abstract class KeyInputQueue { InputDevice.AbsoluteInfo absY; InputDevice.AbsoluteInfo absPressure; InputDevice.AbsoluteInfo absSize; - if ((classes&RawInputEvent.CLASS_TOUCHSCREEN) != 0) { + if ((classes&RawInputEvent.CLASS_TOUCHSCREEN_MT) != 0) { + absX = loadAbsoluteInfo(deviceId, RawInputEvent.ABS_MT_POSITION_X, "X"); + absY = loadAbsoluteInfo(deviceId, RawInputEvent.ABS_MT_POSITION_Y, "Y"); + absPressure = loadAbsoluteInfo(deviceId, RawInputEvent.ABS_MT_TOUCH_MAJOR, "Pressure"); + absSize = loadAbsoluteInfo(deviceId, RawInputEvent.ABS_MT_WIDTH_MAJOR, "Size"); + } else if ((classes&RawInputEvent.CLASS_TOUCHSCREEN) != 0) { absX = loadAbsoluteInfo(deviceId, RawInputEvent.ABS_X, "X"); absY = loadAbsoluteInfo(deviceId, RawInputEvent.ABS_Y, "Y"); absPressure = loadAbsoluteInfo(deviceId, RawInputEvent.ABS_PRESSURE, "Pressure"); |
