diff options
Diffstat (limited to 'services/java/com/android/server/InputDevice.java')
-rw-r--r-- | services/java/com/android/server/InputDevice.java | 1025 |
1 files changed, 0 insertions, 1025 deletions
diff --git a/services/java/com/android/server/InputDevice.java b/services/java/com/android/server/InputDevice.java deleted file mode 100644 index 414b69f..0000000 --- a/services/java/com/android/server/InputDevice.java +++ /dev/null @@ -1,1025 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.server; - -import android.util.Slog; -import android.view.Display; -import android.view.MotionEvent; -import android.view.Surface; -import android.view.WindowManagerPolicy; - -import java.io.PrintWriter; - -public class InputDevice { - static final boolean DEBUG_POINTERS = false; - static final boolean DEBUG_HACKS = 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 = 10; - - /** - * Slop distance for jumpy pointer detection. - * The vertical range of the screen divided by this is our epsilon value. - */ - private static final int JUMPY_EPSILON_DIVISOR = 212; - - /** Number of jumpy points to drop for touchscreens that need it. */ - private static final int JUMPY_TRANSITION_DROPS = 3; - private static final int JUMPY_DROP_LIMIT = 3; - - final int id; - final int classes; - final String name; - final AbsoluteInfo absX; - final AbsoluteInfo absY; - final AbsoluteInfo absPressure; - final AbsoluteInfo absSize; - - long mKeyDownTime = 0; - int mMetaKeysState = 0; - - // For use by KeyInputQueue for keeping track of the current touch - // data in the old non-multi-touch protocol. - final int[] curTouchVals = new int[MotionEvent.NUM_SAMPLE_DATA * 2]; - - final MotionState mAbs = new MotionState(0, 0); - final MotionState mRel = new MotionState(TRACKBALL_MOVEMENT_THRESHOLD, - TRACKBALL_MOVEMENT_THRESHOLD); - - static class MotionState { - int xPrecision; - int yPrecision; - float xMoveScale; - float yMoveScale; - MotionEvent currentMove = null; - boolean changed = false; - boolean everChanged = false; - long mDownTime = 0; - - // 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. - boolean mSkipLastPointers; - int mLastNumPointers = 0; - final int[] mLastData = 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]; - - // Used to determine whether we dropped bad data, to avoid doing - // it repeatedly. - final boolean[] mDroppedBadPoint = new boolean[MAX_POINTERS]; - - // Used to count the number of jumpy points dropped. - private int mJumpyPointsDropped = 0; - - // Used to perform averaging of reported coordinates, to smooth - // the data and filter out transients during a release. - static final int HISTORY_SIZE = 5; - int[] mHistoryDataStart = new int[MAX_POINTERS]; - int[] mHistoryDataEnd = new int[MAX_POINTERS]; - final int[] mHistoryData = new int[(MotionEvent.NUM_SAMPLE_DATA * MAX_POINTERS) - * HISTORY_SIZE]; - final int[] mAveragedData = new int[MotionEvent.NUM_SAMPLE_DATA * MAX_POINTERS]; - - // 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]; - - void dumpIntArray(PrintWriter pw, int[] array) { - pw.print("["); - for (int i=0; i<array.length; i++) { - if (i > 0) pw.print(", "); - pw.print(array[i]); - } - pw.print("]"); - } - - void dumpBooleanArray(PrintWriter pw, boolean[] array) { - pw.print("["); - for (int i=0; i<array.length; i++) { - if (i > 0) pw.print(", "); - pw.print(array[i] ? "true" : "false"); - } - pw.print("]"); - } - - void dump(PrintWriter pw, String prefix) { - pw.print(prefix); pw.print("xPrecision="); pw.print(xPrecision); - pw.print(" yPrecision="); pw.println(yPrecision); - pw.print(prefix); pw.print("xMoveScale="); pw.print(xMoveScale); - pw.print(" yMoveScale="); pw.println(yMoveScale); - if (currentMove != null) { - pw.print(prefix); pw.print("currentMove="); pw.println(currentMove); - } - if (changed || mDownTime != 0) { - pw.print(prefix); pw.print("changed="); pw.print(changed); - pw.print(" mDownTime="); pw.println(mDownTime); - } - pw.print(prefix); pw.print("mPointerIds="); dumpIntArray(pw, mPointerIds); - pw.println(""); - if (mSkipLastPointers || mLastNumPointers != 0) { - pw.print(prefix); pw.print("mSkipLastPointers="); pw.print(mSkipLastPointers); - pw.print(" mLastNumPointers="); pw.println(mLastNumPointers); - pw.print(prefix); pw.print("mLastData="); dumpIntArray(pw, mLastData); - pw.println(""); - } - if (mNextNumPointers != 0) { - pw.print(prefix); pw.print("mNextNumPointers="); pw.println(mNextNumPointers); - pw.print(prefix); pw.print("mNextData="); dumpIntArray(pw, mNextData); - pw.println(""); - } - pw.print(prefix); pw.print("mDroppedBadPoint="); - dumpBooleanArray(pw, mDroppedBadPoint); pw.println(""); - pw.print(prefix); pw.print("mAddingPointerOffset="); pw.println(mAddingPointerOffset); - pw.print(prefix); pw.print("mDown="); - dumpBooleanArray(pw, mDown); pw.println(""); - } - - 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; - } - } - - /** - * Special hack for devices that have bad screen data: if one of the - * points has moved more than a screen height from the last position, - * then drop it. - */ - void dropBadPoint(InputDevice dev) { - // We should always have absY, but let's be paranoid. - if (dev.absY == null) { - return; - } - // Don't do anything if a finger is going down or up. We run - // here before assigning pointer IDs, so there isn't a good - // way to do per-finger matching. - if (mNextNumPointers != mLastNumPointers) { - return; - } - - // We consider a single movement across more than a 7/16 of - // the long size of the screen to be bad. This was a magic value - // determined by looking at the maximum distance it is feasible - // to actually move in one sample. - final int maxDy = ((dev.absY.maxValue-dev.absY.minValue)*7)/16; - - // Look through all new points and see if any are farther than - // acceptable from all previous points. - for (int i=mNextNumPointers-1; i>=0; i--) { - final int ioff = i * MotionEvent.NUM_SAMPLE_DATA; - //final int x = mNextData[ioff + MotionEvent.SAMPLE_X]; - final int y = mNextData[ioff + MotionEvent.SAMPLE_Y]; - if (DEBUG_HACKS) Slog.v("InputDevice", "Looking at next point #" + i + ": y=" + y); - boolean dropped = false; - if (!mDroppedBadPoint[i] && mLastNumPointers > 0) { - dropped = true; - int closestDy = -1; - int closestY = -1; - // We will drop this new point if it is sufficiently - // far away from -all- last points. - for (int j=mLastNumPointers-1; j>=0; j--) { - final int joff = j * MotionEvent.NUM_SAMPLE_DATA; - //int dx = x - mLastData[joff + MotionEvent.SAMPLE_X]; - int dy = y - mLastData[joff + MotionEvent.SAMPLE_Y]; - //if (dx < 0) dx = -dx; - if (dy < 0) dy = -dy; - if (DEBUG_HACKS) Slog.v("InputDevice", "Comparing with last point #" + j - + ": y=" + mLastData[joff] + " dy=" + dy); - if (dy < maxDy) { - dropped = false; - break; - } else if (closestDy < 0 || dy < closestDy) { - closestDy = dy; - closestY = mLastData[joff + MotionEvent.SAMPLE_Y]; - } - } - if (dropped) { - dropped = true; - Slog.i("InputDevice", "Dropping bad point #" + i - + ": newY=" + y + " closestDy=" + closestDy - + " maxDy=" + maxDy); - mNextData[ioff + MotionEvent.SAMPLE_Y] = closestY; - break; - } - } - mDroppedBadPoint[i] = dropped; - } - } - - void dropJumpyPoint(InputDevice dev) { - // We should always have absY, but let's be paranoid. - if (dev.absY == null) { - return; - } - final int jumpyEpsilon = dev.absY.range / JUMPY_EPSILON_DIVISOR; - - final int nextNumPointers = mNextNumPointers; - final int lastNumPointers = mLastNumPointers; - final int[] nextData = mNextData; - final int[] lastData = mLastData; - - if (nextNumPointers != mLastNumPointers) { - if (DEBUG_HACKS) { - Slog.d("InputDevice", "Different pointer count " + lastNumPointers + - " -> " + nextNumPointers); - for (int i = 0; i < nextNumPointers; i++) { - int ioff = i * MotionEvent.NUM_SAMPLE_DATA; - Slog.d("InputDevice", "Pointer " + i + " (" + - mNextData[ioff + MotionEvent.SAMPLE_X] + ", " + - mNextData[ioff + MotionEvent.SAMPLE_Y] + ")"); - } - } - - // Just drop the first few events going from 1 to 2 pointers. - // They're bad often enough that they're not worth considering. - if (lastNumPointers == 1 && nextNumPointers == 2 - && mJumpyPointsDropped < JUMPY_TRANSITION_DROPS) { - mNextNumPointers = 1; - mJumpyPointsDropped++; - } else if (lastNumPointers == 2 && nextNumPointers == 1 - && mJumpyPointsDropped < JUMPY_TRANSITION_DROPS) { - // The event when we go from 2 -> 1 tends to be messed up too - System.arraycopy(lastData, 0, nextData, 0, - lastNumPointers * MotionEvent.NUM_SAMPLE_DATA); - mNextNumPointers = lastNumPointers; - mJumpyPointsDropped++; - - if (DEBUG_HACKS) { - for (int i = 0; i < mNextNumPointers; i++) { - int ioff = i * MotionEvent.NUM_SAMPLE_DATA; - Slog.d("InputDevice", "Pointer " + i + " replaced (" + - mNextData[ioff + MotionEvent.SAMPLE_X] + ", " + - mNextData[ioff + MotionEvent.SAMPLE_Y] + ")"); - } - } - } else { - mJumpyPointsDropped = 0; - - if (DEBUG_HACKS) { - Slog.d("InputDevice", "Transition - drop limit reset"); - } - } - return; - } - - // A 'jumpy' point is one where the coordinate value for one axis - // has jumped to the other pointer's location. No need to do anything - // else if we only have one pointer. - if (nextNumPointers < 2) { - return; - } - - int badPointerIndex = -1; - int badPointerReplaceXWith = 0; - int badPointerReplaceYWith = 0; - int badPointerDistance = Integer.MIN_VALUE; - for (int i = nextNumPointers - 1; i >= 0; i--) { - boolean dropx = false; - boolean dropy = false; - - // Limit how many times a jumpy point can get dropped. - if (mJumpyPointsDropped < JUMPY_DROP_LIMIT) { - final int ioff = i * MotionEvent.NUM_SAMPLE_DATA; - final int x = nextData[ioff + MotionEvent.SAMPLE_X]; - final int y = nextData[ioff + MotionEvent.SAMPLE_Y]; - - if (DEBUG_HACKS) { - Slog.d("InputDevice", "Point " + i + " (" + x + ", " + y + ")"); - } - - // Check if a touch point is too close to another's coordinates - for (int j = 0; j < nextNumPointers && !dropx && !dropy; j++) { - if (j == i) { - continue; - } - - final int joff = j * MotionEvent.NUM_SAMPLE_DATA; - final int xOther = nextData[joff + MotionEvent.SAMPLE_X]; - final int yOther = nextData[joff + MotionEvent.SAMPLE_Y]; - - dropx = Math.abs(x - xOther) <= jumpyEpsilon; - dropy = Math.abs(y - yOther) <= jumpyEpsilon; - } - - if (dropx) { - int xreplace = lastData[MotionEvent.SAMPLE_X]; - int yreplace = lastData[MotionEvent.SAMPLE_Y]; - int distance = Math.abs(yreplace - y); - for (int j = 1; j < lastNumPointers; j++) { - final int joff = j * MotionEvent.NUM_SAMPLE_DATA; - int lasty = lastData[joff + MotionEvent.SAMPLE_Y]; - int currDist = Math.abs(lasty - y); - if (currDist < distance) { - xreplace = lastData[joff + MotionEvent.SAMPLE_X]; - yreplace = lasty; - distance = currDist; - } - } - - int badXDelta = Math.abs(xreplace - x); - if (badXDelta > badPointerDistance) { - badPointerDistance = badXDelta; - badPointerIndex = i; - badPointerReplaceXWith = xreplace; - badPointerReplaceYWith = yreplace; - } - } else if (dropy) { - int xreplace = lastData[MotionEvent.SAMPLE_X]; - int yreplace = lastData[MotionEvent.SAMPLE_Y]; - int distance = Math.abs(xreplace - x); - for (int j = 1; j < lastNumPointers; j++) { - final int joff = j * MotionEvent.NUM_SAMPLE_DATA; - int lastx = lastData[joff + MotionEvent.SAMPLE_X]; - int currDist = Math.abs(lastx - x); - if (currDist < distance) { - xreplace = lastx; - yreplace = lastData[joff + MotionEvent.SAMPLE_Y]; - distance = currDist; - } - } - - int badYDelta = Math.abs(yreplace - y); - if (badYDelta > badPointerDistance) { - badPointerDistance = badYDelta; - badPointerIndex = i; - badPointerReplaceXWith = xreplace; - badPointerReplaceYWith = yreplace; - } - } - } - } - if (badPointerIndex >= 0) { - if (DEBUG_HACKS) { - Slog.d("InputDevice", "Replacing bad pointer " + badPointerIndex + - " with (" + badPointerReplaceXWith + ", " + badPointerReplaceYWith + - ")"); - } - - final int offset = badPointerIndex * MotionEvent.NUM_SAMPLE_DATA; - nextData[offset + MotionEvent.SAMPLE_X] = badPointerReplaceXWith; - nextData[offset + MotionEvent.SAMPLE_Y] = badPointerReplaceYWith; - mJumpyPointsDropped++; - } else { - mJumpyPointsDropped = 0; - } - } - - /** - * Special hack for devices that have bad screen data: aggregate and - * compute averages of the coordinate data, to reduce the amount of - * jitter seen by applications. - */ - int[] generateAveragedData(int upOrDownPointer, int lastNumPointers, - int nextNumPointers) { - final int numPointers = mLastNumPointers; - final int[] rawData = mLastData; - if (DEBUG_HACKS) Slog.v("InputDevice", "lastNumPointers=" + lastNumPointers - + " nextNumPointers=" + nextNumPointers - + " numPointers=" + numPointers); - for (int i=0; i<numPointers; i++) { - final int ioff = i * MotionEvent.NUM_SAMPLE_DATA; - // We keep the average data in offsets based on the pointer - // ID, so we don't need to move it around as fingers are - // pressed and released. - final int p = mPointerIds[i]; - final int poff = p * MotionEvent.NUM_SAMPLE_DATA * HISTORY_SIZE; - if (i == upOrDownPointer && lastNumPointers != nextNumPointers) { - if (lastNumPointers < nextNumPointers) { - // This pointer is going down. Clear its history - // and start fresh. - if (DEBUG_HACKS) Slog.v("InputDevice", "Pointer down @ index " - + upOrDownPointer + " id " + mPointerIds[i]); - mHistoryDataStart[i] = 0; - mHistoryDataEnd[i] = 0; - System.arraycopy(rawData, ioff, mHistoryData, poff, - MotionEvent.NUM_SAMPLE_DATA); - System.arraycopy(rawData, ioff, mAveragedData, ioff, - MotionEvent.NUM_SAMPLE_DATA); - continue; - } else { - // The pointer is going up. Just fall through to - // recompute the last averaged point (and don't add - // it as a new point to include in the average). - if (DEBUG_HACKS) Slog.v("InputDevice", "Pointer up @ index " - + upOrDownPointer + " id " + mPointerIds[i]); - } - } else { - int end = mHistoryDataEnd[i]; - int eoff = poff + (end*MotionEvent.NUM_SAMPLE_DATA); - int oldX = mHistoryData[eoff + MotionEvent.SAMPLE_X]; - int oldY = mHistoryData[eoff + MotionEvent.SAMPLE_Y]; - int newX = rawData[ioff + MotionEvent.SAMPLE_X]; - int newY = rawData[ioff + MotionEvent.SAMPLE_Y]; - int dx = newX-oldX; - int dy = newY-oldY; - int delta = dx*dx + dy*dy; - if (DEBUG_HACKS) Slog.v("InputDevice", "Delta from last: " + delta); - if (delta >= (75*75)) { - // Magic number, if moving farther than this, turn - // off filtering to avoid lag in response. - mHistoryDataStart[i] = 0; - mHistoryDataEnd[i] = 0; - System.arraycopy(rawData, ioff, mHistoryData, poff, - MotionEvent.NUM_SAMPLE_DATA); - System.arraycopy(rawData, ioff, mAveragedData, ioff, - MotionEvent.NUM_SAMPLE_DATA); - continue; - } else { - end++; - if (end >= HISTORY_SIZE) { - end -= HISTORY_SIZE; - } - mHistoryDataEnd[i] = end; - int noff = poff + (end*MotionEvent.NUM_SAMPLE_DATA); - mHistoryData[noff + MotionEvent.SAMPLE_X] = newX; - mHistoryData[noff + MotionEvent.SAMPLE_Y] = newY; - mHistoryData[noff + MotionEvent.SAMPLE_PRESSURE] - = rawData[ioff + MotionEvent.SAMPLE_PRESSURE]; - int start = mHistoryDataStart[i]; - if (end == start) { - start++; - if (start >= HISTORY_SIZE) { - start -= HISTORY_SIZE; - } - mHistoryDataStart[i] = start; - } - } - } - - // Now compute the average. - int start = mHistoryDataStart[i]; - int end = mHistoryDataEnd[i]; - int x=0, y=0; - int totalPressure = 0; - while (start != end) { - int soff = poff + (start*MotionEvent.NUM_SAMPLE_DATA); - int pressure = mHistoryData[soff + MotionEvent.SAMPLE_PRESSURE]; - if (pressure <= 0) pressure = 1; - x += mHistoryData[soff + MotionEvent.SAMPLE_X] * pressure; - y += mHistoryData[soff + MotionEvent.SAMPLE_Y] * pressure; - totalPressure += pressure; - start++; - if (start >= HISTORY_SIZE) start = 0; - } - int eoff = poff + (end*MotionEvent.NUM_SAMPLE_DATA); - int pressure = mHistoryData[eoff + MotionEvent.SAMPLE_PRESSURE]; - if (pressure <= 0) pressure = 1; - x += mHistoryData[eoff + MotionEvent.SAMPLE_X] * pressure; - y += mHistoryData[eoff + MotionEvent.SAMPLE_Y] * pressure; - totalPressure += pressure; - x /= totalPressure; - y /= totalPressure; - if (DEBUG_HACKS) Slog.v("InputDevice", "Averaging " + totalPressure - + " weight: (" + x + "," + y + ")"); - mAveragedData[ioff + MotionEvent.SAMPLE_X] = x; - mAveragedData[ioff + MotionEvent.SAMPLE_Y] = y; - mAveragedData[ioff + MotionEvent.SAMPLE_PRESSURE] = - rawData[ioff + MotionEvent.SAMPLE_PRESSURE]; - mAveragedData[ioff + MotionEvent.SAMPLE_SIZE] = - rawData[ioff + MotionEvent.SAMPLE_SIZE]; - } - return mAveragedData; - } - - 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; - - if (DEBUG_POINTERS) Slog.v("InputDevice", "assignPointer: nextIndex=" - + nextIndex + " dataOff=" + id); - final int x1 = nextData[id + MotionEvent.SAMPLE_X]; - final int y1 = nextData[id + MotionEvent.SAMPLE_Y]; - - long bestDistance = -1; - int bestIndex = -1; - for (int j=0; j<lastNumPointers; j++) { - // If we are not allowing multiple new points to be assigned - // to the same old pointer, then skip this one if it is already - // detected as a conflict (-2). - if (!allowOverlap && last2Next[j] < -1) { - 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 (bestDistance == -1 || distance < bestDistance) { - bestDistance = distance; - bestIndex = j; - } - } - - if (DEBUG_POINTERS) Slog.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) Slog.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) Slog.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) Slog.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) Slog.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) Slog.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) Slog.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) Slog.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); - System.arraycopy(next2Last, i, next2Last, - i+1, lastNumPointers-i); - break; - } - i++; - nextId++; - } - - if (DEBUG_POINTERS) Slog.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) Slog.v("InputDevice", - "Assigning new id to new pointer index " + j); - next2Last[j] = i; - break; - } - } - } - - // 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) Slog.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) Slog.v("InputDevice", "Removing old pointer"); - for (int i=0; i<lastNumPointers; i++) { - if (last2Next[i] == -1) { - if (DEBUG_POINTERS) Slog.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 (mSkipLastPointers) { - mSkipLastPointers = false; - mLastNumPointers = 0; - } - - if (mNextNumPointers <= 0 && mLastNumPointers <= 0) { - return null; - } - - final int lastNumPointers = mLastNumPointers; - final int nextNumPointers = mNextNumPointers; - if (mNextNumPointers > MAX_POINTERS) { - Slog.w("InputDevice", "Number of pointers " + mNextNumPointers - + " exceeded maximum of " + MAX_POINTERS); - mNextNumPointers = MAX_POINTERS; - } - - int upOrDownPointer = updatePointerIdentifiers(); - - final float[] reportData = mReportData; - final int[] rawData; - if (KeyInputQueue.BAD_TOUCH_HACK) { - rawData = generateAveragedData(upOrDownPointer, lastNumPointers, - nextNumPointers); - } else { - rawData = mLastData; - } - - final int numPointers = mLastNumPointers; - - if (DEBUG_POINTERS) Slog.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 (nextNumPointers != lastNumPointers) { - if (nextNumPointers > lastNumPointers) { - if (lastNumPointers == 0) { - action = MotionEvent.ACTION_DOWN; - mDownTime = curTime; - } else { - action = MotionEvent.ACTION_POINTER_DOWN - | (upOrDownPointer << MotionEvent.ACTION_POINTER_INDEX_SHIFT); - } - } else { - if (numPointers == 1) { - action = MotionEvent.ACTION_UP; - } else { - action = MotionEvent.ACTION_POINTER_UP - | (upOrDownPointer << MotionEvent.ACTION_POINTER_INDEX_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<numPointers; i++) { - final int j = i * MotionEvent.NUM_SAMPLE_DATA; - - if (absX != null) { - reportData[j + MotionEvent.SAMPLE_X] = - ((reportData[j + MotionEvent.SAMPLE_X]-absX.minValue) - / absX.range) * w; - } - if (absY != null) { - reportData[j + MotionEvent.SAMPLE_Y] = - ((reportData[j + MotionEvent.SAMPLE_Y]-absY.minValue) - / absY.range) * h; - } - if (absPressure != null) { - reportData[j + MotionEvent.SAMPLE_PRESSURE] = - ((reportData[j + MotionEvent.SAMPLE_PRESSURE]-absPressure.minValue) - / (float)absPressure.range); - } - if (absSize != null) { - reportData[j + MotionEvent.SAMPLE_SIZE] = - ((reportData[j + MotionEvent.SAMPLE_SIZE]-absSize.minValue) - / (float)absSize.range); - } - - switch (orientation) { - case Surface.ROTATION_90: { - final float temp = reportData[j + 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: { - 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 = reportData[j + MotionEvent.SAMPLE_X]; - reportData[j + MotionEvent.SAMPLE_X] = h-reportData[j + MotionEvent.SAMPLE_Y]; - reportData[j + MotionEvent.SAMPLE_Y] = temp; - break; - } - } - } - - // We only consider the first pointer when computing the edge - // flags, since they are global to the event. - if (action == MotionEvent.ACTION_DOWN) { - if (reportData[MotionEvent.SAMPLE_X] <= 0) { - edgeFlags |= MotionEvent.EDGE_LEFT; - } else if (reportData[MotionEvent.SAMPLE_X] >= dispW) { - edgeFlags |= MotionEvent.EDGE_RIGHT; - } - if (reportData[MotionEvent.SAMPLE_Y] <= 0) { - edgeFlags |= MotionEvent.EDGE_TOP; - } else if (reportData[MotionEvent.SAMPLE_Y] >= dispH) { - edgeFlags |= MotionEvent.EDGE_BOTTOM; - } - } - - if (currentMove != null) { - if (false) Slog.i("InputDevice", "Adding batch x=" - + reportData[MotionEvent.SAMPLE_X] - + " y=" + reportData[MotionEvent.SAMPLE_Y] - + " to " + currentMove); - currentMove.addBatch(curTime, reportData, metaState); - if (WindowManagerPolicy.WATCH_POINTER) { - Slog.i("KeyInputQueue", "Updating: " + currentMove); - } - return null; - } - - MotionEvent me = MotionEvent.obtainNano(mDownTime, curTime, - 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] = 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 (mNextNumPointers != mLastNumPointers) { - mNextData[MotionEvent.SAMPLE_X] = - mNextData[MotionEvent.SAMPLE_Y] = 0; - if (mNextNumPointers > 0 && mLastNumPointers == 0) { - action = MotionEvent.ACTION_DOWN; - mDownTime = curTime; - } else if (mNextNumPointers == 0) { - action = MotionEvent.ACTION_UP; - } else { - action = MotionEvent.ACTION_MOVE; - } - mLastNumPointers = mNextNumPointers; - currentMove = null; - } else { - action = MotionEvent.ACTION_MOVE; - } - - 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; - } - case Surface.ROTATION_180: { - scaled[MotionEvent.SAMPLE_X] = -scaled[MotionEvent.SAMPLE_X]; - scaled[MotionEvent.SAMPLE_Y] = -scaled[MotionEvent.SAMPLE_Y]; - 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) Slog.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) { - Slog.i("KeyInputQueue", "Updating: " + currentMove); - } - return null; - } - - MotionEvent me = MotionEvent.obtainNano(mDownTime, curTime, - curTimeNano, action, 1, mPointerIds, scaled, metaState, - xPrecision, yPrecision, device.id, edgeFlags); - if (action == MotionEvent.ACTION_MOVE) { - currentMove = me; - } - return me; - } - } - - static class AbsoluteInfo { - int minValue; - int maxValue; - int range; - int flat; - int fuzz; - - final void dump(PrintWriter pw) { - pw.print("minValue="); pw.print(minValue); - pw.print(" maxValue="); pw.print(maxValue); - pw.print(" range="); pw.print(range); - pw.print(" flat="); pw.print(flat); - pw.print(" fuzz="); pw.print(fuzz); - } - }; - - InputDevice(int _id, int _classes, String _name, - AbsoluteInfo _absX, AbsoluteInfo _absY, - AbsoluteInfo _absPressure, AbsoluteInfo _absSize) { - id = _id; - classes = _classes; - name = _name; - absX = _absX; - absY = _absY; - absPressure = _absPressure; - absSize = _absSize; - } -}; |