am d27f1cd3: Merge "Further refine touchMajor processing in ScaleGestureDetector" into jb-mr1-dev

* commit 'd27f1cd30b140f042e11032e4aa4381756e2998f':
  Further refine touchMajor processing in ScaleGestureDetector
This commit is contained in:
Adam Powell
2012-10-02 19:35:04 -07:00
committed by Android Git Automerger

View File

@@ -19,9 +19,6 @@ package android.view;
import android.content.Context; import android.content.Context;
import android.os.SystemClock; import android.os.SystemClock;
import android.util.FloatMath; import android.util.FloatMath;
import android.util.Log;
import java.util.Arrays;
/** /**
* Detects scaling transformation gestures using the supplied {@link MotionEvent}s. * Detects scaling transformation gestures using the supplied {@link MotionEvent}s.
@@ -143,11 +140,16 @@ public class ScaleGestureDetector {
private int mSpanSlop; private int mSpanSlop;
private int mMinSpan; private int mMinSpan;
private float[] mTouchHistoryLastAccepted; // Bounds for recently seen values
private int[] mTouchHistoryDirection; private float mTouchUpper;
private long[] mTouchHistoryLastAcceptedTime; 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 long TOUCH_STABILIZE_TIME = 128; // ms
private static final int TOUCH_MIN_MAJOR = 48; // dp
/** /**
* Consistency verifier for debugging purposes. * Consistency verifier for debugging purposes.
@@ -160,6 +162,8 @@ public class ScaleGestureDetector {
mContext = context; mContext = context;
mListener = listener; mListener = listener;
mSpanSlop = ViewConfiguration.get(context).getScaledTouchSlop() * 2; mSpanSlop = ViewConfiguration.get(context).getScaledTouchSlop() * 2;
mTouchMinMajor =
(int) (context.getResources().getDisplayMetrics().density * TOUCH_MIN_MAJOR + 0.5f);
mMinSpan = context.getResources().getDimensionPixelSize( mMinSpan = context.getResources().getDimensionPixelSize(
com.android.internal.R.dimen.config_minScalingSpan); com.android.internal.R.dimen.config_minScalingSpan);
} }
@@ -172,81 +176,55 @@ public class ScaleGestureDetector {
private void addTouchHistory(MotionEvent ev) { private void addTouchHistory(MotionEvent ev) {
final long currentTime = SystemClock.uptimeMillis(); final long currentTime = SystemClock.uptimeMillis();
final int count = ev.getPointerCount(); 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++) { for (int i = 0; i < count; i++) {
final int id = ev.getPointerId(i); final boolean hasLastAccepted = !Float.isNaN(mTouchHistoryLastAccepted);
ensureTouchHistorySize(id);
final boolean hasLastAccepted = !Float.isNaN(mTouchHistoryLastAccepted[id]);
boolean accept = true;
final int historySize = ev.getHistorySize(); final int historySize = ev.getHistorySize();
for (int h = 0; h < historySize + 1; h++) { final int pointerSampleCount = historySize + 1;
final float major; for (int h = 0; h < pointerSampleCount; h++) {
final float minor; float major;
if (h < historySize) { if (h < historySize) {
major = ev.getHistoricalTouchMajor(i, h); major = ev.getHistoricalTouchMajor(i, h);
minor = ev.getHistoricalTouchMinor(i, h);
} else { } else {
major = ev.getTouchMajor(i); 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) { if (hasLastAccepted) {
final int directionSig = (int) Math.signum(avg - mTouchHistoryLastAccepted[id]); final int directionSig = (int) Math.signum(major - mTouchHistoryLastAccepted);
if (directionSig != mTouchHistoryDirection[id] || if (directionSig != mTouchHistoryDirection ||
(directionSig == 0 && mTouchHistoryDirection[id] == 0)) { (directionSig == 0 && mTouchHistoryDirection == 0)) {
mTouchHistoryDirection[id] = directionSig; mTouchHistoryDirection = directionSig;
final long time = h < historySize ? ev.getHistoricalEventTime(h) final long time = h < historySize ? ev.getHistoricalEventTime(h)
: ev.getEventTime(); : ev.getEventTime();
mTouchHistoryLastAcceptedTime[id] = time; mTouchHistoryLastAcceptedTime = time;
accept = false;
}
if (currentTime - mTouchHistoryLastAcceptedTime[id] < TOUCH_STABILIZE_TIME) {
accept = false; accept = false;
} }
} }
} }
sampleCount += pointerSampleCount;
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();
}
} }
}
/** final float avg = total / sampleCount;
* 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;
}
/** if (accept) {
* Get the adjusted combined touchMajor/touchMinor value for a given pointer id float newAccepted = (mTouchUpper + mTouchLower + avg) / 3;
* @param id the pointer id of the data to obtain mTouchUpper = (mTouchUpper + newAccepted) / 2;
* @return the adjusted major/minor value for the point at id mTouchLower = (mTouchLower + newAccepted) / 2;
* @see #addTouchHistory(MotionEvent) mTouchHistoryLastAccepted = newAccepted;
*/ mTouchHistoryDirection = 0;
private float getAdjustedTouchHistory(int id) { mTouchHistoryLastAcceptedTime = ev.getEventTime();
if (id >= mTouchHistoryLastAccepted.length) {
Log.e(TAG, "Error retrieving adjusted touch history for id=" + id +
" - incomplete event stream?");
return 0;
} }
return mTouchHistoryLastAccepted[id];
} }
/** /**
@@ -254,41 +232,11 @@ public class ScaleGestureDetector {
* @see #addTouchHistory(MotionEvent) * @see #addTouchHistory(MotionEvent)
*/ */
private void clearTouchHistory() { private void clearTouchHistory() {
if (mTouchHistoryLastAccepted == null) { mTouchUpper = Float.NaN;
// All three arrays will be null if this is the case; nothing to do. mTouchLower = Float.NaN;
return; mTouchHistoryLastAccepted = Float.NaN;
} mTouchHistoryDirection = 0;
Arrays.fill(mTouchHistoryLastAccepted, Float.NaN); mTouchHistoryLastAcceptedTime = 0;
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;
}
} }
/** /**
@@ -346,23 +294,16 @@ public class ScaleGestureDetector {
final float focusX = sumX / div; final float focusX = sumX / div;
final float focusY = sumY / div; final float focusY = sumY / div;
if (pointerUp) {
final int id = event.getPointerId(event.getActionIndex()); addTouchHistory(event);
if (!removeTouchHistoryForId(id)) {
Log.e(TAG, "Got ACTION_POINTER_UP for previously unknown id=" + id +
" - incomplete event stream?");
}
} else {
addTouchHistory(event);
}
// Determine average deviation from focal point // Determine average deviation from focal point
float devSumX = 0, devSumY = 0; float devSumX = 0, devSumY = 0;
for (int i = 0; i < count; i++) { for (int i = 0; i < count; i++) {
if (skipIndex == i) continue; if (skipIndex == i) continue;
// Average touch major and touch minor and convert the resulting diameter into a radius. // Convert the resulting diameter into a radius.
final float touchSize = getAdjustedTouchHistory(event.getPointerId(i)) / 2; final float touchSize = mTouchHistoryLastAccepted / 2;
devSumX += Math.abs(event.getX(i) - focusX) + touchSize; devSumX += Math.abs(event.getX(i) - focusX) + touchSize;
devSumY += Math.abs(event.getY(i) - focusY) + touchSize; devSumY += Math.abs(event.getY(i) - focusY) + touchSize;
} }