diff options
-rw-r--r-- | core/java/android/view/ScaleGestureDetector.java | 94 | ||||
-rw-r--r-- | core/res/res/values/config.xml | 5 | ||||
-rw-r--r-- | services/java/com/android/server/InputDevice.java | 165 | ||||
-rw-r--r-- | services/java/com/android/server/KeyInputQueue.java | 16 |
4 files changed, 234 insertions, 46 deletions
diff --git a/core/java/android/view/ScaleGestureDetector.java b/core/java/android/view/ScaleGestureDetector.java index 8140d61..d8b6d1f 100644 --- a/core/java/android/view/ScaleGestureDetector.java +++ b/core/java/android/view/ScaleGestureDetector.java @@ -154,9 +154,8 @@ public class ScaleGestureDetector { boolean handled = true; if (!mGestureInProgress) { - if ((action == MotionEvent.ACTION_POINTER_1_DOWN || - action == MotionEvent.ACTION_POINTER_2_DOWN) && - event.getPointerCount() >= 2) { + switch (action & MotionEvent.ACTION_MASK) { + case MotionEvent.ACTION_POINTER_DOWN: { // We have a new multi-finger gesture // as orientation can change, query the metrics in touch down @@ -189,7 +188,7 @@ public class ScaleGestureDetector { boolean p1sloppy = x1 < edgeSlop || y1 < edgeSlop || x1 > rightSlop || y1 > bottomSlop; - if(p0sloppy && p1sloppy) { + if (p0sloppy && p1sloppy) { mFocusX = -1; mFocusY = -1; mSloppyGesture = true; @@ -204,54 +203,61 @@ public class ScaleGestureDetector { } else { mGestureInProgress = mListener.onScaleBegin(this); } - } else if (action == MotionEvent.ACTION_MOVE && mSloppyGesture) { - // Initiate sloppy gestures if we've moved outside of the slop area. - final float edgeSlop = mEdgeSlop; - final float rightSlop = mRightSlopEdge; - final float bottomSlop = mBottomSlopEdge; - final float x0 = event.getRawX(); - final float y0 = event.getRawY(); - final float x1 = getRawX(event, 1); - final float y1 = getRawY(event, 1); - - boolean p0sloppy = x0 < edgeSlop || y0 < edgeSlop - || x0 > rightSlop || y0 > bottomSlop; - boolean p1sloppy = x1 < edgeSlop || y1 < edgeSlop - || x1 > rightSlop || y1 > bottomSlop; - - if(p0sloppy && p1sloppy) { - mFocusX = -1; - mFocusY = -1; - } else if (p0sloppy) { - mFocusX = event.getX(1); - mFocusY = event.getY(1); - } else if (p1sloppy) { - mFocusX = event.getX(0); - mFocusY = event.getY(0); - } else { - mSloppyGesture = false; - mGestureInProgress = mListener.onScaleBegin(this); + } + break; + + case MotionEvent.ACTION_MOVE: + if (mSloppyGesture) { + // Initiate sloppy gestures if we've moved outside of the slop area. + final float edgeSlop = mEdgeSlop; + final float rightSlop = mRightSlopEdge; + final float bottomSlop = mBottomSlopEdge; + final float x0 = event.getRawX(); + final float y0 = event.getRawY(); + final float x1 = getRawX(event, 1); + final float y1 = getRawY(event, 1); + + boolean p0sloppy = x0 < edgeSlop || y0 < edgeSlop + || x0 > rightSlop || y0 > bottomSlop; + boolean p1sloppy = x1 < edgeSlop || y1 < edgeSlop + || x1 > rightSlop || y1 > bottomSlop; + + if(p0sloppy && p1sloppy) { + mFocusX = -1; + mFocusY = -1; + } else if (p0sloppy) { + mFocusX = event.getX(1); + mFocusY = event.getY(1); + } else if (p1sloppy) { + mFocusX = event.getX(0); + mFocusY = event.getY(0); + } else { + mSloppyGesture = false; + mGestureInProgress = mListener.onScaleBegin(this); + } + } + break; + + case MotionEvent.ACTION_POINTER_UP: + if (mSloppyGesture) { + // Set focus point to the remaining finger + int id = (((action & MotionEvent.ACTION_POINTER_INDEX_MASK) + >> MotionEvent.ACTION_POINTER_INDEX_SHIFT) == 0) ? 1 : 0; + mFocusX = event.getX(id); + mFocusY = event.getY(id); } - } else if ((action == MotionEvent.ACTION_POINTER_1_UP - || action == MotionEvent.ACTION_POINTER_2_UP) - && mSloppyGesture) { - // Set focus point to the remaining finger - int id = (((action & MotionEvent.ACTION_POINTER_ID_MASK) - >> MotionEvent.ACTION_POINTER_ID_SHIFT) == 0) ? 1 : 0; - mFocusX = event.getX(id); - mFocusY = event.getY(id); + break; } } else { // Transform gesture in progress - attempt to handle it - switch (action) { - case MotionEvent.ACTION_POINTER_1_UP: - case MotionEvent.ACTION_POINTER_2_UP: + switch (action & MotionEvent.ACTION_MASK) { + case MotionEvent.ACTION_POINTER_UP: // Gesture ended setContext(event); // Set focus point to the remaining finger - int id = (((action & MotionEvent.ACTION_POINTER_ID_MASK) - >> MotionEvent.ACTION_POINTER_ID_SHIFT) == 0) ? 1 : 0; + int id = (((action & MotionEvent.ACTION_POINTER_INDEX_MASK) + >> MotionEvent.ACTION_POINTER_INDEX_SHIFT) == 0) ? 1 : 0; mFocusX = event.getX(id); mFocusY = event.getY(id); diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index 02961f0..84cd4c3 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -267,6 +267,11 @@ it will be removed when the lower-level touch driver generates better data. --> <bool name="config_filterTouchEvents">false</bool> + + <!-- Enables special filtering code in the framework for raw touch events + from the touch driver. This code exists for one particular device, + and should not be enabled for any others. --> + <bool name="config_filterJumpyTouchEvents">false</bool> <!-- Component name of the default wallpaper. This will be ImageWallpaper if not specified --> diff --git a/services/java/com/android/server/InputDevice.java b/services/java/com/android/server/InputDevice.java index d5e94ec..ed7eed0 100644 --- a/services/java/com/android/server/InputDevice.java +++ b/services/java/com/android/server/InputDevice.java @@ -34,6 +34,16 @@ public class InputDevice { /** Maximum number of pointers we will track and report. */ static final int MAX_POINTERS = 10; + /** + * Slop distance for jumpy pointer detection. + * This is in touchscreen coordinates, not pixels or dips. + */ + private static final int JUMPY_EPSILON = 30; + + /** 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; @@ -84,6 +94,9 @@ public class InputDevice { // 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. @@ -232,6 +245,158 @@ public class InputDevice { } } + void dropJumpyPoint(InputDevice dev) { + 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) <= JUMPY_EPSILON; + dropy = Math.abs(y - yOther) <= JUMPY_EPSILON; + } + + 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 diff --git a/services/java/com/android/server/KeyInputQueue.java b/services/java/com/android/server/KeyInputQueue.java index a08258a..8cd9578 100644 --- a/services/java/com/android/server/KeyInputQueue.java +++ b/services/java/com/android/server/KeyInputQueue.java @@ -18,6 +18,7 @@ package com.android.server; import android.content.Context; import android.content.res.Configuration; +import android.content.res.Resources; import android.os.Environment; import android.os.LatencyTimer; import android.os.PowerManager; @@ -60,6 +61,12 @@ public abstract class KeyInputQueue { */ static boolean BAD_TOUCH_HACK = false; + /** + * Turn on some hacks to improve touch interaction with another device + * where touch coordinate data can get corrupted. + */ + static boolean JUMPY_TOUCH_HACK = false; + private static final String EXCLUDED_DEVICES_PATH = "etc/excluded-input-devices.xml"; final SparseArray<InputDevice> mDevices = new SparseArray<InputDevice>(); @@ -284,8 +291,10 @@ public abstract class KeyInputQueue { lt = new LatencyTimer(100, 1000); } - BAD_TOUCH_HACK = context.getResources().getBoolean( - com.android.internal.R.bool.config_filterTouchEvents); + Resources r = context.getResources(); + BAD_TOUCH_HACK = r.getBoolean(com.android.internal.R.bool.config_filterTouchEvents); + + JUMPY_TOUCH_HACK = r.getBoolean(com.android.internal.R.bool.config_filterJumpyTouchEvents); mHapticFeedbackCallback = hapticFeedbackCallback; @@ -758,6 +767,9 @@ public abstract class KeyInputQueue { if (BAD_TOUCH_HACK) { ms.dropBadPoint(di); } + if (JUMPY_TOUCH_HACK) { + ms.dropJumpyPoint(di); + } boolean doMotion = !monitorVirtualKey(di, ev, curTime, curTimeNano); |