summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--core/java/android/view/ScaleGestureDetector.java94
-rw-r--r--core/res/res/values/config.xml5
-rw-r--r--services/java/com/android/server/InputDevice.java165
-rw-r--r--services/java/com/android/server/KeyInputQueue.java16
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);