summaryrefslogtreecommitdiffstats
path: root/services/java
diff options
context:
space:
mode:
Diffstat (limited to 'services/java')
-rw-r--r--services/java/com/android/server/InputDevice.java199
-rw-r--r--services/java/com/android/server/KeyInputQueue.java61
2 files changed, 232 insertions, 28 deletions
diff --git a/services/java/com/android/server/InputDevice.java b/services/java/com/android/server/InputDevice.java
index e1bce73..2dc45b5 100644
--- a/services/java/com/android/server/InputDevice.java
+++ b/services/java/com/android/server/InputDevice.java
@@ -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;
diff --git a/services/java/com/android/server/KeyInputQueue.java b/services/java/com/android/server/KeyInputQueue.java
index 35ed448..09591f4 100644
--- a/services/java/com/android/server/KeyInputQueue.java
+++ b/services/java/com/android/server/KeyInputQueue.java
@@ -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();