Merge "InputDevice filtering for jumpy screens. Updated ScaleGestureDetector for framework deprecations."
This commit is contained in:
@@ -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);
|
||||
}
|
||||
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;
|
||||
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);
|
||||
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);
|
||||
}
|
||||
}
|
||||
} 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;
|
||||
|
||||
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);
|
||||
}
|
||||
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);
|
||||
|
||||
|
||||
@@ -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 -->
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user