eclair snapshot
This commit is contained in:
@@ -23,9 +23,15 @@ import android.view.Surface;
|
||||
import android.view.WindowManagerPolicy;
|
||||
|
||||
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;
|
||||
|
||||
final int id;
|
||||
final int classes;
|
||||
final String name;
|
||||
@@ -34,9 +40,13 @@ public class InputDevice {
|
||||
final AbsoluteInfo absPressure;
|
||||
final AbsoluteInfo absSize;
|
||||
|
||||
long mDownTime = 0;
|
||||
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);
|
||||
@@ -48,146 +58,707 @@ public class InputDevice {
|
||||
float yMoveScale;
|
||||
MotionEvent currentMove = null;
|
||||
boolean changed = false;
|
||||
boolean down = false;
|
||||
boolean lastDown = false;
|
||||
long downTime = 0;
|
||||
int x = 0;
|
||||
int y = 0;
|
||||
int pressure = 1;
|
||||
int size = 0;
|
||||
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 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];
|
||||
|
||||
MotionState(int mx, int my) {
|
||||
xPrecision = mx;
|
||||
yPrecision = my;
|
||||
xMoveScale = mx != 0 ? (1.0f/mx) : 1.0f;
|
||||
yMoveScale = my != 0 ? (1.0f/my) : 1.0f;
|
||||
for (int i=0; i<MAX_POINTERS; i++) {
|
||||
mPointerIds[i] = i;
|
||||
}
|
||||
}
|
||||
|
||||
MotionEvent generateMotion(InputDevice device, long curTime,
|
||||
boolean isAbs, Display display, int orientation,
|
||||
/**
|
||||
* 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) Log.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) Log.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;
|
||||
Log.i("InputDevice", "Dropping bad point #" + i
|
||||
+ ": newY=" + y + " closestDy=" + closestDy
|
||||
+ " maxDy=" + maxDy);
|
||||
mNextData[ioff + MotionEvent.SAMPLE_Y] = closestY;
|
||||
break;
|
||||
}
|
||||
}
|
||||
mDroppedBadPoint[i] = dropped;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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) Log.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) Log.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) Log.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) Log.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) Log.v("InputDevice", "Averaging " + totalPressure
|
||||
+ " weight: (" + x + "," + y + ")");
|
||||
mAveragedData[ioff + MotionEvent.SAMPLE_X] = x;
|
||||
mAveragedData[ioff + MotionEvent.SAMPLE_Y] = y;
|
||||
}
|
||||
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) Log.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 (!allowOverlap && last2Next[j] < 0) {
|
||||
continue;
|
||||
}
|
||||
final int jd = j * MotionEvent.NUM_SAMPLE_DATA;
|
||||
final int xd = lastData[jd + MotionEvent.SAMPLE_X] - x1;
|
||||
final int yd = lastData[jd + MotionEvent.SAMPLE_Y] - y1;
|
||||
final long distance = xd*(long)xd + yd*(long)yd;
|
||||
if (j == 0 || distance < bestDistance) {
|
||||
bestDistance = distance;
|
||||
bestIndex = j;
|
||||
}
|
||||
}
|
||||
|
||||
if (DEBUG_POINTERS) Log.v("InputDevice", "New index " + nextIndex
|
||||
+ " best old index=" + bestIndex + " (distance="
|
||||
+ bestDistance + ")");
|
||||
next2Last[nextIndex] = bestIndex;
|
||||
next2LastDistance[nextIndex] = bestDistance;
|
||||
|
||||
if (bestIndex < 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (last2Next[bestIndex] == -1) {
|
||||
last2Next[bestIndex] = nextIndex;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (DEBUG_POINTERS) Log.v("InputDevice", "Old index " + bestIndex
|
||||
+ " has multiple best new pointers!");
|
||||
|
||||
last2Next[bestIndex] = -2;
|
||||
return true;
|
||||
}
|
||||
|
||||
private int updatePointerIdentifiers() {
|
||||
final int[] lastData = mLastData;
|
||||
final int[] nextData = mNextData;
|
||||
final int nextNumPointers = mNextNumPointers;
|
||||
final int lastNumPointers = mLastNumPointers;
|
||||
|
||||
if (nextNumPointers == 1 && lastNumPointers == 1) {
|
||||
System.arraycopy(nextData, 0, lastData, 0,
|
||||
MotionEvent.NUM_SAMPLE_DATA);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Clear our old state.
|
||||
final int[] last2Next = mLast2Next;
|
||||
for (int i=0; i<lastNumPointers; i++) {
|
||||
last2Next[i] = -1;
|
||||
}
|
||||
|
||||
if (DEBUG_POINTERS) Log.v("InputDevice",
|
||||
"Update pointers: lastNumPointers=" + lastNumPointers
|
||||
+ " nextNumPointers=" + nextNumPointers);
|
||||
|
||||
// Figure out the closes new points to the previous points.
|
||||
final int[] next2Last = mNext2Last;
|
||||
final long[] next2LastDistance = mNext2LastDistance;
|
||||
boolean conflicts = false;
|
||||
for (int i=0; i<nextNumPointers; i++) {
|
||||
conflicts |= assignPointer(i, true);
|
||||
}
|
||||
|
||||
// Resolve ambiguities in pointer mappings, when two or more
|
||||
// new pointer locations find their best previous location is
|
||||
// the same.
|
||||
if (conflicts) {
|
||||
if (DEBUG_POINTERS) Log.v("InputDevice", "Resolving conflicts");
|
||||
|
||||
for (int i=0; i<lastNumPointers; i++) {
|
||||
if (last2Next[i] != -2) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Note that this algorithm is far from perfect. Ideally
|
||||
// we should do something like the one described at
|
||||
// http://portal.acm.org/citation.cfm?id=997856
|
||||
|
||||
if (DEBUG_POINTERS) Log.v("InputDevice",
|
||||
"Resolving last index #" + i);
|
||||
|
||||
int numFound;
|
||||
do {
|
||||
numFound = 0;
|
||||
long worstDistance = 0;
|
||||
int worstJ = -1;
|
||||
for (int j=0; j<nextNumPointers; j++) {
|
||||
if (next2Last[j] != i) {
|
||||
continue;
|
||||
}
|
||||
numFound++;
|
||||
if (worstDistance < next2LastDistance[j]) {
|
||||
worstDistance = next2LastDistance[j];
|
||||
worstJ = j;
|
||||
}
|
||||
}
|
||||
|
||||
if (worstJ >= 0) {
|
||||
if (DEBUG_POINTERS) Log.v("InputDevice",
|
||||
"Worst new pointer: " + worstJ
|
||||
+ " (distance=" + worstDistance + ")");
|
||||
if (assignPointer(worstJ, false)) {
|
||||
// In this case there is no last pointer
|
||||
// remaining for this new one!
|
||||
next2Last[worstJ] = -1;
|
||||
}
|
||||
}
|
||||
} while (numFound > 2);
|
||||
}
|
||||
}
|
||||
|
||||
int retIndex = -1;
|
||||
|
||||
if (lastNumPointers < nextNumPointers) {
|
||||
// We have one or more new pointers that are down. Create a
|
||||
// new pointer identifier for one of them.
|
||||
if (DEBUG_POINTERS) Log.v("InputDevice", "Adding new pointer");
|
||||
int nextId = 0;
|
||||
int i=0;
|
||||
while (i < lastNumPointers) {
|
||||
if (mPointerIds[i] > nextId) {
|
||||
// Found a hole, insert the pointer here.
|
||||
if (DEBUG_POINTERS) Log.v("InputDevice",
|
||||
"Inserting new pointer at hole " + i);
|
||||
System.arraycopy(mPointerIds, i, mPointerIds,
|
||||
i+1, lastNumPointers-i);
|
||||
System.arraycopy(lastData, i*MotionEvent.NUM_SAMPLE_DATA,
|
||||
lastData, (i+1)*MotionEvent.NUM_SAMPLE_DATA,
|
||||
(lastNumPointers-i)*MotionEvent.NUM_SAMPLE_DATA);
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
nextId++;
|
||||
}
|
||||
|
||||
if (DEBUG_POINTERS) Log.v("InputDevice",
|
||||
"New pointer id " + nextId + " at index " + i);
|
||||
|
||||
mLastNumPointers++;
|
||||
retIndex = i;
|
||||
mPointerIds[i] = nextId;
|
||||
|
||||
// And assign this identifier to the first new pointer.
|
||||
for (int j=0; j<nextNumPointers; j++) {
|
||||
if (next2Last[j] < 0) {
|
||||
if (DEBUG_POINTERS) Log.v("InputDevice",
|
||||
"Assigning new id to new pointer index " + j);
|
||||
next2Last[j] = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Propagate all of the current data into the appropriate
|
||||
// location in the old data to match the pointer ID that was
|
||||
// assigned to it.
|
||||
for (int i=0; i<nextNumPointers; i++) {
|
||||
int lastIndex = next2Last[i];
|
||||
if (lastIndex >= 0) {
|
||||
if (DEBUG_POINTERS) Log.v("InputDevice",
|
||||
"Copying next pointer index " + i
|
||||
+ " to last index " + lastIndex);
|
||||
System.arraycopy(nextData, i*MotionEvent.NUM_SAMPLE_DATA,
|
||||
lastData, lastIndex*MotionEvent.NUM_SAMPLE_DATA,
|
||||
MotionEvent.NUM_SAMPLE_DATA);
|
||||
}
|
||||
}
|
||||
|
||||
if (lastNumPointers > nextNumPointers) {
|
||||
// One or more pointers has gone up. Find the first one,
|
||||
// and adjust accordingly.
|
||||
if (DEBUG_POINTERS) Log.v("InputDevice", "Removing old pointer");
|
||||
for (int i=0; i<lastNumPointers; i++) {
|
||||
if (last2Next[i] == -1) {
|
||||
if (DEBUG_POINTERS) Log.v("InputDevice",
|
||||
"Removing old pointer at index " + i);
|
||||
retIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return retIndex;
|
||||
}
|
||||
|
||||
void removeOldPointer(int index) {
|
||||
final int lastNumPointers = mLastNumPointers;
|
||||
if (index >= 0 && index < lastNumPointers) {
|
||||
System.arraycopy(mPointerIds, index+1, mPointerIds,
|
||||
index, lastNumPointers-index-1);
|
||||
System.arraycopy(mLastData, (index+1)*MotionEvent.NUM_SAMPLE_DATA,
|
||||
mLastData, (index)*MotionEvent.NUM_SAMPLE_DATA,
|
||||
(lastNumPointers-index-1)*MotionEvent.NUM_SAMPLE_DATA);
|
||||
mLastNumPointers--;
|
||||
}
|
||||
}
|
||||
|
||||
MotionEvent generateAbsMotion(InputDevice device, long curTime,
|
||||
long curTimeNano, Display display, int orientation,
|
||||
int metaState) {
|
||||
if (!changed) {
|
||||
|
||||
if (mSkipLastPointers) {
|
||||
mSkipLastPointers = false;
|
||||
mLastNumPointers = 0;
|
||||
}
|
||||
|
||||
if (mNextNumPointers <= 0 && mLastNumPointers <= 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
float scaledX = x;
|
||||
float scaledY = y;
|
||||
float temp;
|
||||
float scaledPressure = 1.0f;
|
||||
float scaledSize = 0;
|
||||
int edgeFlags = 0;
|
||||
if (isAbs) {
|
||||
int w = display.getWidth()-1;
|
||||
int h = display.getHeight()-1;
|
||||
if (orientation == Surface.ROTATION_90
|
||||
|| orientation == Surface.ROTATION_270) {
|
||||
int tmp = w;
|
||||
w = h;
|
||||
h = tmp;
|
||||
}
|
||||
if (device.absX != null) {
|
||||
scaledX = ((scaledX-device.absX.minValue)
|
||||
/ device.absX.range) * w;
|
||||
}
|
||||
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 (scaledX == 0) {
|
||||
edgeFlags += MotionEvent.EDGE_LEFT;
|
||||
} else if (scaledX == display.getWidth() - 1.0f) {
|
||||
edgeFlags += MotionEvent.EDGE_RIGHT;
|
||||
}
|
||||
|
||||
if (scaledY == 0) {
|
||||
edgeFlags += MotionEvent.EDGE_TOP;
|
||||
} else if (scaledY == display.getHeight() - 1.0f) {
|
||||
edgeFlags += MotionEvent.EDGE_BOTTOM;
|
||||
}
|
||||
|
||||
final int lastNumPointers = mLastNumPointers;
|
||||
final int nextNumPointers = mNextNumPointers;
|
||||
if (mNextNumPointers > MAX_POINTERS) {
|
||||
Log.w("InputDevice", "Number of pointers " + mNextNumPointers
|
||||
+ " exceeded maximum of " + MAX_POINTERS);
|
||||
mNextNumPointers = MAX_POINTERS;
|
||||
}
|
||||
|
||||
int upOrDownPointer = updatePointerIdentifiers();
|
||||
|
||||
final float[] reportData = mReportData;
|
||||
final int[] rawData;
|
||||
if (KeyInputQueue.BAD_TOUCH_HACK) {
|
||||
rawData = generateAveragedData(upOrDownPointer, lastNumPointers,
|
||||
nextNumPointers);
|
||||
} else {
|
||||
scaledX *= xMoveScale;
|
||||
scaledY *= yMoveScale;
|
||||
rawData = mLastData;
|
||||
}
|
||||
|
||||
final int numPointers = mLastNumPointers;
|
||||
|
||||
if (DEBUG_POINTERS) Log.v("InputDevice", "Processing "
|
||||
+ numPointers + " pointers (going from " + lastNumPointers
|
||||
+ " to " + nextNumPointers + ")");
|
||||
|
||||
for (int i=0; i<numPointers; i++) {
|
||||
final int pos = i * MotionEvent.NUM_SAMPLE_DATA;
|
||||
reportData[pos + MotionEvent.SAMPLE_X] = rawData[pos + MotionEvent.SAMPLE_X];
|
||||
reportData[pos + MotionEvent.SAMPLE_Y] = rawData[pos + MotionEvent.SAMPLE_Y];
|
||||
reportData[pos + MotionEvent.SAMPLE_PRESSURE] = rawData[pos + MotionEvent.SAMPLE_PRESSURE];
|
||||
reportData[pos + MotionEvent.SAMPLE_SIZE] = rawData[pos + MotionEvent.SAMPLE_SIZE];
|
||||
}
|
||||
|
||||
int action;
|
||||
int edgeFlags = 0;
|
||||
if (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);
|
||||
}
|
||||
} else {
|
||||
if (numPointers == 1) {
|
||||
action = MotionEvent.ACTION_UP;
|
||||
} else {
|
||||
action = MotionEvent.ACTION_POINTER_UP
|
||||
| (upOrDownPointer << MotionEvent.ACTION_POINTER_ID_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:
|
||||
temp = scaledX;
|
||||
scaledX = scaledY;
|
||||
scaledY = -temp;
|
||||
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:
|
||||
scaledX = -scaledX;
|
||||
scaledY = -scaledY;
|
||||
}
|
||||
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:
|
||||
temp = scaledX;
|
||||
scaledX = -scaledY;
|
||||
scaledY = temp;
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
changed = false;
|
||||
if (down != lastDown) {
|
||||
int action;
|
||||
lastDown = down;
|
||||
if (down) {
|
||||
action = MotionEvent.ACTION_DOWN;
|
||||
downTime = curTime;
|
||||
} else {
|
||||
action = MotionEvent.ACTION_UP;
|
||||
// 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;
|
||||
}
|
||||
currentMove = null;
|
||||
if (!isAbs) {
|
||||
x = y = 0;
|
||||
if (reportData[MotionEvent.SAMPLE_Y] <= 0) {
|
||||
edgeFlags |= MotionEvent.EDGE_TOP;
|
||||
} else if (reportData[MotionEvent.SAMPLE_Y] >= dispH) {
|
||||
edgeFlags |= MotionEvent.EDGE_BOTTOM;
|
||||
}
|
||||
return MotionEvent.obtain(downTime, curTime, action,
|
||||
scaledX, scaledY, scaledPressure, scaledSize, metaState,
|
||||
xPrecision, yPrecision, device.id, edgeFlags);
|
||||
} else {
|
||||
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 (WindowManagerPolicy.WATCH_POINTER) {
|
||||
Log.i("KeyInputQueue", "Updating: " + currentMove);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
MotionEvent me = MotionEvent.obtain(downTime, curTime,
|
||||
MotionEvent.ACTION_MOVE, scaledX, scaledY,
|
||||
scaledPressure, scaledSize, metaState,
|
||||
xPrecision, yPrecision, device.id, edgeFlags);
|
||||
currentMove = me;
|
||||
return me;
|
||||
}
|
||||
|
||||
if (currentMove != null) {
|
||||
if (false) Log.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) {
|
||||
Log.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) 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, 1, mPointerIds, scaled, metaState,
|
||||
xPrecision, yPrecision, device.id, edgeFlags);
|
||||
if (action == MotionEvent.ACTION_MOVE) {
|
||||
currentMove = me;
|
||||
}
|
||||
return me;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user