am 2a21a77d: Merge change I1369e9ab into eclair

Merge commit '2a21a77d5cf481b129a7cb4e3e00424e4d300e6d' into eclair-mr2

* commit '2a21a77d5cf481b129a7cb4e3e00424e4d300e6d':
  Work on issue #2144454: Inconsistent swipes...
This commit is contained in:
Dianne Hackborn
2009-10-13 11:52:34 -07:00
committed by Android Git Automerger
2 changed files with 232 additions and 28 deletions

View File

@@ -24,6 +24,7 @@ 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;
@@ -76,6 +77,19 @@ public class InputDevice {
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];
@@ -98,6 +112,183 @@ public class InputDevice {
}
}
/**
* 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];
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];
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;
@@ -333,7 +524,13 @@ public class InputDevice {
int upOrDownPointer = updatePointerIdentifiers();
final float[] reportData = mReportData;
final int[] rawData = mLastData;
final int[] rawData;
if (KeyInputQueue.BAD_TOUCH_HACK) {
rawData = generateAveragedData(upOrDownPointer, lastNumPointers,
nextNumPointers);
} else {
rawData = mLastData;
}
final int numPointers = mLastNumPointers;

View File

@@ -52,6 +52,12 @@ public abstract class KeyInputQueue {
static final boolean DEBUG_VIRTUAL_KEYS = false;
static final boolean DEBUG_POINTERS = false;
/**
* Turn on some hacks we have to improve the touch interaction with a
* certain device whose screen currently is not all that good.
*/
static final boolean BAD_TOUCH_HACK = true;
private static final String EXCLUDED_DEVICES_PATH = "etc/excluded-input-devices.xml";
final SparseArray<InputDevice> mDevices = new SparseArray<InputDevice>();
@@ -540,19 +546,17 @@ public abstract class KeyInputQueue {
keycode, 0, scancode,
((ev.flags & WindowManagerPolicy.FLAG_WOKE_HERE) != 0)
? KeyEvent.FLAG_WOKE_HERE : 0));
} else if (ev.type == RawInputEvent.EV_KEY) {
// Single touch protocol: touch going down or up.
if (ev.scancode == RawInputEvent.BTN_TOUCH &&
(classes&(RawInputEvent.CLASS_TOUCHSCREEN
|RawInputEvent.CLASS_TOUCHSCREEN_MT))
== RawInputEvent.CLASS_TOUCHSCREEN) {
di.mAbs.changed = true;
di.mAbs.mDown[0] = ev.value != 0;
} else if (ev.scancode == RawInputEvent.BTN_2 &&
(classes&(RawInputEvent.CLASS_TOUCHSCREEN
|RawInputEvent.CLASS_TOUCHSCREEN_MT))
== RawInputEvent.CLASS_TOUCHSCREEN) {
di.mAbs.changed = true;
di.mAbs.mDown[1] = ev.value != 0;
// Trackball (mouse) protocol: press down or up.
} else if (ev.scancode == RawInputEvent.BTN_MOUSE &&
(classes&RawInputEvent.CLASS_TRACKBALL) != 0) {
di.mRel.changed = true;
@@ -560,6 +564,7 @@ public abstract class KeyInputQueue {
send = true;
}
// Process position events from multitouch protocol.
} else if (ev.type == RawInputEvent.EV_ABS &&
(classes&RawInputEvent.CLASS_TOUCHSCREEN_MT) != 0) {
if (ev.scancode == RawInputEvent.ABS_MT_TOUCH_MAJOR) {
@@ -585,10 +590,10 @@ public abstract class KeyInputQueue {
di.mAbs.mNextData[di.mAbs.mAddingPointerOffset
+ MotionEvent.SAMPLE_SIZE] = ev.value;
}
// Process position events from single touch protocol.
} 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.curTouchVals[MotionEvent.SAMPLE_X] = ev.value;
@@ -605,18 +610,9 @@ public abstract class KeyInputQueue {
di.curTouchVals[MotionEvent.SAMPLE_SIZE] = ev.value;
di.curTouchVals[MotionEvent.NUM_SAMPLE_DATA
+ MotionEvent.SAMPLE_SIZE] = ev.value;
// Finger 2
} else if (ev.scancode == RawInputEvent.ABS_HAT0X) {
di.mAbs.changed = true;
di.curTouchVals[MotionEvent.NUM_SAMPLE_DATA
+ MotionEvent.SAMPLE_X] = ev.value;
} else if (ev.scancode == RawInputEvent.ABS_HAT0Y) {
di.mAbs.changed = true;
di.curTouchVals[MotionEvent.NUM_SAMPLE_DATA
+ MotionEvent.SAMPLE_Y] = ev.value;
}
// Process movement events from trackball (mouse) protocol.
} else if (ev.type == RawInputEvent.EV_REL &&
(classes&RawInputEvent.CLASS_TRACKBALL) != 0) {
// Add this relative movement into our totals.
@@ -629,6 +625,9 @@ public abstract class KeyInputQueue {
}
}
// Handle multitouch protocol sync: tells us that the
// driver has returned all data for -one- of the pointers
// that is currently down.
if (ev.type == RawInputEvent.EV_SYN
&& ev.scancode == RawInputEvent.SYN_MT_REPORT
&& di.mAbs != null) {
@@ -654,6 +653,9 @@ public abstract class KeyInputQueue {
if (DEBUG_POINTERS) Log.v(TAG, "MT_REPORT: no pointer");
}
}
// Handle general event sync: all data for the current
// event update has been delivered.
} else if (send || (ev.type == RawInputEvent.EV_SYN
&& ev.scancode == RawInputEvent.SYN_REPORT)) {
if (mDisplay != null) {
@@ -677,15 +679,10 @@ public abstract class KeyInputQueue {
MotionEvent.NUM_SAMPLE_DATA);
ms.mNextNumPointers++;
}
if (ms.mDown[1]) {
System.arraycopy(di.curTouchVals,
MotionEvent.NUM_SAMPLE_DATA,
ms.mNextData,
ms.mNextNumPointers
* MotionEvent.NUM_SAMPLE_DATA,
MotionEvent.NUM_SAMPLE_DATA);
ms.mNextNumPointers++;
}
}
if (BAD_TOUCH_HACK) {
ms.dropBadPoint(di);
}
boolean doMotion = !monitorVirtualKey(di,
@@ -719,6 +716,16 @@ public abstract class KeyInputQueue {
RawInputEvent.CLASS_TOUCHSCREEN, me);
}
} while (ms.hasMore());
} else {
// We are consuming movement in the
// virtual key area... but still
// propagate this to the previous
// data for comparisons.
System.arraycopy(ms.mNextData, 0,
ms.mLastData, 0,
ms.mNextNumPointers
* MotionEvent.NUM_SAMPLE_DATA);
ms.mLastNumPointers = ms.mNextNumPointers;
}
ms.finish();