summaryrefslogtreecommitdiffstats
path: root/core/java/android/gesture/GestureOverlayView.java
diff options
context:
space:
mode:
Diffstat (limited to 'core/java/android/gesture/GestureOverlayView.java')
-rwxr-xr-xcore/java/android/gesture/GestureOverlayView.java564
1 files changed, 363 insertions, 201 deletions
diff --git a/core/java/android/gesture/GestureOverlayView.java b/core/java/android/gesture/GestureOverlayView.java
index 64ddbbd..012c01f 100755
--- a/core/java/android/gesture/GestureOverlayView.java
+++ b/core/java/android/gesture/GestureOverlayView.java
@@ -18,51 +18,62 @@ package android.gesture;
import android.content.Context;
import android.content.res.TypedArray;
-import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Rect;
+import android.graphics.RectF;
import android.util.AttributeSet;
import android.view.MotionEvent;
-import android.view.View;
import android.view.animation.AnimationUtils;
import android.view.animation.AccelerateDecelerateInterpolator;
+import android.widget.FrameLayout;
+import android.os.SystemClock;
import com.android.internal.R;
import java.util.ArrayList;
/**
- * A (transparent) overlay for gesture input that can be placed on top of other
- * widgets.
+ * A transparent overlay for gesture input that can be placed on top of other
+ * widgets or contain other widgets.
*
+ * @attr ref android.R.styleable#GestureOverlayView_eventsInterceptionEnabled
+ * @attr ref android.R.styleable#GestureOverlayView_fadeDuration
+ * @attr ref android.R.styleable#GestureOverlayView_fadeOffset
* @attr ref android.R.styleable#GestureOverlayView_gestureStrokeWidth
+ * @attr ref android.R.styleable#GestureOverlayView_gestureStrokeAngleThreshold
+ * @attr ref android.R.styleable#GestureOverlayView_gestureStrokeLengthThreshold
+ * @attr ref android.R.styleable#GestureOverlayView_gestureStrokeSquarenessThreshold
+ * @attr ref android.R.styleable#GestureOverlayView_gestureStrokeType
* @attr ref android.R.styleable#GestureOverlayView_gestureColor
* @attr ref android.R.styleable#GestureOverlayView_uncertainGestureColor
- * @attr ref android.R.styleable#GestureOverlayView_fadeDuration
- * @attr ref android.R.styleable#GestureOverlayView_fadeOffset
*/
-public class GestureOverlayView extends View {
- private static final int TRANSPARENT_BACKGROUND = 0x00000000;
+public class GestureOverlayView extends FrameLayout {
+ public static final int GESTURE_STROKE_TYPE_SINGLE = 0;
+ public static final int GESTURE_STROKE_TYPE_MULTIPLE = 1;
+
+ private static final int FADE_ANIMATION_RATE = 16;
private static final boolean GESTURE_RENDERING_ANTIALIAS = true;
private static final boolean DITHER_FLAG = true;
- private Paint mGesturePaint;
-
- private final Paint mBitmapPaint = new Paint(Paint.DITHER_FLAG);
- private Bitmap mBitmap;
- private Canvas mBitmapCanvas;
+ private final Paint mGesturePaint = new Paint();
- private long mFadeDuration = 300;
- private long mFadeOffset = 300;
+ private long mFadeDuration = 150;
+ private long mFadeOffset = 420;
private long mFadingStart;
+ private boolean mFadingHasStarted;
- private float mGestureStroke = 12.0f;
+ private int mCurrentColor;
private int mCertainGestureColor = 0xFFFFFF00;
- private int mUncertainGestureColor = 0x3CFFFF00;
+ private int mUncertainGestureColor = 0x48FFFF00;
+ private float mGestureStrokeWidth = 12.0f;
private int mInvalidateExtraBorder = 10;
- // for rendering immediate ink feedback
+ private int mGestureStrokeType = GESTURE_STROKE_TYPE_SINGLE;
+ private float mGestureStrokeLengthThreshold = 30.0f;
+ private float mGestureStrokeSquarenessTreshold = 0.275f;
+ private float mGestureStrokeAngleThreshold = 40.0f;
+
private final Rect mInvalidRect = new Rect();
private final Path mPath = new Path();
@@ -72,41 +83,31 @@ public class GestureOverlayView extends View {
private float mCurveEndX;
private float mCurveEndY;
+ private float mTotalLength;
+ private boolean mIsGesturing = false;
+ private boolean mInterceptEvents = true;
+ private boolean mIsListeningForGestures;
+
// current gesture
- private Gesture mCurrentGesture = null;
+ private Gesture mCurrentGesture;
+ private final ArrayList<GesturePoint> mStrokeBuffer = new ArrayList<GesturePoint>(100);
// TODO: Make this a list of WeakReferences
private final ArrayList<OnGestureListener> mOnGestureListeners =
new ArrayList<OnGestureListener>();
- private final ArrayList<GesturePoint> mPointBuffer = new ArrayList<GesturePoint>(100);
+ // TODO: Make this a list of WeakReferences
+ private final ArrayList<OnGesturePerformedListener> mOnGesturePerformedListeners =
+ new ArrayList<OnGesturePerformedListener>();
+
+ private boolean mHandleGestureActions;
// fading out effect
private boolean mIsFadingOut = false;
- private float mFadingAlpha = 1;
+ private float mFadingAlpha = 1.0f;
private final AccelerateDecelerateInterpolator mInterpolator =
new AccelerateDecelerateInterpolator();
- private final Runnable mFadingOut = new Runnable() {
- public void run() {
- if (mIsFadingOut) {
- final long now = AnimationUtils.currentAnimationTimeMillis();
- final long duration = now - mFadingStart;
-
- if (duration > mFadeDuration) {
- mIsFadingOut = false;
- mPath.rewind();
- mCurrentGesture = null;
- mBitmap.eraseColor(TRANSPARENT_BACKGROUND);
- } else {
- float interpolatedTime = Math.max(0.0f,
- Math.min(1.0f, duration / (float) mFadeDuration));
- mFadingAlpha = 1.0f - mInterpolator.getInterpolation(interpolatedTime);
- postDelayed(this, 16);
- }
- invalidate();
- }
- }
- };
+ private final FadeOutRunnable mFadingOut = new FadeOutRunnable();
public GestureOverlayView(Context context) {
super(context);
@@ -123,41 +124,52 @@ public class GestureOverlayView extends View {
TypedArray a = context.obtainStyledAttributes(attrs,
R.styleable.GestureOverlayView, defStyle, 0);
- mGestureStroke = a.getFloat(R.styleable.GestureOverlayView_gestureStrokeWidth,
- mGestureStroke);
- mInvalidateExtraBorder = Math.max(1, ((int) mGestureStroke) - 1);
+ mGestureStrokeWidth = a.getFloat(R.styleable.GestureOverlayView_gestureStrokeWidth,
+ mGestureStrokeWidth);
+ mInvalidateExtraBorder = Math.max(1, ((int) mGestureStrokeWidth) - 1);
mCertainGestureColor = a.getColor(R.styleable.GestureOverlayView_gestureColor,
mCertainGestureColor);
mUncertainGestureColor = a.getColor(R.styleable.GestureOverlayView_uncertainGestureColor,
mUncertainGestureColor);
mFadeDuration = a.getInt(R.styleable.GestureOverlayView_fadeDuration, (int) mFadeDuration);
mFadeOffset = a.getInt(R.styleable.GestureOverlayView_fadeOffset, (int) mFadeOffset);
+ mGestureStrokeType = a.getInt(R.styleable.GestureOverlayView_gestureStrokeType,
+ mGestureStrokeType);
+ mGestureStrokeLengthThreshold = a.getFloat(
+ R.styleable.GestureOverlayView_gestureStrokeLengthThreshold,
+ mGestureStrokeLengthThreshold);
+ mGestureStrokeAngleThreshold = a.getFloat(
+ R.styleable.GestureOverlayView_gestureStrokeAngleThreshold,
+ mGestureStrokeAngleThreshold);
+ mGestureStrokeSquarenessTreshold = a.getFloat(
+ R.styleable.GestureOverlayView_gestureStrokeSquarenessThreshold,
+ mGestureStrokeSquarenessTreshold);
+ mInterceptEvents = a.getBoolean(R.styleable.GestureOverlayView_eventsInterceptionEnabled,
+ mInterceptEvents);
a.recycle();
init();
}
- public ArrayList<GesturePoint> getCurrentStroke() {
- return mPointBuffer;
- }
+ private void init() {
+ setWillNotDraw(false);
- public Gesture getCurrentGesture() {
- return mCurrentGesture;
+ final Paint gesturePaint = mGesturePaint;
+ gesturePaint.setAntiAlias(GESTURE_RENDERING_ANTIALIAS);
+ gesturePaint.setColor(mCertainGestureColor);
+ gesturePaint.setStyle(Paint.Style.STROKE);
+ gesturePaint.setStrokeJoin(Paint.Join.ROUND);
+ gesturePaint.setStrokeCap(Paint.Cap.ROUND);
+ gesturePaint.setStrokeWidth(mGestureStrokeWidth);
+ gesturePaint.setDither(DITHER_FLAG);
+
+ mCurrentColor = mCertainGestureColor;
+ setPaintAlpha(255);
}
- /**
- * Set Gesture color
- *
- * @param color
- */
- public void setGestureDrawingColor(int color) {
- mGesturePaint.setColor(color);
- if (mCurrentGesture != null) {
- mBitmap.eraseColor(TRANSPARENT_BACKGROUND);
- mCurrentGesture.draw(mBitmapCanvas, mGesturePaint);
- }
- invalidate();
+ public ArrayList<GesturePoint> getCurrentStroke() {
+ return mStrokeBuffer;
}
public void setGestureColor(int color) {
@@ -176,73 +188,77 @@ public class GestureOverlayView extends View {
return mCertainGestureColor;
}
- public float getGestureStroke() {
- return mGestureStroke;
+ public float getGestureStrokeWidth() {
+ return mGestureStrokeWidth;
}
- public void setGestureStroke(float gestureStroke) {
- mGestureStroke = gestureStroke;
- mInvalidateExtraBorder = Math.max(1, ((int) mGestureStroke) - 1);
- mGesturePaint.setStrokeWidth(mGestureStroke);
+ public void setGestureStrokeWidth(float gestureStrokeWidth) {
+ mGestureStrokeWidth = gestureStrokeWidth;
+ mInvalidateExtraBorder = Math.max(1, ((int) gestureStrokeWidth) - 1);
+ mGesturePaint.setStrokeWidth(gestureStrokeWidth);
}
- /**
- * Set the gesture to be shown in the view
- *
- * @param gesture
- */
- public void setCurrentGesture(Gesture gesture) {
- if (mCurrentGesture != null) {
- clear(false);
- }
+ public int getGestureStrokeType() {
+ return mGestureStrokeType;
+ }
- mCurrentGesture = gesture;
+ public void setGestureStrokeType(int gestureStrokeType) {
+ mGestureStrokeType = gestureStrokeType;
+ }
- if (gesture != null) {
- if (mBitmapCanvas != null) {
- gesture.draw(mBitmapCanvas, mGesturePaint);
- invalidate();
- }
- }
+ public float getGestureStrokeLengthThreshold() {
+ return mGestureStrokeLengthThreshold;
}
- private void init() {
- mGesturePaint = new Paint();
+ public void setGestureStrokeLengthThreshold(float gestureStrokeLengthThreshold) {
+ mGestureStrokeLengthThreshold = gestureStrokeLengthThreshold;
+ }
- final Paint gesturePaint = mGesturePaint;
- gesturePaint.setAntiAlias(GESTURE_RENDERING_ANTIALIAS);
- gesturePaint.setColor(mCertainGestureColor);
- gesturePaint.setStyle(Paint.Style.STROKE);
- gesturePaint.setStrokeJoin(Paint.Join.ROUND);
- gesturePaint.setStrokeCap(Paint.Cap.ROUND);
- gesturePaint.setStrokeWidth(mGestureStroke);
- gesturePaint.setDither(DITHER_FLAG);
+ public float getGestureStrokeSquarenessTreshold() {
+ return mGestureStrokeSquarenessTreshold;
}
- @Override
- protected void onSizeChanged(int width, int height, int oldWidth, int oldHeight) {
- super.onSizeChanged(width, height, oldWidth, oldHeight);
+ public void setGestureStrokeSquarenessTreshold(float gestureStrokeSquarenessTreshold) {
+ mGestureStrokeSquarenessTreshold = gestureStrokeSquarenessTreshold;
+ }
- if (width <= 0 || height <= 0) {
- return;
- }
+ public float getGestureStrokeAngleThreshold() {
+ return mGestureStrokeAngleThreshold;
+ }
- int targetWidth = width > oldWidth ? width : oldWidth;
- int targetHeight = height > oldHeight ? height : oldHeight;
+ public void setGestureStrokeAngleThreshold(float gestureStrokeAngleThreshold) {
+ mGestureStrokeAngleThreshold = gestureStrokeAngleThreshold;
+ }
- if (mBitmap != null) mBitmap.recycle();
+ public boolean isEventsInterceptionEnabled() {
+ return mInterceptEvents;
+ }
- mBitmap = Bitmap.createBitmap(targetWidth, targetHeight, Bitmap.Config.ARGB_8888);
- if (mBitmapCanvas != null) {
- mBitmapCanvas.setBitmap(mBitmap);
- } else {
- mBitmapCanvas = new Canvas(mBitmap);
- }
- mBitmapCanvas.drawColor(TRANSPARENT_BACKGROUND);
+ public void setEventsInterceptionEnabled(boolean enabled) {
+ mInterceptEvents = enabled;
+ }
+
+ public Gesture getGesture() {
+ return mCurrentGesture;
+ }
+ public void setGesture(Gesture gesture) {
if (mCurrentGesture != null) {
- mCurrentGesture.draw(mBitmapCanvas, mGesturePaint);
+ clear(false);
}
+
+ setCurrentColor(mCertainGestureColor);
+ mCurrentGesture = gesture;
+
+ final Path path = mCurrentGesture.toPath();
+ final RectF bounds = new RectF();
+ path.computeBounds(bounds, true);
+
+ mPath.rewind();
+ mPath.addPath(path, (getWidth() - bounds.width()) / 2.0f,
+ (getHeight() - bounds.height()) / 2.0f);
+
+ invalidate();
}
public void addOnGestureListener(OnGestureListener listener) {
@@ -257,100 +273,172 @@ public class GestureOverlayView extends View {
mOnGestureListeners.clear();
}
- @Override
- protected void onDraw(Canvas canvas) {
- super.onDraw(canvas);
+ public void addOnGesturePerformedListener(OnGesturePerformedListener listener) {
+ mOnGesturePerformedListeners.add(listener);
+ if (mOnGesturePerformedListeners.size() > 0) {
+ mHandleGestureActions = true;
+ }
+ }
+
+ public void removeOnGesturePerformedListener(OnGesturePerformedListener listener) {
+ mOnGesturePerformedListeners.remove(listener);
+ if (mOnGesturePerformedListeners.size() <= 0) {
+ mHandleGestureActions = false;
+ }
+ }
+
+ public void removeAllOnGesturePerformedListeners() {
+ mOnGesturePerformedListeners.clear();
+ mHandleGestureActions = false;
+ }
- // draw double buffer
- if (mIsFadingOut) {
- mBitmapPaint.setAlpha((int) (255 * mFadingAlpha));
- canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint);
+ public boolean isGesturing() {
+ return mIsGesturing;
+ }
+
+ private void setCurrentColor(int color) {
+ mCurrentColor = color;
+ if (mFadingHasStarted) {
+ setPaintAlpha((int) (255 * mFadingAlpha));
} else {
- mBitmapPaint.setAlpha(255);
- canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint);
+ setPaintAlpha(255);
+ }
+ invalidate();
+ }
+
+ @Override
+ public void draw(Canvas canvas) {
+ super.draw(canvas);
+
+ if (mCurrentGesture != null) {
+ canvas.drawPath(mPath, mGesturePaint);
}
+ }
+
+ private void setPaintAlpha(int alpha) {
+ alpha += alpha >> 7;
+ final int baseAlpha = mCurrentColor >>> 24;
+ final int useAlpha = baseAlpha * alpha >> 8;
+ mGesturePaint.setColor((mCurrentColor << 8 >>> 8) | (useAlpha << 24));
+ }
- // draw the current stroke
- canvas.drawPath(mPath, mGesturePaint);
+ public void clear(boolean animated) {
+ clear(animated, false);
}
- /**
- * Clear up the overlay
- *
- * @param fadeOut whether the gesture on the overlay should fade out
- * gradually or disappear immediately
- */
- public void clear(boolean fadeOut) {
- if (fadeOut) {
+ private void clear(boolean animated, boolean fireActionPerformed) {
+ setPaintAlpha(255);
+ if (animated && mCurrentGesture != null) {
mFadingAlpha = 1.0f;
mIsFadingOut = true;
+ mFadingHasStarted = false;
+ mFadingOut.fireActionPerformed = fireActionPerformed;
removeCallbacks(mFadingOut);
mFadingStart = AnimationUtils.currentAnimationTimeMillis() + mFadeOffset;
postDelayed(mFadingOut, mFadeOffset);
} else {
mPath.rewind();
mCurrentGesture = null;
- if (mBitmap != null) {
- mBitmap.eraseColor(TRANSPARENT_BACKGROUND);
- invalidate();
- }
}
}
- public void cancelFadingOut() {
+ public void cancelClearAnimation() {
+ setPaintAlpha(255);
mIsFadingOut = false;
+ mFadingHasStarted = false;
removeCallbacks(mFadingOut);
+ mPath.rewind();
+ mCurrentGesture = null;
+ }
+
+ public void cancelGesture() {
+ mIsListeningForGestures = false;
+
+ // add the stroke to the current gesture
+ mCurrentGesture.addStroke(new GestureStroke(mStrokeBuffer));
+
+ // pass the event to handlers
+ final long now = SystemClock.uptimeMillis();
+ final MotionEvent event = MotionEvent.obtain(now, now,
+ MotionEvent.ACTION_CANCEL, 0.0f, 0.0f, 0);
+
+ final ArrayList<OnGestureListener> listeners = mOnGestureListeners;
+ final int count = listeners.size();
+ for (int i = 0; i < count; i++) {
+ listeners.get(i).onGestureCancelled(this, event);
+ }
+
+ event.recycle();
+
+ clear(false);
+ mIsGesturing = false;
+ mStrokeBuffer.clear();
}
@Override
- public boolean onTouchEvent(MotionEvent event) {
- if (!isEnabled()) {
+ protected void onDetachedFromWindow() {
+ cancelClearAnimation();
+ }
+
+ @Override
+ public boolean dispatchTouchEvent(MotionEvent event) {
+ if (isEnabled()) {
+ boolean cancelDispatch = (mIsGesturing || (mCurrentGesture != null &&
+ mCurrentGesture.getStrokesCount() > 0)) && mInterceptEvents;
+ processEvent(event);
+
+ if (cancelDispatch) {
+ event.setAction(MotionEvent.ACTION_CANCEL);
+ }
+
+ super.dispatchTouchEvent(event);
return true;
}
- processEvent(event);
-
- return true;
+ return super.dispatchTouchEvent(event);
}
- public void processEvent(MotionEvent event) {
+ private boolean processEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
- Rect rect = touchStart(event);
- invalidate(rect);
- break;
+ touchStart(event);
+ invalidate();
+ return true;
case MotionEvent.ACTION_MOVE:
- rect = touchMove(event);
- if (rect != null) {
- invalidate(rect);
+ if (mIsListeningForGestures) {
+ Rect rect = touchMove(event);
+ if (rect != null) {
+ invalidate(rect);
+ }
+ return true;
}
break;
case MotionEvent.ACTION_UP:
- touchUp(event, false);
- invalidate();
+ if (mIsListeningForGestures) {
+ touchUp(event, false);
+ invalidate();
+ return true;
+ }
break;
case MotionEvent.ACTION_CANCEL:
- touchUp(event, true);
- invalidate();
- break;
+ if (mIsListeningForGestures) {
+ touchUp(event, true);
+ invalidate();
+ return true;
+ }
}
+
+ return false;
}
- private Rect touchStart(MotionEvent event) {
+ private void touchStart(MotionEvent event) {
+ mIsListeningForGestures = true;
+
// pass the event to handlers
final ArrayList<OnGestureListener> listeners = mOnGestureListeners;
final int count = listeners.size();
for (int i = 0; i < count; i++) {
- OnGestureListener listener = listeners.get(i);
- listener.onGestureStarted(this, event);
- }
-
- // if there is fading out going on, stop it.
- if (mIsFadingOut) {
- mIsFadingOut = false;
- removeCallbacks(mFadingOut);
- mBitmap.eraseColor(TRANSPARENT_BACKGROUND);
- mCurrentGesture = null;
+ listeners.get(i).onGestureStarted(this, event);
}
float x = event.getX();
@@ -359,22 +447,39 @@ public class GestureOverlayView extends View {
mX = x;
mY = y;
+ mTotalLength = 0;
+ mIsGesturing = false;
+
+ if (mGestureStrokeType == GESTURE_STROKE_TYPE_SINGLE) {
+ if (mHandleGestureActions) setCurrentColor(mUncertainGestureColor);
+ mCurrentGesture = null;
+ mPath.rewind();
+ } else if (mCurrentGesture == null || mCurrentGesture.getStrokesCount() == 0) {
+ if (mHandleGestureActions) setCurrentColor(mUncertainGestureColor);
+ }
+
+ // if there is fading out going on, stop it.
+ if (mFadingHasStarted) {
+ cancelClearAnimation();
+ } else if (mIsFadingOut) {
+ setPaintAlpha(255);
+ mIsFadingOut = false;
+ mFadingHasStarted = false;
+ removeCallbacks(mFadingOut);
+ }
+
if (mCurrentGesture == null) {
mCurrentGesture = new Gesture();
}
- mPointBuffer.add(new GesturePoint(x, y, event.getEventTime()));
-
- mPath.rewind();
+ mStrokeBuffer.add(new GesturePoint(x, y, event.getEventTime()));
mPath.moveTo(x, y);
- mInvalidRect.set((int) x - mInvalidateExtraBorder, (int) y - mInvalidateExtraBorder,
- (int) x + mInvalidateExtraBorder, (int) y + mInvalidateExtraBorder);
-
+ final int border = mInvalidateExtraBorder;
+ mInvalidRect.set((int) x - border, (int) y - border, (int) x + border, (int) y + border);
+
mCurveEndX = x;
mCurveEndY = y;
-
- return mInvalidRect;
}
private Rect touchMove(MotionEvent event) {
@@ -393,36 +498,28 @@ public class GestureOverlayView extends View {
areaToRefresh = mInvalidRect;
// start with the curve end
- areaToRefresh.set(
- (int) mCurveEndX - mInvalidateExtraBorder,
- (int) mCurveEndY - mInvalidateExtraBorder,
- (int) mCurveEndX + mInvalidateExtraBorder,
- (int) mCurveEndY + mInvalidateExtraBorder);
+ final int border = mInvalidateExtraBorder;
+ areaToRefresh.set((int) mCurveEndX - border, (int) mCurveEndY - border,
+ (int) mCurveEndX + border, (int) mCurveEndY + border);
- mCurveEndX = (x + previousX) / 2;
- mCurveEndY = (y + previousY) / 2;
+ float cX = mCurveEndX = (x + previousX) / 2;
+ float cY = mCurveEndY = (y + previousY) / 2;
- mPath.quadTo(previousX, previousY, mCurveEndX, mCurveEndY);
+ mPath.quadTo(previousX, previousY, cX, cY);
// union with the control point of the new curve
- areaToRefresh.union(
- (int) previousX - mInvalidateExtraBorder,
- (int) previousY - mInvalidateExtraBorder,
- (int) previousX + mInvalidateExtraBorder,
- (int) previousY + mInvalidateExtraBorder);
+ areaToRefresh.union((int) previousX - border, (int) previousY - border,
+ (int) previousX + border, (int) previousY + border);
// union with the end point of the new curve
- areaToRefresh.union(
- (int) mCurveEndX - mInvalidateExtraBorder,
- (int) mCurveEndY - mInvalidateExtraBorder,
- (int) mCurveEndX + mInvalidateExtraBorder,
- (int) mCurveEndY + mInvalidateExtraBorder);
+ areaToRefresh.union((int) cX - border, (int) cY - border,
+ (int) cX + border, (int) cY + border);
mX = x;
mY = y;
}
- mPointBuffer.add(new GesturePoint(x, y, event.getEventTime()));
+ mStrokeBuffer.add(new GesturePoint(x, y, event.getEventTime()));
// pass the event to handlers
final ArrayList<OnGestureListener> listeners = mOnGestureListeners;
@@ -430,24 +527,48 @@ public class GestureOverlayView extends View {
for (int i = 0; i < count; i++) {
listeners.get(i).onGesture(this, event);
}
-
+
+ if (mHandleGestureActions && !mIsGesturing) {
+ mTotalLength += (float) Math.sqrt(dx * dx + dy * dy);
+
+ if (mTotalLength > mGestureStrokeLengthThreshold) {
+ final OrientedBoundingBox box =
+ GestureUtilities.computeOrientedBoundingBox(mStrokeBuffer);
+
+ float angle = Math.abs(box.orientation);
+ if (angle > 90) {
+ angle = 180 - angle;
+ }
+
+ if (box.squareness > mGestureStrokeSquarenessTreshold ||
+ angle < mGestureStrokeAngleThreshold) {
+
+ mIsGesturing = true;
+ setCurrentColor(mCertainGestureColor);
+ }
+ }
+ }
+
return areaToRefresh;
}
private void touchUp(MotionEvent event, boolean cancel) {
- // add the stroke to the current gesture
- mCurrentGesture.addStroke(new GestureStroke(mPointBuffer));
+ mIsListeningForGestures = false;
- // add the stroke to the double buffer
- mBitmapCanvas.drawPath(mPath, mGesturePaint);
+ // add the stroke to the current gesture
+ mCurrentGesture.addStroke(new GestureStroke(mStrokeBuffer));
if (!cancel) {
// pass the event to handlers
final ArrayList<OnGestureListener> listeners = mOnGestureListeners;
- final int count = listeners.size();
+ int count = listeners.size();
for (int i = 0; i < count; i++) {
listeners.get(i).onGestureEnded(this, event);
}
+
+ if (mHandleGestureActions) {
+ clear(true, mIsGesturing);
+ }
} else {
// pass the event to handlers
final ArrayList<OnGestureListener> listeners = mOnGestureListeners;
@@ -455,15 +576,52 @@ public class GestureOverlayView extends View {
for (int i = 0; i < count; i++) {
listeners.get(i).onGestureCancelled(this, event);
}
+
+ clear(false);
}
- mPath.rewind();
- mPointBuffer.clear();
+ mIsGesturing = false;
+ mStrokeBuffer.clear();
+ }
+
+ private class FadeOutRunnable implements Runnable {
+ boolean fireActionPerformed;
+
+ public void run() {
+ if (mIsFadingOut) {
+ final long now = AnimationUtils.currentAnimationTimeMillis();
+ final long duration = now - mFadingStart;
+
+ if (duration > mFadeDuration) {
+ if (fireActionPerformed) {
+ final ArrayList<OnGesturePerformedListener> actionListeners =
+ mOnGesturePerformedListeners;
+ final int count = actionListeners.size();
+ for (int i = 0; i < count; i++) {
+ actionListeners.get(i).onGesturePerformed(GestureOverlayView.this,
+ mCurrentGesture);
+ }
+ }
+
+ mIsFadingOut = false;
+ mFadingHasStarted = false;
+ mPath.rewind();
+ mCurrentGesture = null;
+ setPaintAlpha(255);
+ } else {
+ mFadingHasStarted = true;
+ float interpolatedTime = Math.max(0.0f,
+ Math.min(1.0f, duration / (float) mFadeDuration));
+ mFadingAlpha = 1.0f - mInterpolator.getInterpolation(interpolatedTime);
+ setPaintAlpha((int) (255 * mFadingAlpha));
+ postDelayed(this, FADE_ANIMATION_RATE);
+ }
+
+ invalidate();
+ }
+ }
}
- /**
- * An interface for processing gesture events
- */
public static interface OnGestureListener {
void onGestureStarted(GestureOverlayView overlay, MotionEvent event);
@@ -473,4 +631,8 @@ public class GestureOverlayView extends View {
void onGestureCancelled(GestureOverlayView overlay, MotionEvent event);
}
+
+ public static interface OnGesturePerformedListener {
+ void onGesturePerformed(GestureOverlayView overlay, Gesture gesture);
+ }
}