summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAdam Powell <adamp@google.com>2012-10-02 16:25:30 -0700
committerAdam Powell <adamp@google.com>2012-10-02 19:07:16 -0700
commit5b5c414e31c4a8433a3290b931687a05dadc97b6 (patch)
treea9054f26592dffe58bd4a5f0b2cc86a4e4ab88cb
parent57e6203457cedbc6f4bf8a45635862a3eb717e9f (diff)
downloadframeworks_base-5b5c414e31c4a8433a3290b931687a05dadc97b6.zip
frameworks_base-5b5c414e31c4a8433a3290b931687a05dadc97b6.tar.gz
frameworks_base-5b5c414e31c4a8433a3290b931687a05dadc97b6.tar.bz2
Further refine touchMajor processing in ScaleGestureDetector
On some devices the information coming from the touchscreen is very noisy or otherwise unreliable. Perform some processing on the data we have to try to provide a smoother experience. Bug 7267507 Change-Id: I863125f58577f522de05a1361b81c2e42975fd89
-rw-r--r--core/java/android/view/ScaleGestureDetector.java157
1 files changed, 49 insertions, 108 deletions
diff --git a/core/java/android/view/ScaleGestureDetector.java b/core/java/android/view/ScaleGestureDetector.java
index 4873860..a74e438 100644
--- a/core/java/android/view/ScaleGestureDetector.java
+++ b/core/java/android/view/ScaleGestureDetector.java
@@ -19,9 +19,6 @@ package android.view;
import android.content.Context;
import android.os.SystemClock;
import android.util.FloatMath;
-import android.util.Log;
-
-import java.util.Arrays;
/**
* Detects scaling transformation gestures using the supplied {@link MotionEvent}s.
@@ -143,11 +140,16 @@ public class ScaleGestureDetector {
private int mSpanSlop;
private int mMinSpan;
- private float[] mTouchHistoryLastAccepted;
- private int[] mTouchHistoryDirection;
- private long[] mTouchHistoryLastAcceptedTime;
+ // Bounds for recently seen values
+ private float mTouchUpper;
+ private float mTouchLower;
+ private float mTouchHistoryLastAccepted;
+ private int mTouchHistoryDirection;
+ private long mTouchHistoryLastAcceptedTime;
+ private int mTouchMinMajor;
private static final long TOUCH_STABILIZE_TIME = 128; // ms
+ private static final int TOUCH_MIN_MAJOR = 48; // dp
/**
* Consistency verifier for debugging purposes.
@@ -160,6 +162,8 @@ public class ScaleGestureDetector {
mContext = context;
mListener = listener;
mSpanSlop = ViewConfiguration.get(context).getScaledTouchSlop() * 2;
+ mTouchMinMajor =
+ (int) (context.getResources().getDisplayMetrics().density * TOUCH_MIN_MAJOR + 0.5f);
mMinSpan = context.getResources().getDimensionPixelSize(
com.android.internal.R.dimen.config_minScalingSpan);
}
@@ -172,81 +176,55 @@ public class ScaleGestureDetector {
private void addTouchHistory(MotionEvent ev) {
final long currentTime = SystemClock.uptimeMillis();
final int count = ev.getPointerCount();
+ boolean accept = currentTime - mTouchHistoryLastAcceptedTime >= TOUCH_STABILIZE_TIME;
+ float total = 0;
+ int sampleCount = 0;
for (int i = 0; i < count; i++) {
- final int id = ev.getPointerId(i);
- ensureTouchHistorySize(id);
-
- final boolean hasLastAccepted = !Float.isNaN(mTouchHistoryLastAccepted[id]);
- boolean accept = true;
+ final boolean hasLastAccepted = !Float.isNaN(mTouchHistoryLastAccepted);
final int historySize = ev.getHistorySize();
- for (int h = 0; h < historySize + 1; h++) {
- final float major;
- final float minor;
+ final int pointerSampleCount = historySize + 1;
+ for (int h = 0; h < pointerSampleCount; h++) {
+ float major;
if (h < historySize) {
major = ev.getHistoricalTouchMajor(i, h);
- minor = ev.getHistoricalTouchMinor(i, h);
} else {
major = ev.getTouchMajor(i);
- minor = ev.getTouchMinor(i);
}
- final float avg = (major + minor) / 2;
+ if (major < mTouchMinMajor) major = mTouchMinMajor;
+ total += major;
+
+ if (Float.isNaN(mTouchUpper) || major > mTouchUpper) {
+ mTouchUpper = major;
+ }
+ if (Float.isNaN(mTouchLower) || major < mTouchLower) {
+ mTouchLower = major;
+ }
if (hasLastAccepted) {
- final int directionSig = (int) Math.signum(avg - mTouchHistoryLastAccepted[id]);
- if (directionSig != mTouchHistoryDirection[id] ||
- (directionSig == 0 && mTouchHistoryDirection[id] == 0)) {
- mTouchHistoryDirection[id] = directionSig;
+ final int directionSig = (int) Math.signum(major - mTouchHistoryLastAccepted);
+ if (directionSig != mTouchHistoryDirection ||
+ (directionSig == 0 && mTouchHistoryDirection == 0)) {
+ mTouchHistoryDirection = directionSig;
final long time = h < historySize ? ev.getHistoricalEventTime(h)
: ev.getEventTime();
- mTouchHistoryLastAcceptedTime[id] = time;
- accept = false;
- }
- if (currentTime - mTouchHistoryLastAcceptedTime[id] < TOUCH_STABILIZE_TIME) {
+ mTouchHistoryLastAcceptedTime = time;
accept = false;
}
}
}
-
- if (accept) {
- float newAccepted = (ev.getTouchMajor(i) + ev.getTouchMinor(i)) / 2;
- if (hasLastAccepted) {
- newAccepted = (mTouchHistoryLastAccepted[id] + newAccepted) / 2;
- }
- mTouchHistoryLastAccepted[id] = newAccepted;
- mTouchHistoryDirection[id] = 0;
- mTouchHistoryLastAcceptedTime[id] = ev.getEventTime();
- }
+ sampleCount += pointerSampleCount;
}
- }
- /**
- * Clear out the touch history for a given pointer id.
- * @param id pointer id to clear
- * @see #addTouchHistory(MotionEvent)
- */
- private boolean removeTouchHistoryForId(int id) {
- if (id >= mTouchHistoryLastAccepted.length) {
- return false;
- }
- mTouchHistoryLastAccepted[id] = Float.NaN;
- mTouchHistoryDirection[id] = 0;
- mTouchHistoryLastAcceptedTime[id] = 0;
- return true;
- }
+ final float avg = total / sampleCount;
- /**
- * Get the adjusted combined touchMajor/touchMinor value for a given pointer id
- * @param id the pointer id of the data to obtain
- * @return the adjusted major/minor value for the point at id
- * @see #addTouchHistory(MotionEvent)
- */
- private float getAdjustedTouchHistory(int id) {
- if (id >= mTouchHistoryLastAccepted.length) {
- Log.e(TAG, "Error retrieving adjusted touch history for id=" + id +
- " - incomplete event stream?");
- return 0;
+ if (accept) {
+ float newAccepted = (mTouchUpper + mTouchLower + avg) / 3;
+ mTouchUpper = (mTouchUpper + newAccepted) / 2;
+ mTouchLower = (mTouchLower + newAccepted) / 2;
+ mTouchHistoryLastAccepted = newAccepted;
+ mTouchHistoryDirection = 0;
+ mTouchHistoryLastAcceptedTime = ev.getEventTime();
}
- return mTouchHistoryLastAccepted[id];
}
/**
@@ -254,41 +232,11 @@ public class ScaleGestureDetector {
* @see #addTouchHistory(MotionEvent)
*/
private void clearTouchHistory() {
- if (mTouchHistoryLastAccepted == null) {
- // All three arrays will be null if this is the case; nothing to do.
- return;
- }
- Arrays.fill(mTouchHistoryLastAccepted, Float.NaN);
- Arrays.fill(mTouchHistoryDirection, 0);
- Arrays.fill(mTouchHistoryLastAcceptedTime, 0);
- }
-
- private void ensureTouchHistorySize(int id) {
- final int requiredSize = id + 1;
- if (mTouchHistoryLastAccepted == null || mTouchHistoryLastAccepted.length < requiredSize) {
- final float[] newLastAccepted = new float[requiredSize];
- final int[] newDirection = new int[requiredSize];
- final long[] newLastAcceptedTime = new long[requiredSize];
-
- int oldLength = 0;
- if (mTouchHistoryLastAccepted != null) {
- System.arraycopy(mTouchHistoryLastAccepted, 0, newLastAccepted, 0,
- mTouchHistoryLastAccepted.length);
- System.arraycopy(mTouchHistoryDirection, 0, newDirection, 0,
- mTouchHistoryDirection.length);
- System.arraycopy(mTouchHistoryLastAcceptedTime, 0, newLastAcceptedTime, 0,
- mTouchHistoryLastAcceptedTime.length);
- oldLength = mTouchHistoryLastAccepted.length;
- }
-
- Arrays.fill(newLastAccepted, oldLength, newLastAccepted.length, Float.NaN);
- Arrays.fill(newDirection, oldLength, newDirection.length, 0);
- Arrays.fill(newLastAcceptedTime, oldLength, newLastAcceptedTime.length, 0);
-
- mTouchHistoryLastAccepted = newLastAccepted;
- mTouchHistoryDirection = newDirection;
- mTouchHistoryLastAcceptedTime = newLastAcceptedTime;
- }
+ mTouchUpper = Float.NaN;
+ mTouchLower = Float.NaN;
+ mTouchHistoryLastAccepted = Float.NaN;
+ mTouchHistoryDirection = 0;
+ mTouchHistoryLastAcceptedTime = 0;
}
/**
@@ -346,23 +294,16 @@ public class ScaleGestureDetector {
final float focusX = sumX / div;
final float focusY = sumY / div;
- if (pointerUp) {
- final int id = event.getPointerId(event.getActionIndex());
- if (!removeTouchHistoryForId(id)) {
- Log.e(TAG, "Got ACTION_POINTER_UP for previously unknown id=" + id +
- " - incomplete event stream?");
- }
- } else {
- addTouchHistory(event);
- }
+
+ addTouchHistory(event);
// Determine average deviation from focal point
float devSumX = 0, devSumY = 0;
for (int i = 0; i < count; i++) {
if (skipIndex == i) continue;
- // Average touch major and touch minor and convert the resulting diameter into a radius.
- final float touchSize = getAdjustedTouchHistory(event.getPointerId(i)) / 2;
+ // Convert the resulting diameter into a radius.
+ final float touchSize = mTouchHistoryLastAccepted / 2;
devSumX += Math.abs(event.getX(i) - focusX) + touchSize;
devSumY += Math.abs(event.getY(i) - focusY) + touchSize;
}