summaryrefslogtreecommitdiffstats
path: root/tests/sketch/src/com/android/gesture/GestureOverlay.java
diff options
context:
space:
mode:
Diffstat (limited to 'tests/sketch/src/com/android/gesture/GestureOverlay.java')
-rwxr-xr-xtests/sketch/src/com/android/gesture/GestureOverlay.java386
1 files changed, 386 insertions, 0 deletions
diff --git a/tests/sketch/src/com/android/gesture/GestureOverlay.java b/tests/sketch/src/com/android/gesture/GestureOverlay.java
new file mode 100755
index 0000000..9907831
--- /dev/null
+++ b/tests/sketch/src/com/android/gesture/GestureOverlay.java
@@ -0,0 +1,386 @@
+/*
+ * Copyright (C) 2008-2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.gesture;
+
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.BlurMaskFilter;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.Path;
+import android.graphics.Rect;
+import android.os.Handler;
+import android.util.AttributeSet;
+import android.view.MotionEvent;
+import android.view.View;
+
+import java.util.ArrayList;
+
+/**
+ * A (transparent) overlay for gesture input that can be placed on top of other
+ * widgets. The view can also be opaque.
+ */
+
+public class GestureOverlay extends View {
+
+ static final float TOUCH_TOLERANCE = 3;
+
+ private static final int TRANSPARENT_BACKGROUND = Color.argb(0, 0, 0, 0);
+
+ private static final float FADING_ALPHA_CHANGE = 0.03f;
+
+ private static final long FADING_REFRESHING_RATE = 100;
+
+ private static final int GESTURE_STROKE_WIDTH = 12;
+
+ private static final boolean GESTURE_RENDERING_ANTIALIAS = true;
+
+ private static final BlurMaskFilter BLUR_MASK_FILTER = new BlurMaskFilter(1, BlurMaskFilter.Blur.NORMAL);
+
+ private static final boolean DITHER_FLAG = true;
+
+ private static final int REFRESH_RANGE = 10;
+
+ public static final int DEFAULT_GESTURE_COLOR = Color.argb(255, 255, 255, 0);
+
+ // double buffering
+ private Paint mGesturePaint;
+
+ private Bitmap mBitmap; // with transparent background
+
+ private Canvas mBitmapCanvas;
+
+ // for rendering immediate ink feedback
+ private Rect mInvalidRect = new Rect();
+
+ private Path mPath;
+
+ private float mX;
+
+ private float mY;
+
+ private float mCurveEndX;
+
+ private float mCurveEndY;
+
+ // current gesture
+ private Gesture mCurrentGesture = null;
+
+ // gesture event handlers
+ ArrayList<GestureListener> mGestureListeners = new ArrayList<GestureListener>();
+
+ private ArrayList<GesturePoint> mPointBuffer = null;
+
+ // fading out effect
+ private boolean mIsFadingOut = false;
+
+ private float mFadingAlpha = 1;
+
+ private Handler mHandler = new Handler();
+
+ private Paint mBitmapPaint = new Paint(Paint.DITHER_FLAG);
+
+ private Runnable mFadingOut = new Runnable() {
+ public void run() {
+ if (mIsFadingOut) {
+ mFadingAlpha -= FADING_ALPHA_CHANGE;
+ if (mFadingAlpha <= 0) {
+ mIsFadingOut = false;
+ mPath = null;
+ mCurrentGesture = null;
+ mBitmap.eraseColor(TRANSPARENT_BACKGROUND);
+ } else {
+ mHandler.postDelayed(this, FADING_REFRESHING_RATE);
+ }
+ invalidate();
+ }
+ }
+ };
+
+ public GestureOverlay(Context context) {
+ super(context);
+ init();
+ }
+
+ public GestureOverlay(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ init();
+ }
+
+ public ArrayList<GesturePoint> getCurrentStroke() {
+ return mPointBuffer;
+ }
+
+ public Gesture getCurrentGesture() {
+ return mCurrentGesture;
+ }
+
+ /**
+ * Set Gesture color
+ *
+ * @param color
+ */
+ public void setGestureColor(int color) {
+ mGesturePaint.setColor(color);
+ if (mCurrentGesture != null) {
+ mBitmap.eraseColor(TRANSPARENT_BACKGROUND);
+ mCurrentGesture.draw(mBitmapCanvas, mGesturePaint);
+ }
+ }
+
+ /**
+ * Set the gesture to be shown in the view
+ *
+ * @param gesture
+ */
+ public void setCurrentGesture(Gesture gesture) {
+ if (mCurrentGesture != null) {
+ clear(false);
+ }
+
+ mCurrentGesture = gesture;
+
+ if (gesture != null) {
+ if (mBitmapCanvas != null) {
+ gesture.draw(mBitmapCanvas, mGesturePaint);
+ invalidate();
+ }
+ }
+ }
+
+ private void init() {
+ mGesturePaint = new Paint();
+ mGesturePaint.setAntiAlias(GESTURE_RENDERING_ANTIALIAS);
+ mGesturePaint.setColor(DEFAULT_GESTURE_COLOR);
+ mGesturePaint.setStyle(Paint.Style.STROKE);
+ mGesturePaint.setStrokeJoin(Paint.Join.ROUND);
+ mGesturePaint.setStrokeCap(Paint.Cap.ROUND);
+ mGesturePaint.setStrokeWidth(GESTURE_STROKE_WIDTH);
+ mGesturePaint.setDither(DITHER_FLAG);
+
+ mPath = null;
+ }
+
+ @Override
+ protected void onSizeChanged(int width, int height, int oldWidth, int oldHeight) {
+ super.onSizeChanged(width, height, oldWidth, oldHeight);
+ if (width <= 0 || height <= 0) {
+ return;
+ }
+ int targetWidth = width > oldWidth ? width : oldWidth;
+ int targetHeight = height > oldHeight ? height : oldHeight;
+ mBitmap = Bitmap.createBitmap(targetWidth, targetHeight, Bitmap.Config.ARGB_8888);
+ mBitmapCanvas = new Canvas(mBitmap);
+ mBitmapCanvas.drawColor(TRANSPARENT_BACKGROUND);
+ if (mCurrentGesture != null) {
+ mCurrentGesture.draw(mBitmapCanvas, mGesturePaint);
+ }
+ }
+
+ public void addGestureListener(GestureListener listener) {
+ mGestureListeners.add(listener);
+ }
+
+ public void removeGestureListener(GestureListener listener) {
+ mGestureListeners.remove(listener);
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ super.onDraw(canvas);
+
+ // draw double buffer
+ if (mIsFadingOut) {
+ mBitmapPaint.setAlpha((int) (255 * mFadingAlpha));
+ canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint);
+ } else {
+ mBitmapPaint.setAlpha(255);
+ canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint);
+ }
+
+ // draw the current stroke
+ if (mPath != null) {
+ canvas.drawPath(mPath, mGesturePaint);
+ }
+ }
+
+ /**
+ * 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) {
+ mFadingAlpha = 1;
+ mIsFadingOut = true;
+ mHandler.removeCallbacks(mFadingOut);
+ mHandler.postDelayed(mFadingOut, FADING_REFRESHING_RATE);
+ } else {
+ mPath = null;
+ mCurrentGesture = null;
+ if (mBitmap != null) {
+ mBitmap.eraseColor(TRANSPARENT_BACKGROUND);
+ invalidate();
+ }
+ }
+ }
+
+ public void cancelFadingOut() {
+ mIsFadingOut = false;
+ mHandler.removeCallbacks(mFadingOut);
+ }
+
+ @Override
+ public boolean onTouchEvent(MotionEvent event) {
+
+ if (!isEnabled()) {
+ return true;
+ }
+
+ switch (event.getAction()) {
+ case MotionEvent.ACTION_DOWN:
+ Rect rect = touchStart(event);
+ invalidate(rect);
+ break;
+ case MotionEvent.ACTION_MOVE:
+ rect = touchMove(event);
+ if (rect != null) {
+ invalidate(rect);
+ }
+ break;
+ case MotionEvent.ACTION_UP:
+ touchUp(event);
+ invalidate();
+ break;
+ }
+
+ return true;
+ }
+
+ private Rect touchStart(MotionEvent event) {
+ // pass the event to handlers
+ ArrayList<GestureListener> listeners = mGestureListeners;
+ int count = listeners.size();
+ for (int i = 0; i < count; i++) {
+ GestureListener listener = listeners.get(i);
+ listener.onStartGesture(this, event);
+ }
+
+ // if there is fading out going on, stop it.
+ if (mIsFadingOut) {
+ mIsFadingOut = false;
+ mHandler.removeCallbacks(mFadingOut);
+ mBitmap.eraseColor(TRANSPARENT_BACKGROUND);
+ mCurrentGesture = null;
+ }
+
+ float x = event.getX();
+ float y = event.getY();
+
+ mX = x;
+ mY = y;
+
+ if (mCurrentGesture == null) {
+ mCurrentGesture = new Gesture();
+ }
+
+ mPointBuffer = new ArrayList<GesturePoint>();
+ mPointBuffer.add(new GesturePoint(x, y, event.getEventTime()));
+
+ mPath = new Path();
+ mPath.moveTo(x, y);
+
+ mInvalidRect.set((int) x - REFRESH_RANGE, (int) y - REFRESH_RANGE, (int) x + REFRESH_RANGE,
+ (int) y + REFRESH_RANGE);
+
+ mCurveEndX = x;
+ mCurveEndY = y;
+
+ return mInvalidRect;
+ }
+
+ private Rect touchMove(MotionEvent event) {
+ Rect areaToRefresh = null;
+
+ float x = event.getX();
+ float y = event.getY();
+
+ float dx = Math.abs(x - mX);
+ float dy = Math.abs(y - mY);
+
+ if (dx >= TOUCH_TOLERANCE || dy >= TOUCH_TOLERANCE) {
+
+ // start with the curve end
+ mInvalidRect.set((int) mCurveEndX - REFRESH_RANGE, (int) mCurveEndY - REFRESH_RANGE,
+ (int) mCurveEndX + REFRESH_RANGE, (int) mCurveEndY + REFRESH_RANGE);
+
+ mCurveEndX = (x + mX) / 2;
+ mCurveEndY = (y + mY) / 2;
+ mPath.quadTo(mX, mY, mCurveEndX, mCurveEndY);
+
+ // union with the control point of the new curve
+ mInvalidRect.union((int) mX - REFRESH_RANGE, (int) mY - REFRESH_RANGE,
+ (int) mX + REFRESH_RANGE, (int) mY + REFRESH_RANGE);
+
+ // union with the end point of the new curve
+ mInvalidRect.union((int) mCurveEndX - REFRESH_RANGE, (int) mCurveEndY - REFRESH_RANGE,
+ (int) mCurveEndX + REFRESH_RANGE, (int) mCurveEndY + REFRESH_RANGE);
+
+ areaToRefresh = mInvalidRect;
+
+ mX = x;
+ mY = y;
+ }
+
+
+ mPointBuffer.add(new GesturePoint(x, y, event.getEventTime()));
+
+ // pass the event to handlers
+ ArrayList<GestureListener> listeners = mGestureListeners;
+ int count = listeners.size();
+ for (int i = 0; i < count; i++) {
+ GestureListener listener = listeners.get(i);
+ listener.onGesture(this, event);
+ }
+
+ return areaToRefresh;
+ }
+
+ private void touchUp(MotionEvent event) {
+ // add the stroke to the current gesture
+ mCurrentGesture.addStroke(new GestureStroke(mPointBuffer));
+
+ // add the stroke to the double buffer
+ mGesturePaint.setMaskFilter(BLUR_MASK_FILTER);
+ mBitmapCanvas.drawPath(mPath, mGesturePaint);
+ mGesturePaint.setMaskFilter(null);
+
+ // pass the event to handlers
+ ArrayList<GestureListener> listeners = mGestureListeners;
+ int count = listeners.size();
+ for (int i = 0; i < count; i++) {
+ GestureListener listener = listeners.get(i);
+ listener.onFinishGesture(this, event);
+ }
+
+ mPath = null;
+ mPointBuffer = null;
+ }
+
+}