From 9822d2b27330793ea4ba9c3316ef35f402f35fb4 Mon Sep 17 00:00:00 2001 From: Dianne Hackborn Date: Mon, 20 Jul 2009 17:33:15 -0700 Subject: [PATCH] First stab at poly-finger support. The MotionEvent API should be fairly solid, but there is still a lot of work to do in the input device code. In particular, right now we are really stupid about watching how fingers change -- we just take whatever the driver reports as down and dump that directly into the motion event. The big remaning work is to assign pointer IDs so that applications have help in determine which fingers go up and down, and adding support for the official multi-touch driver protocol. --- api/current.xml | 281 +++++++ core/java/android/view/MotionEvent.java | 687 +++++++++++++----- .../java/com/android/server/InputDevice.java | 356 +++++---- .../com/android/server/KeyInputQueue.java | 107 ++- 4 files changed, 1095 insertions(+), 336 deletions(-) diff --git a/api/current.xml b/api/current.xml index 3a7fd2f921bb2..ae7e7569330a7 100644 --- a/api/current.xml +++ b/api/current.xml @@ -144536,6 +144536,21 @@ + + + + + + + + + + + + + + + + + + @@ -144575,6 +144620,21 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -144860,6 +145020,17 @@ visibility="public" > + + + + + + + + + + + + + + + + + + + + + + 0) { + pointers--; + state[pointers] = pointers; + } + + ev.mTimeSamples[0] = eventTime; return ev; } @@ -218,17 +346,83 @@ public final class MotionEvent implements Parcelable { ev.mDeviceId = deviceId; ev.mEdgeFlags = edgeFlags; ev.mDownTime = downTime; - ev.mEventTime = eventTime; ev.mEventTimeNano = eventTime * 1000000; ev.mAction = action; - ev.mX = ev.mRawX = x; - ev.mY = ev.mRawY = y; - ev.mPressure = pressure; - ev.mSize = size; ev.mMetaState = metaState; ev.mXPrecision = xPrecision; ev.mYPrecision = yPrecision; + ev.mNumPointers = 1; + ev.mNumSamples = 1; + int[] state = ev.mStateSamples; + state[0] = 0; + float[] data = ev.mDataSamples; + data[SAMPLE_X] = ev.mRawX = x; + data[SAMPLE_Y] = ev.mRawY = y; + data[SAMPLE_PRESSURE] = pressure; + data[SAMPLE_SIZE] = size; + ev.mTimeSamples[0] = eventTime; + + return ev; + } + + /** + * Create a new MotionEvent, filling in all of the basic values that + * define the motion. + * + * @param downTime The time (in ms) when the user originally pressed down to start + * a stream of position events. This must be obtained from {@link SystemClock#uptimeMillis()}. + * @param eventTime The the time (in ms) when this specific event was generated. This + * must be obtained from {@link SystemClock#uptimeMillis()}. + * @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 pointers The number of pointers that are active in this event. + * @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 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. + * @param yPrecision The precision of the Y coordinate being reported. + * @param deviceId The id for the device that this event came from. An id of + * zero indicates that the event didn't come from a physical device; other + * numbers are arbitrary and you shouldn't depend on the values. + * @param edgeFlags A bitfield indicating which edges, if any, where touched by this + * MotionEvent. + */ + static public MotionEvent obtain(long downTime, long eventTime, int action, + int pointers, float x, float y, float pressure, float size, int metaState, + float xPrecision, float yPrecision, int deviceId, int edgeFlags) { + MotionEvent ev = obtain(); + ev.mDeviceId = deviceId; + ev.mEdgeFlags = edgeFlags; + ev.mDownTime = downTime; + ev.mEventTimeNano = eventTime * 1000000; + ev.mAction = action; + ev.mNumPointers = pointers; + ev.mMetaState = metaState; + ev.mXPrecision = xPrecision; + ev.mYPrecision = yPrecision; + + ev.mNumPointers = 1; + ev.mNumSamples = 1; + int[] state = ev.mStateSamples; + state[0] = 0; + float[] data = ev.mDataSamples; + data[SAMPLE_X] = ev.mRawX = x; + data[SAMPLE_Y] = ev.mRawY = y; + data[SAMPLE_PRESSURE] = pressure; + data[SAMPLE_SIZE] = size; + ev.mTimeSamples[0] = eventTime; + return ev; } @@ -255,17 +449,24 @@ public final class MotionEvent implements Parcelable { ev.mDeviceId = 0; ev.mEdgeFlags = 0; ev.mDownTime = downTime; - ev.mEventTime = eventTime; ev.mEventTimeNano = eventTime * 1000000; ev.mAction = action; - ev.mX = ev.mRawX = x; - ev.mY = ev.mRawY = y; - ev.mPressure = 1.0f; - ev.mSize = 1.0f; + ev.mNumPointers = 1; ev.mMetaState = metaState; ev.mXPrecision = 1.0f; ev.mYPrecision = 1.0f; + ev.mNumPointers = 1; + ev.mNumSamples = 1; + int[] state = ev.mStateSamples; + state[0] = 0; + float[] data = ev.mDataSamples; + data[SAMPLE_X] = ev.mRawX = x; + data[SAMPLE_Y] = ev.mRawY = y; + data[SAMPLE_PRESSURE] = 1.0f; + data[SAMPLE_SIZE] = 1.0f; + ev.mTimeSamples[0] = eventTime; + return ev; } @@ -275,43 +476,17 @@ public final class MotionEvent implements Parcelable { * @hide */ public void scale(float scale) { - mX *= scale; - mY *= scale; mRawX *= scale; mRawY *= scale; - mSize *= scale; mXPrecision *= scale; mYPrecision *= scale; - if (mHistory != null) { - float[] history = mHistory; - int length = history.length; - for (int i = 0; i < length; i += 4) { - history[i] *= scale; // X - history[i + 1] *= scale; // Y - // no need to scale pressure ([i+2]) - history[i + 3] *= scale; // Size, TODO: square this? - } - } - } - - /** - * Translate the coordination of the event by given x and y. - * - * @hide - */ - public void translate(float dx, float dy) { - mX += dx; - mY += dy; - mRawX += dx; - mRawY += dx; - if (mHistory != null) { - float[] history = mHistory; - int length = history.length; - for (int i = 0; i < length; i += 4) { - history[i] += dx; // X - history[i + 1] += dy; // Y - // no need to translate pressure (i+2) and size (i+3) - } + float[] history = mDataSamples; + final int length = mNumPointers * mNumSamples * NUM_SAMPLE_DATA; + for (int i = 0; i < length; i += NUM_SAMPLE_DATA) { + history[i + SAMPLE_X] *= scale; + history[i + SAMPLE_Y] *= scale; + // no need to scale pressure + history[i + SAMPLE_SIZE] *= scale; // TODO: square this? } } @@ -323,25 +498,36 @@ public final class MotionEvent implements Parcelable { ev.mDeviceId = o.mDeviceId; ev.mEdgeFlags = o.mEdgeFlags; ev.mDownTime = o.mDownTime; - ev.mEventTime = o.mEventTime; ev.mEventTimeNano = o.mEventTimeNano; ev.mAction = o.mAction; - ev.mX = o.mX; + ev.mNumPointers = o.mNumPointers; ev.mRawX = o.mRawX; - ev.mY = o.mY; ev.mRawY = o.mRawY; - ev.mPressure = o.mPressure; - ev.mSize = o.mSize; ev.mMetaState = o.mMetaState; ev.mXPrecision = o.mXPrecision; ev.mYPrecision = o.mYPrecision; - final int N = o.mNumHistory; - ev.mNumHistory = N; - if (N > 0) { - // could be more efficient about this... - ev.mHistory = (float[])o.mHistory.clone(); - ev.mHistoryTimes = (long[])o.mHistoryTimes.clone(); + + final int NT = ev.mNumSamples = o.mNumSamples; + if (ev.mTimeSamples.length < NT) { + System.arraycopy(o.mTimeSamples, 0, ev.mTimeSamples, 0, NT); + } 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); + } else { + ev.mStateSamples = (int[])o.mStateSamples.clone(); + } + + final int ND = NS * NUM_SAMPLE_DATA; + if (ev.mDataSamples.length < ND) { + System.arraycopy(o.mDataSamples, 0, ev.mDataSamples, 0, ND); + } else { + ev.mDataSamples = (float[])o.mDataSamples.clone(); + } + return ev; } @@ -364,7 +550,7 @@ public final class MotionEvent implements Parcelable { synchronized (gRecyclerLock) { if (gRecyclerUsed < MAX_RECYCLED) { gRecyclerUsed++; - mNumHistory = 0; + mNumSamples = 0; mNext = gRecyclerTop; gRecyclerTop = this; } @@ -392,7 +578,7 @@ public final class MotionEvent implements Parcelable { * Returns the time (in ms) when this specific event was generated. */ public final long getEventTime() { - return mEventTime; + return mTimeSamples[0]; } /** @@ -406,40 +592,88 @@ public final class MotionEvent implements Parcelable { } /** - * Returns the X coordinate of this event. Whole numbers are pixels; the - * value may have a fraction for input devices that are sub-pixel precise. + * 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). */ public final float getX() { - return mX; + return mDataSamples[SAMPLE_X]; } /** - * Returns the Y coordinate of this event. Whole numbers are pixels; the - * value may have a fraction for input devices that are sub-pixel precise. + * {@link #getY(int)} for the first pointer (pointer 0). */ public final float getY() { - return mY; + return mDataSamples[SAMPLE_Y]; } /** - * Returns the current pressure of this event. The pressure generally + * {@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. + * 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. + */ + public final float getX(int pointer) { + return mDataSamples[(pointer*NUM_SAMPLE_DATA) + SAMPLE_X]; + } + + /** + * Returns the Y coordinate of this event for the given pointer. + * 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. + */ + public final float getY(int pointer) { + return mDataSamples[(pointer*NUM_SAMPLE_DATA) + SAMPLE_Y]; + } + + /** + * Returns the current pressure of this event for the given pointer. + * 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. */ - public final float getPressure() { - return mPressure; + public final float getPressure(int pointer) { + return mDataSamples[(pointer*NUM_SAMPLE_DATA) + SAMPLE_PRESSURE]; } /** - * Returns 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 the device specific range of values + * 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 + * 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. */ - public final float getSize() { - return mSize; + public final float getSize(int pointer) { + return mDataSamples[(pointer*NUM_SAMPLE_DATA) + SAMPLE_SIZE]; } /** @@ -505,7 +739,7 @@ public final class MotionEvent implements Parcelable { * @return Returns the number of historical points in the event. */ public final int getHistorySize() { - return mNumHistory; + return mNumSamples - 1; } /** @@ -519,63 +753,103 @@ public final class MotionEvent implements Parcelable { * @see #getEventTime */ public final long getHistoricalEventTime(int pos) { - return mHistoryTimes[pos]; + return mTimeSamples[pos + 1]; + } + + /** + * {@link #getHistoricalX(int)} for the first pointer (pointer 0). + */ + 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). + */ + 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). + */ + 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). + */ + 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. Only applies to ACTION_MOVE events. + * 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 pos Which historical value to return; must be less than * {@link #getHistorySize} * * @see #getHistorySize * @see #getX */ - public final float getHistoricalX(int pos) { - return mHistory[pos*4]; + public final float getHistoricalX(int pointer, int pos) { + return mDataSamples[((pos + 1) * NUM_SAMPLE_DATA * mNumPointers) + + (pointer * NUM_SAMPLE_DATA) + SAMPLE_X]; } /** * Returns a historical Y coordinate that occurred between this event - * and the previous event. Only applies to ACTION_MOVE events. + * 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 pos Which historical value to return; must be less than * {@link #getHistorySize} * * @see #getHistorySize * @see #getY */ - public final float getHistoricalY(int pos) { - return mHistory[pos*4 + 1]; + public final float getHistoricalY(int pointer, int pos) { + return mDataSamples[((pos + 1) * NUM_SAMPLE_DATA * mNumPointers) + + (pointer * NUM_SAMPLE_DATA) + SAMPLE_Y]; } /** * Returns a historical pressure coordinate that occurred between this event - * and the previous event. Only applies to ACTION_MOVE events. + * and the previous event for the given pointer. Only applies to ACTION_MOVE events. * * @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 pos) { - return mHistory[pos*4 + 2]; + public final float getHistoricalPressure(int pointer, int pos) { + return mDataSamples[((pos + 1) * NUM_SAMPLE_DATA * mNumPointers) + + (pointer * NUM_SAMPLE_DATA) + SAMPLE_PRESSURE]; } /** * Returns a historical size coordinate that occurred between this event - * and the previous event. Only applies to ACTION_MOVE events. + * and the previous event for the given pointer. Only applies to ACTION_MOVE events. * * @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 pos) { - return mHistory[pos*4 + 3]; + public final float getHistoricalSize(int pointer, int pos) { + return mDataSamples[((pos + 1) * NUM_SAMPLE_DATA * mNumPointers) + + (pointer * NUM_SAMPLE_DATA) + SAMPLE_SIZE]; } /** @@ -625,16 +899,11 @@ public final class MotionEvent implements Parcelable { * @param deltaY Amount to add to the current Y coordinate of the event. */ public final void offsetLocation(float deltaX, float deltaY) { - mX += deltaX; - mY += deltaY; - final int N = mNumHistory*4; - if (N <= 0) { - return; - } - final float[] pos = mHistory; - for (int i=0; i CREATOR @@ -732,27 +1061,29 @@ public final class MotionEvent implements Parcelable { public void writeToParcel(Parcel out, int flags) { out.writeLong(mDownTime); - out.writeLong(mEventTime); out.writeLong(mEventTimeNano); out.writeInt(mAction); - out.writeFloat(mX); - out.writeFloat(mY); - out.writeFloat(mPressure); - out.writeFloat(mSize); out.writeInt(mMetaState); out.writeFloat(mRawX); out.writeFloat(mRawY); - final int N = mNumHistory; - out.writeInt(N); - if (N > 0) { - final int N4 = N*4; + final int NP = mNumPointers; + out.writeInt(NP); + final int NS = mNumSamples; + out.writeInt(NS); + final int NI = NP*NS; + if (NI > 0) { int i; - float[] history = mHistory; - for (i=0; i 0) { - final int N4 = N*4; - float[] history = mHistory; - if (history == null || history.length < N4) { - mHistory = history = new float[N4 + (4*4)]; + final int NP = in.readInt(); + mNumPointers = NP; + final int NS = in.readInt(); + 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]; } - 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; + } + } + 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); + } + currentMove = null; + } else { + action = MotionEvent.ACTION_MOVE; + } + + final int dispW = display.getWidth()-1; + final int dispH = display.getHeight()-1; + int w = dispW; + int h = dispH; + if (orientation == Surface.ROTATION_90 + || orientation == Surface.ROTATION_270) { + int tmp = w; + w = h; + h = tmp; + } + + final AbsoluteInfo absX = device.absX; + final AbsoluteInfo absY = device.absY; + final AbsoluteInfo absPressure = device.absPressure; + final AbsoluteInfo absSize = device.absSize; + for (int i=0; i= dispW) { + edgeFlags |= MotionEvent.EDGE_RIGHT; + } + if (scaled[MotionEvent.SAMPLE_Y] <= 0) { + edgeFlags |= MotionEvent.EDGE_TOP; + } else if (scaled[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] + + " to " + currentMove); + currentMove.addBatch(curTime, scaled, metaState); + if (WindowManagerPolicy.WATCH_POINTER) { + Log.i("KeyInputQueue", "Updating: " + currentMove); + } + return null; + } + + MotionEvent me = MotionEvent.obtainNano(mDownTime, curTime, + curTimeNano, action, numPointers, scaled, metaState, + xPrecision, yPrecision, device.id, edgeFlags); + if (action == MotionEvent.ACTION_MOVE) { + currentMove = me; + } + return me; + } + + 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_PRESSURE] = 1.0f; + scaled[MotionEvent.SAMPLE_SIZE] = 0; int edgeFlags = 0; int action; - if (down != lastDown) { - if (isAbs) { - final AbsoluteInfo absX = device.absX; - final AbsoluteInfo absY = device.absY; - if (down && 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. - if (scaledX < absX.minValue || scaledX > absX.maxValue - || scaledY < absY.minValue || scaledY > absY.maxValue) { - if (false) Log.v("InputDevice", "Rejecting (" + scaledX + "," - + scaledY + "): outside of (" - + absX.minValue + "," + absY.minValue - + ")-(" + absX.maxValue + "," - + absY.maxValue + ")"); - return null; - } - } - } else { - x = y = 0; - } - lastDown = down; - if (down) { + if (mDown[0] != mLastDown[0]) { + mCurData[MotionEvent.SAMPLE_X] = + mCurData[MotionEvent.SAMPLE_Y] = 0; + mLastDown[0] = mDown[0]; + if (mDown[0]) { action = MotionEvent.ACTION_DOWN; - downTime = curTime; + mDownTime = curTime; } else { action = MotionEvent.ACTION_UP; } @@ -111,100 +275,42 @@ public class InputDevice { action = MotionEvent.ACTION_MOVE; } - if (isAbs) { - final int dispW = display.getWidth()-1; - final int dispH = display.getHeight()-1; - int w = dispW; - int h = dispH; - if (orientation == Surface.ROTATION_90 - || orientation == Surface.ROTATION_270) { - int tmp = w; - w = h; - h = tmp; + scaled[MotionEvent.SAMPLE_X] *= xMoveScale; + scaled[MotionEvent.SAMPLE_Y] *= yMoveScale; + switch (orientation) { + case Surface.ROTATION_90: { + final float temp = scaled[MotionEvent.SAMPLE_X]; + scaled[MotionEvent.SAMPLE_X] = scaled[MotionEvent.SAMPLE_Y]; + scaled[MotionEvent.SAMPLE_Y] = -temp; + break; } - if (device.absX != null) { - scaledX = ((scaledX-device.absX.minValue) - / device.absX.range) * w; + case Surface.ROTATION_180: { + scaled[MotionEvent.SAMPLE_X] = -scaled[MotionEvent.SAMPLE_X]; + scaled[MotionEvent.SAMPLE_Y] = -scaled[MotionEvent.SAMPLE_Y]; + break; } - if (device.absY != null) { - scaledY = ((scaledY-device.absY.minValue) - / device.absY.range) * h; - } - if (device.absPressure != null) { - scaledPressure = - ((pressure-device.absPressure.minValue) - / (float)device.absPressure.range); - } - if (device.absSize != null) { - scaledSize = - ((size-device.absSize.minValue) - / (float)device.absSize.range); - } - switch (orientation) { - case Surface.ROTATION_90: - temp = scaledX; - scaledX = scaledY; - scaledY = w-temp; - break; - case Surface.ROTATION_180: - scaledX = w-scaledX; - scaledY = h-scaledY; - break; - case Surface.ROTATION_270: - temp = scaledX; - scaledX = h-scaledY; - scaledY = temp; - break; - } - - if (action != MotionEvent.ACTION_DOWN) { - if (scaledX <= 0) { - edgeFlags += MotionEvent.EDGE_LEFT; - } else if (scaledX >= dispW) { - edgeFlags += MotionEvent.EDGE_RIGHT; - } - if (scaledY <= 0) { - edgeFlags += MotionEvent.EDGE_TOP; - } else if (scaledY >= dispH) { - edgeFlags += MotionEvent.EDGE_BOTTOM; - } - } - - } else { - scaledX *= xMoveScale; - scaledY *= yMoveScale; - switch (orientation) { - case Surface.ROTATION_90: - temp = scaledX; - scaledX = scaledY; - scaledY = -temp; - break; - case Surface.ROTATION_180: - scaledX = -scaledX; - scaledY = -scaledY; - break; - case Surface.ROTATION_270: - temp = scaledX; - scaledX = -scaledY; - scaledY = temp; - break; + case Surface.ROTATION_270: { + final float temp = scaled[MotionEvent.SAMPLE_X]; + scaled[MotionEvent.SAMPLE_X] = -scaled[MotionEvent.SAMPLE_Y]; + scaled[MotionEvent.SAMPLE_Y] = temp; + break; } } if (currentMove != null) { - if (false) Log.i("InputDevice", "Adding batch x=" + scaledX - + " y=" + scaledY + " to " + currentMove); - currentMove.addBatch(curTime, scaledX, scaledY, - scaledPressure, scaledSize, metaState); + if (false) Log.i("InputDevice", "Adding batch x=" + + scaled[MotionEvent.SAMPLE_X] + + " y=" + scaled[MotionEvent.SAMPLE_Y] + + " to " + currentMove); + currentMove.addBatch(curTime, scaled, metaState); if (WindowManagerPolicy.WATCH_POINTER) { Log.i("KeyInputQueue", "Updating: " + currentMove); } return null; } - MotionEvent me = MotionEvent.obtainNano(downTime, curTime, - curTimeNano, action, scaledX, scaledY, - scaledPressure, scaledSize, metaState, + MotionEvent me = MotionEvent.obtainNano(mDownTime, curTime, + curTimeNano, action, 1, 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 77051bd0023c8..17e9625409408 100644 --- a/services/java/com/android/server/KeyInputQueue.java +++ b/services/java/com/android/server/KeyInputQueue.java @@ -446,14 +446,14 @@ public abstract class KeyInputQueue { boolean down; if (ev.value != 0) { down = true; - di.mDownTime = curTime; + di.mKeyDownTime = curTime; } else { down = false; } int keycode = rotateKeyCodeLocked(ev.keycode); addLocked(di, curTimeNano, ev.flags, RawInputEvent.CLASS_KEYBOARD, - newKeyEvent(di, di.mDownTime, curTime, down, + newKeyEvent(di, di.mKeyDownTime, curTime, down, keycode, 0, scancode, ((ev.flags & WindowManagerPolicy.FLAG_WOKE_HERE) != 0) ? KeyEvent.FLAG_WOKE_HERE : 0)); @@ -461,29 +461,47 @@ public abstract class KeyInputQueue { if (ev.scancode == RawInputEvent.BTN_TOUCH && (classes&RawInputEvent.CLASS_TOUCHSCREEN) != 0) { di.mAbs.changed = true; - di.mAbs.down = ev.value != 0; - } - if (ev.scancode == RawInputEvent.BTN_MOUSE && + di.mAbs.mDown[0] = ev.value != 0; + } else if (ev.scancode == RawInputEvent.BTN_2 && + (classes&RawInputEvent.CLASS_TOUCHSCREEN) != 0) { + 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.down = ev.value != 0; + di.mRel.mDown[0] = ev.value != 0; send = true; } } 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.x = ev.value; + di.mAbs.mCurData[MotionEvent.SAMPLE_X] = ev.value; } else if (ev.scancode == RawInputEvent.ABS_Y) { di.mAbs.changed = true; - di.mAbs.y = ev.value; + di.mAbs.mCurData[MotionEvent.SAMPLE_Y] = ev.value; } else if (ev.scancode == RawInputEvent.ABS_PRESSURE) { di.mAbs.changed = true; - di.mAbs.pressure = ev.value; + di.mAbs.mCurData[MotionEvent.SAMPLE_PRESSURE] = ev.value; + di.mAbs.mCurData[MotionEvent.NUM_SAMPLE_DATA + + MotionEvent.SAMPLE_PRESSURE] = ev.value; } else if (ev.scancode == RawInputEvent.ABS_TOOL_WIDTH) { di.mAbs.changed = true; - di.mAbs.size = ev.value; + di.mAbs.mCurData[MotionEvent.SAMPLE_SIZE] = ev.value; + di.mAbs.mCurData[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; + } else if (ev.scancode == RawInputEvent.ABS_HAT0Y) { + di.mAbs.changed = true; + di.mAbs.mCurData[MotionEvent.NUM_SAMPLE_DATA + + MotionEvent.SAMPLE_Y] = ev.value; } } else if (ev.type == RawInputEvent.EV_REL && @@ -491,10 +509,10 @@ public abstract class KeyInputQueue { // Add this relative movement into our totals. if (ev.scancode == RawInputEvent.REL_X) { di.mRel.changed = true; - di.mRel.x += ev.value; + di.mRel.mCurData[MotionEvent.SAMPLE_X] += ev.value; } else if (ev.scancode == RawInputEvent.REL_Y) { di.mRel.changed = true; - di.mRel.y += ev.value; + di.mRel.mCurData[MotionEvent.SAMPLE_Y] += ev.value; } } @@ -516,33 +534,33 @@ public abstract class KeyInputQueue { VirtualKey vk = mPressedVirtualKey; if (vk != null) { doMotion = false; - if (!ms.down) { + if (!ms.mDown[0]) { mPressedVirtualKey = null; - ms.lastDown = ms.down; + ms.mLastDown[0] = ms.mDown[0]; if (DEBUG_VIRTUAL_KEYS) Log.v(TAG, "Generate key up for: " + vk.scancode); addLocked(di, curTimeNano, ev.flags, RawInputEvent.CLASS_KEYBOARD, - newKeyEvent(di, di.mDownTime, + newKeyEvent(di, di.mKeyDownTime, curTime, false, vk.lastKeycode, 0, vk.scancode, 0)); } - } else if (ms.down && !ms.lastDown) { + } else if (ms.mDown[0] && !ms.mLastDown[0]) { vk = findSoftButton(di); if (vk != null) { doMotion = false; mPressedVirtualKey = vk; vk.lastKeycode = scancodeToKeycode( di.id, vk.scancode); - ms.lastDown = ms.down; - di.mDownTime = curTime; + 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 + ")"); addLocked(di, curTimeNano, ev.flags, RawInputEvent.CLASS_KEYBOARD, - newKeyEvent(di, di.mDownTime, + newKeyEvent(di, di.mKeyDownTime, curTime, true, vk.lastKeycode, 0, vk.scancode, 0)); @@ -550,11 +568,18 @@ public abstract class KeyInputQueue { } if (doMotion) { - me = ms.generateMotion(di, curTime, - curTimeNano, true, mDisplay, + // XXX Need to be able to generate + // 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.x - + " y=" + di.mAbs.y + " ev=" + me); + 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); @@ -569,11 +594,14 @@ public abstract class KeyInputQueue { if (ms.changed) { ms.changed = false; - me = ms.generateMotion(di, curTime, - curTimeNano, false, mDisplay, + me = ms.generateRelMotion(di, curTime, + curTimeNano, mOrientation, mGlobalMetaState); - if (false) Log.v(TAG, "Relative: x=" + di.mRel.x - + " y=" + di.mRel.y + " ev=" + me); + if (false) Log.v(TAG, "Relative: x=" + + di.mRel.mCurData[MotionEvent.SAMPLE_X] + + " y=" + + di.mRel.mCurData[MotionEvent.SAMPLE_Y] + + " ev=" + me); if (me != null) { addLocked(di, curTimeNano, ev.flags, RawInputEvent.CLASS_TRACKBALL, me); @@ -603,21 +631,28 @@ public abstract class KeyInputQueue { return null; } - if (absm.x >= absx.minValue && absm.x <= absx.maxValue - && absm.y >= absy.minValue && absm.y <= absy.maxValue) { - if (DEBUG_VIRTUAL_KEYS) Log.v(TAG, "Input (" + absm.x - + "," + absm.y + ") inside of display"); + 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 (DEBUG_VIRTUAL_KEYS) Log.v(TAG, "Input (" + + absm.mCurData[MotionEvent.SAMPLE_X] + + "," + absm.mCurData[MotionEvent.SAMPLE_Y] + + ") inside of display"); return null; } for (int i=0; i