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 long getTimeDelta();
|
||||||
method public boolean isInProgress();
|
method public boolean isInProgress();
|
||||||
method public boolean onTouchEvent(android.view.MotionEvent);
|
method public boolean onTouchEvent(android.view.MotionEvent);
|
||||||
|
method public void setQuickScaleEnabled(boolean);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static abstract interface ScaleGestureDetector.OnScaleGestureListener {
|
public static abstract interface ScaleGestureDetector.OnScaleGestureListener {
|
||||||
|
|||||||
@@ -18,6 +18,8 @@ package android.view;
|
|||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.res.Resources;
|
import android.content.res.Resources;
|
||||||
|
import android.os.Build;
|
||||||
|
import android.os.Handler;
|
||||||
import android.os.SystemClock;
|
import android.os.SystemClock;
|
||||||
import android.util.FloatMath;
|
import android.util.FloatMath;
|
||||||
|
|
||||||
@@ -128,6 +130,8 @@ public class ScaleGestureDetector {
|
|||||||
private float mFocusX;
|
private float mFocusX;
|
||||||
private float mFocusY;
|
private float mFocusY;
|
||||||
|
|
||||||
|
private boolean mDoubleTapScales;
|
||||||
|
|
||||||
private float mCurrSpan;
|
private float mCurrSpan;
|
||||||
private float mPrevSpan;
|
private float mPrevSpan;
|
||||||
private float mInitialSpan;
|
private float mInitialSpan;
|
||||||
@@ -148,9 +152,14 @@ public class ScaleGestureDetector {
|
|||||||
private int mTouchHistoryDirection;
|
private int mTouchHistoryDirection;
|
||||||
private long mTouchHistoryLastAcceptedTime;
|
private long mTouchHistoryLastAcceptedTime;
|
||||||
private int mTouchMinMajor;
|
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 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.
|
* Consistency verifier for debugging purposes.
|
||||||
@@ -158,8 +167,37 @@ public class ScaleGestureDetector {
|
|||||||
private final InputEventConsistencyVerifier mInputEventConsistencyVerifier =
|
private final InputEventConsistencyVerifier mInputEventConsistencyVerifier =
|
||||||
InputEventConsistencyVerifier.isInstrumentationEnabled() ?
|
InputEventConsistencyVerifier.isInstrumentationEnabled() ?
|
||||||
new InputEventConsistencyVerifier(this, 0) : null;
|
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) {
|
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;
|
mContext = context;
|
||||||
mListener = listener;
|
mListener = listener;
|
||||||
mSpanSlop = ViewConfiguration.get(context).getScaledTouchSlop() * 2;
|
mSpanSlop = ViewConfiguration.get(context).getScaledTouchSlop() * 2;
|
||||||
@@ -167,8 +205,12 @@ public class ScaleGestureDetector {
|
|||||||
final Resources res = context.getResources();
|
final Resources res = context.getResources();
|
||||||
mTouchMinMajor = res.getDimensionPixelSize(
|
mTouchMinMajor = res.getDimensionPixelSize(
|
||||||
com.android.internal.R.dimen.config_minScalingTouchMajor);
|
com.android.internal.R.dimen.config_minScalingTouchMajor);
|
||||||
mMinSpan = res.getDimensionPixelSize(
|
mMinSpan = res.getDimensionPixelSize(com.android.internal.R.dimen.config_minScalingSpan);
|
||||||
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();
|
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 ||
|
final boolean streamComplete = action == MotionEvent.ACTION_UP ||
|
||||||
action == MotionEvent.ACTION_CANCEL;
|
action == MotionEvent.ACTION_CANCEL;
|
||||||
|
|
||||||
if (action == MotionEvent.ACTION_DOWN || streamComplete) {
|
if (action == MotionEvent.ACTION_DOWN || streamComplete) {
|
||||||
// Reset any scale in progress with the listener.
|
// Reset any scale in progress with the listener.
|
||||||
// If it's an ACTION_DOWN we're beginning a new event stream.
|
// If it's an ACTION_DOWN we're beginning a new event stream.
|
||||||
@@ -273,6 +321,7 @@ public class ScaleGestureDetector {
|
|||||||
mListener.onScaleEnd(this);
|
mListener.onScaleEnd(this);
|
||||||
mInProgress = false;
|
mInProgress = false;
|
||||||
mInitialSpan = 0;
|
mInitialSpan = 0;
|
||||||
|
mDoubleTapMode = DOUBLE_TAP_MODE_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (streamComplete) {
|
if (streamComplete) {
|
||||||
@@ -284,21 +333,37 @@ public class ScaleGestureDetector {
|
|||||||
final boolean configChanged = action == MotionEvent.ACTION_DOWN ||
|
final boolean configChanged = action == MotionEvent.ACTION_DOWN ||
|
||||||
action == MotionEvent.ACTION_POINTER_UP ||
|
action == MotionEvent.ACTION_POINTER_UP ||
|
||||||
action == MotionEvent.ACTION_POINTER_DOWN;
|
action == MotionEvent.ACTION_POINTER_DOWN;
|
||||||
|
|
||||||
|
|
||||||
final boolean pointerUp = action == MotionEvent.ACTION_POINTER_UP;
|
final boolean pointerUp = action == MotionEvent.ACTION_POINTER_UP;
|
||||||
final int skipIndex = pointerUp ? event.getActionIndex() : -1;
|
final int skipIndex = pointerUp ? event.getActionIndex() : -1;
|
||||||
|
|
||||||
// Determine focal point
|
// Determine focal point
|
||||||
float sumX = 0, sumY = 0;
|
float sumX = 0, sumY = 0;
|
||||||
final int count = event.getPointerCount();
|
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 int div = pointerUp ? count - 1 : count;
|
||||||
final float focusX = sumX / div;
|
final float focusX;
|
||||||
final float focusY = sumY / div;
|
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);
|
addTouchHistory(event);
|
||||||
|
|
||||||
@@ -320,7 +385,12 @@ public class ScaleGestureDetector {
|
|||||||
// the focal point.
|
// the focal point.
|
||||||
final float spanX = devX * 2;
|
final float spanX = devX * 2;
|
||||||
final float spanY = devY * 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.
|
// Dispatch begin/end events as needed.
|
||||||
// If the configuration changes, notify the app to reset its current state by beginning
|
// 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;
|
final boolean wasInProgress = mInProgress;
|
||||||
mFocusX = focusX;
|
mFocusX = focusX;
|
||||||
mFocusY = focusY;
|
mFocusY = focusY;
|
||||||
if (mInProgress && (span < mMinSpan || configChanged)) {
|
if (!inDoubleTapMode() && mInProgress && (span < mMinSpan || configChanged)) {
|
||||||
mListener.onScaleEnd(this);
|
mListener.onScaleEnd(this);
|
||||||
mInProgress = false;
|
mInProgress = false;
|
||||||
mInitialSpan = span;
|
mInitialSpan = span;
|
||||||
|
mDoubleTapMode = DOUBLE_TAP_MODE_NONE;
|
||||||
}
|
}
|
||||||
if (configChanged) {
|
if (configChanged) {
|
||||||
mPrevSpanX = mCurrSpanX = spanX;
|
mPrevSpanX = mCurrSpanX = spanX;
|
||||||
@@ -354,6 +425,7 @@ public class ScaleGestureDetector {
|
|||||||
mCurrSpan = span;
|
mCurrSpan = span;
|
||||||
|
|
||||||
boolean updatePrev = true;
|
boolean updatePrev = true;
|
||||||
|
|
||||||
if (mInProgress) {
|
if (mInProgress) {
|
||||||
updatePrev = mListener.onScale(this);
|
updatePrev = mListener.onScale(this);
|
||||||
}
|
}
|
||||||
@@ -369,6 +441,34 @@ public class ScaleGestureDetector {
|
|||||||
return true;
|
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.
|
* Returns {@code true} if a scale gesture is in progress.
|
||||||
*/
|
*/
|
||||||
@@ -472,6 +572,12 @@ public class ScaleGestureDetector {
|
|||||||
* @return The current scaling factor.
|
* @return The current scaling factor.
|
||||||
*/
|
*/
|
||||||
public float getScaleFactor() {
|
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;
|
return mPrevSpan > 0 ? mCurrSpan / mPrevSpan : 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -493,4 +599,4 @@ public class ScaleGestureDetector {
|
|||||||
public long getEventTime() {
|
public long getEventTime() {
|
||||||
return mCurrTime;
|
return mCurrTime;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user