diff options
author | Adam Powell <adamp@google.com> | 2012-10-02 16:25:30 -0700 |
---|---|---|
committer | Adam Powell <adamp@google.com> | 2012-10-02 19:07:16 -0700 |
commit | 5b5c414e31c4a8433a3290b931687a05dadc97b6 (patch) | |
tree | a9054f26592dffe58bd4a5f0b2cc86a4e4ab88cb | |
parent | 57e6203457cedbc6f4bf8a45635862a3eb717e9f (diff) | |
download | frameworks_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.java | 157 |
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; } |