diff options
author | Android (Google) Code Review <android-gerrit@google.com> | 2009-10-13 14:45:56 -0400 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2009-10-13 14:45:56 -0400 |
commit | 2a21a77d5cf481b129a7cb4e3e00424e4d300e6d (patch) | |
tree | 755d1d76863327b335bd1574d0ea92304e08a200 /services/java | |
parent | 16cb04ab1cd88d917fdd34a9063fe4a9707aa5b1 (diff) | |
parent | 1411d1c822664bbdaa61162f7e62137bc4865e23 (diff) | |
download | frameworks_base-2a21a77d5cf481b129a7cb4e3e00424e4d300e6d.zip frameworks_base-2a21a77d5cf481b129a7cb4e3e00424e4d300e6d.tar.gz frameworks_base-2a21a77d5cf481b129a7cb4e3e00424e4d300e6d.tar.bz2 |
Merge change I1369e9ab into eclair
* changes:
Work on issue #2144454: Inconsistent swipes...
Diffstat (limited to 'services/java')
-rw-r--r-- | services/java/com/android/server/InputDevice.java | 199 | ||||
-rw-r--r-- | services/java/com/android/server/KeyInputQueue.java | 61 |
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(); |