am 510caf30: Merge "Add doubletap swipe to scalegesturedetector" into klp-dev
* commit '510caf30d2f7b240ee0cb470f52299af8576ea8d': Add doubletap swipe to scalegesturedetector
This commit is contained in:
@@ -27175,6 +27175,7 @@ package android.view {
|
||||
method public long getTimeDelta();
|
||||
method public boolean isInProgress();
|
||||
method public boolean onTouchEvent(android.view.MotionEvent);
|
||||
method public void setQuickScaleEnabled(boolean);
|
||||
}
|
||||
|
||||
public static abstract interface ScaleGestureDetector.OnScaleGestureListener {
|
||||
|
||||
@@ -18,6 +18,8 @@ package android.view;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
import android.os.Build;
|
||||
import android.os.Handler;
|
||||
import android.os.SystemClock;
|
||||
import android.util.FloatMath;
|
||||
|
||||
@@ -128,6 +130,8 @@ public class ScaleGestureDetector {
|
||||
private float mFocusX;
|
||||
private float mFocusY;
|
||||
|
||||
private boolean mDoubleTapScales;
|
||||
|
||||
private float mCurrSpan;
|
||||
private float mPrevSpan;
|
||||
private float mInitialSpan;
|
||||
@@ -148,9 +152,14 @@ public class ScaleGestureDetector {
|
||||
private int mTouchHistoryDirection;
|
||||
private long mTouchHistoryLastAcceptedTime;
|
||||
private int mTouchMinMajor;
|
||||
private MotionEvent mDoubleTapEvent;
|
||||
private int mDoubleTapMode = DOUBLE_TAP_MODE_NONE;
|
||||
private final Handler mHandler;
|
||||
|
||||
private static final long TOUCH_STABILIZE_TIME = 128; // ms
|
||||
private static final int TOUCH_MIN_MAJOR = 48; // dp
|
||||
private static final int DOUBLE_TAP_MODE_NONE = 0;
|
||||
private static final int DOUBLE_TAP_MODE_IN_PROGRESS = 1;
|
||||
|
||||
|
||||
/**
|
||||
* Consistency verifier for debugging purposes.
|
||||
@@ -158,8 +167,37 @@ public class ScaleGestureDetector {
|
||||
private final InputEventConsistencyVerifier mInputEventConsistencyVerifier =
|
||||
InputEventConsistencyVerifier.isInstrumentationEnabled() ?
|
||||
new InputEventConsistencyVerifier(this, 0) : null;
|
||||
private GestureDetector mGestureDetector;
|
||||
|
||||
private boolean mEventBeforeOrAboveStartingGestureEvent;
|
||||
|
||||
/**
|
||||
* Creates a ScaleGestureDetector with the supplied listener.
|
||||
* You may only use this constructor from a {@link android.os.Looper Looper} thread.
|
||||
*
|
||||
* @param context the application's context
|
||||
* @param listener the listener invoked for all the callbacks, this must
|
||||
* not be null.
|
||||
*
|
||||
* @throws NullPointerException if {@code listener} is null.
|
||||
*/
|
||||
public ScaleGestureDetector(Context context, OnScaleGestureListener listener) {
|
||||
this(context, listener, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a ScaleGestureDetector with the supplied listener.
|
||||
* @see android.os.Handler#Handler()
|
||||
*
|
||||
* @param context the application's context
|
||||
* @param listener the listener invoked for all the callbacks, this must
|
||||
* not be null.
|
||||
* @param handler the handler to use for running deferred listener events.
|
||||
*
|
||||
* @throws NullPointerException if {@code listener} is null.
|
||||
*/
|
||||
public ScaleGestureDetector(Context context, OnScaleGestureListener listener,
|
||||
Handler handler) {
|
||||
mContext = context;
|
||||
mListener = listener;
|
||||
mSpanSlop = ViewConfiguration.get(context).getScaledTouchSlop() * 2;
|
||||
@@ -167,8 +205,12 @@ public class ScaleGestureDetector {
|
||||
final Resources res = context.getResources();
|
||||
mTouchMinMajor = res.getDimensionPixelSize(
|
||||
com.android.internal.R.dimen.config_minScalingTouchMajor);
|
||||
mMinSpan = res.getDimensionPixelSize(
|
||||
com.android.internal.R.dimen.config_minScalingSpan);
|
||||
mMinSpan = res.getDimensionPixelSize(com.android.internal.R.dimen.config_minScalingSpan);
|
||||
mHandler = handler;
|
||||
// Quick scale is enabled by default after JB_MR2
|
||||
if (context.getApplicationInfo().targetSdkVersion > Build.VERSION_CODES.JELLY_BEAN_MR2) {
|
||||
setQuickScaleEnabled(true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -263,8 +305,14 @@ public class ScaleGestureDetector {
|
||||
|
||||
final int action = event.getActionMasked();
|
||||
|
||||
// Forward the event to check for double tap gesture
|
||||
if (mDoubleTapScales) {
|
||||
mGestureDetector.onTouchEvent(event);
|
||||
}
|
||||
|
||||
final boolean streamComplete = action == MotionEvent.ACTION_UP ||
|
||||
action == MotionEvent.ACTION_CANCEL;
|
||||
|
||||
if (action == MotionEvent.ACTION_DOWN || streamComplete) {
|
||||
// Reset any scale in progress with the listener.
|
||||
// If it's an ACTION_DOWN we're beginning a new event stream.
|
||||
@@ -273,6 +321,7 @@ public class ScaleGestureDetector {
|
||||
mListener.onScaleEnd(this);
|
||||
mInProgress = false;
|
||||
mInitialSpan = 0;
|
||||
mDoubleTapMode = DOUBLE_TAP_MODE_NONE;
|
||||
}
|
||||
|
||||
if (streamComplete) {
|
||||
@@ -284,21 +333,37 @@ public class ScaleGestureDetector {
|
||||
final boolean configChanged = action == MotionEvent.ACTION_DOWN ||
|
||||
action == MotionEvent.ACTION_POINTER_UP ||
|
||||
action == MotionEvent.ACTION_POINTER_DOWN;
|
||||
|
||||
|
||||
final boolean pointerUp = action == MotionEvent.ACTION_POINTER_UP;
|
||||
final int skipIndex = pointerUp ? event.getActionIndex() : -1;
|
||||
|
||||
// Determine focal point
|
||||
float sumX = 0, sumY = 0;
|
||||
final int count = event.getPointerCount();
|
||||
for (int i = 0; i < count; i++) {
|
||||
if (skipIndex == i) continue;
|
||||
sumX += event.getX(i);
|
||||
sumY += event.getY(i);
|
||||
}
|
||||
final int div = pointerUp ? count - 1 : count;
|
||||
final float focusX = sumX / div;
|
||||
final float focusY = sumY / div;
|
||||
final float focusX;
|
||||
final float focusY;
|
||||
if (mDoubleTapMode == DOUBLE_TAP_MODE_IN_PROGRESS) {
|
||||
// In double tap mode, the focal pt is always where the double tap
|
||||
// gesture started
|
||||
focusX = mDoubleTapEvent.getX();
|
||||
focusY = mDoubleTapEvent.getY();
|
||||
if (event.getY() < focusY) {
|
||||
mEventBeforeOrAboveStartingGestureEvent = true;
|
||||
} else {
|
||||
mEventBeforeOrAboveStartingGestureEvent = false;
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i < count; i++) {
|
||||
if (skipIndex == i) continue;
|
||||
sumX += event.getX(i);
|
||||
sumY += event.getY(i);
|
||||
}
|
||||
|
||||
focusX = sumX / div;
|
||||
focusY = sumY / div;
|
||||
}
|
||||
|
||||
addTouchHistory(event);
|
||||
|
||||
@@ -320,7 +385,12 @@ public class ScaleGestureDetector {
|
||||
// the focal point.
|
||||
final float spanX = devX * 2;
|
||||
final float spanY = devY * 2;
|
||||
final float span = FloatMath.sqrt(spanX * spanX + spanY * spanY);
|
||||
final float span;
|
||||
if (inDoubleTapMode()) {
|
||||
span = spanY;
|
||||
} else {
|
||||
span = FloatMath.sqrt(spanX * spanX + spanY * spanY);
|
||||
}
|
||||
|
||||
// Dispatch begin/end events as needed.
|
||||
// If the configuration changes, notify the app to reset its current state by beginning
|
||||
@@ -328,10 +398,11 @@ public class ScaleGestureDetector {
|
||||
final boolean wasInProgress = mInProgress;
|
||||
mFocusX = focusX;
|
||||
mFocusY = focusY;
|
||||
if (mInProgress && (span < mMinSpan || configChanged)) {
|
||||
if (!inDoubleTapMode() && mInProgress && (span < mMinSpan || configChanged)) {
|
||||
mListener.onScaleEnd(this);
|
||||
mInProgress = false;
|
||||
mInitialSpan = span;
|
||||
mDoubleTapMode = DOUBLE_TAP_MODE_NONE;
|
||||
}
|
||||
if (configChanged) {
|
||||
mPrevSpanX = mCurrSpanX = spanX;
|
||||
@@ -354,6 +425,7 @@ public class ScaleGestureDetector {
|
||||
mCurrSpan = span;
|
||||
|
||||
boolean updatePrev = true;
|
||||
|
||||
if (mInProgress) {
|
||||
updatePrev = mListener.onScale(this);
|
||||
}
|
||||
@@ -369,6 +441,34 @@ public class ScaleGestureDetector {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
private boolean inDoubleTapMode() {
|
||||
return mDoubleTapMode == DOUBLE_TAP_MODE_IN_PROGRESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether the associated {@link OnScaleGestureListener} should receive onScale callbacks
|
||||
* when the user performs a doubleTap followed by a swipe. Note that this is enabled by default
|
||||
* if the app targets API 19 and newer.
|
||||
* @param scales true to enable quick scaling, false to disable
|
||||
*/
|
||||
public void setQuickScaleEnabled(boolean scales) {
|
||||
mDoubleTapScales = scales;
|
||||
if (mDoubleTapScales && mGestureDetector == null) {
|
||||
GestureDetector.SimpleOnGestureListener gestureListener =
|
||||
new GestureDetector.SimpleOnGestureListener() {
|
||||
@Override
|
||||
public boolean onDoubleTap(MotionEvent e) {
|
||||
// Double tap: start watching for a swipe
|
||||
mDoubleTapEvent = e;
|
||||
mDoubleTapMode = DOUBLE_TAP_MODE_IN_PROGRESS;
|
||||
return true;
|
||||
}
|
||||
};
|
||||
mGestureDetector = new GestureDetector(mContext, gestureListener, mHandler);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code true} if a scale gesture is in progress.
|
||||
*/
|
||||
@@ -472,6 +572,12 @@ public class ScaleGestureDetector {
|
||||
* @return The current scaling factor.
|
||||
*/
|
||||
public float getScaleFactor() {
|
||||
if (inDoubleTapMode() && mEventBeforeOrAboveStartingGestureEvent) {
|
||||
// Drag is moving up; the further away from the gesture
|
||||
// start, the smaller the span should be, the closer,
|
||||
// the larger the span, and therefore the larger the scale
|
||||
return (1 / mCurrSpan) / (1 / mPrevSpan);
|
||||
}
|
||||
return mPrevSpan > 0 ? mCurrSpan / mPrevSpan : 1;
|
||||
}
|
||||
|
||||
@@ -493,4 +599,4 @@ public class ScaleGestureDetector {
|
||||
public long getEventTime() {
|
||||
return mCurrTime;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user