diff --git a/api/current.xml b/api/current.xml index f65b5ce270fce..c4cac831508af 100644 --- a/api/current.xml +++ b/api/current.xml @@ -145940,6 +145940,19 @@ visibility="public" > + + + + - + @@ -146059,7 +146072,7 @@ deprecated="not deprecated" visibility="public" > - + @@ -146087,7 +146100,7 @@ deprecated="not deprecated" visibility="public" > - + @@ -146115,7 +146128,7 @@ deprecated="not deprecated" visibility="public" > - + @@ -146153,6 +146166,19 @@ visibility="public" > + + + + - + - + - + - + - -not 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; @@ -143,18 +155,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 pointers values providing + * an identifier for each pointer. + * @param inData An array of pointers*NUM_SAMPLE_DATA 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= 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 { @@ -592,6 +595,38 @@ public final class MotionEvent implements Parcelable { return mEventTimeNano; } + /** + * {@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 index (may be an + * arbitrary pointer identifier). + */ + public final float getY() { + return mDataSamples[SAMPLE_Y]; + } + + /** + * {@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 index (may be an + * arbitrary pointer identifier). + */ + public final float getSize() { + return mDataSamples[SAMPLE_SIZE]; + } + /** * The number of pointers of data contained in this event. Always * >= 1. @@ -601,80 +636,91 @@ public final class MotionEvent implements Parcelable { } /** - * {@link #getX(int)} for the first pointer (pointer 0). + * 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 float getX() { - return mDataSamples[SAMPLE_X]; + public final int getPointerId(int index) { + return mPointerIdentifiers[index]; } - + /** - * {@link #getY(int)} for the first pointer (pointer 0). + * 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 float getY() { - return mDataSamples[SAMPLE_Y]; + public final int findPointerIndex(int pointerId) { + int i = mNumPointers; + while (i > 0) { + i--; + if (mPointerIdentifiers[i] == pointerId) { + return i; + } + } + return -1; } - + /** - * {@link #getPressure(int)} for the first pointer (pointer 0). - */ - public final float getPressure() { - return mDataSamples[SAMPLE_PRESSURE]; - } - - /** - * {@link #getSize(int)} for the first pointer (pointer 0). - */ - public final float getSize() { - return mDataSamples[SAMPLE_SIZE]; - } - - /** - * Returns the X coordinate of this event for the given pointer. + * Returns the X coordinate of this event for the given pointer + * index (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 + * index (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 + * index (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 + * index (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 0) { int i; - int[] state = mStateSamples; - for (i=0; i 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 +#include #include #include @@ -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 scanCodes; + device->layoutMap->findScancodes(keycode, &scanCodes); + const size_t N = scanCodes.size(); + for (size_t i=0; i= 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 0ac5740cd0981..cb23c45581435 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= 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 (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= 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= 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) { - final float[] scaled = mReportData; - final int[] cur = mCurData; - - boolean anyDown = false; - int firstDownChanged = -1; - int numPointers = 0; - for (int i=0; i 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 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 e0ee7ed6698ab..cfb3e35bec54e 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