diff options
author | Romain Guy <romainguy@android.com> | 2009-05-21 16:23:21 -0700 |
---|---|---|
committer | Romain Guy <romainguy@android.com> | 2009-05-21 18:12:56 -0700 |
commit | db567c390bd56c05614eaa83c02dbb99f97ad9cc (patch) | |
tree | 86399406ca7a53c3d902b3863bf7a944cb7c5c3f /tests/sketch/src/com/android | |
parent | 384bfa270cdcb5dc3bc9ec396b783e25eb2d9b4d (diff) | |
download | frameworks_base-db567c390bd56c05614eaa83c02dbb99f97ad9cc.zip frameworks_base-db567c390bd56c05614eaa83c02dbb99f97ad9cc.tar.gz frameworks_base-db567c390bd56c05614eaa83c02dbb99f97ad9cc.tar.bz2 |
Move the Gestures API to the framework in android.gesture.
Diffstat (limited to 'tests/sketch/src/com/android')
19 files changed, 28 insertions, 2698 deletions
diff --git a/tests/sketch/src/com/android/gesture/Gesture.java b/tests/sketch/src/com/android/gesture/Gesture.java deleted file mode 100755 index d5dcc65..0000000 --- a/tests/sketch/src/com/android/gesture/Gesture.java +++ /dev/null @@ -1,320 +0,0 @@ -/* - * 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.graphics.Bitmap; -import android.graphics.Canvas; -import android.graphics.Paint; -import android.graphics.Path; -import android.graphics.RectF; -import android.os.Parcel; -import android.os.Parcelable; -import android.util.Log; - -import java.io.IOException; -import java.io.DataOutputStream; -import java.io.DataInputStream; -import java.io.ByteArrayOutputStream; -import java.io.ByteArrayInputStream; -import java.util.ArrayList; - -import static com.android.gesture.GestureConstants.LOG_TAG; - -/** - * A gesture can have a single or multiple strokes - */ - -public class Gesture implements Parcelable { - private static final long GESTURE_ID_BASE = System.currentTimeMillis(); - - private static final int BITMAP_RENDERING_WIDTH = 2; - - private static final boolean BITMAP_RENDERING_ANTIALIAS = true; - private static final boolean BITMAP_RENDERING_DITHER = true; - - private static int sGestureCount = 0; - - private RectF mBoundingBox; - - // the same as its instance ID - private long mGestureID; - - private final ArrayList<GestureStroke> mStrokes = new ArrayList<GestureStroke>(); - - public Gesture() { - mGestureID = GESTURE_ID_BASE + sGestureCount++; - } - - /** - * @return all the strokes of the gesture - */ - public ArrayList<GestureStroke> getStrokes() { - return mStrokes; - } - - /** - * @return the number of strokes included by this gesture - */ - public int getStrokesCount() { - return mStrokes.size(); - } - - /** - * Add a stroke to the gesture - * - * @param stroke - */ - public void addStroke(GestureStroke stroke) { - mStrokes.add(stroke); - - if (mBoundingBox == null) { - mBoundingBox = new RectF(stroke.boundingBox); - } else { - mBoundingBox.union(stroke.boundingBox); - } - } - - /** - * Get the total length of the gesture. When there are multiple strokes in - * the gesture, this returns the sum of the lengths of all the strokes - * - * @return the length of the gesture - */ - public float getLength() { - int len = 0; - final ArrayList<GestureStroke> strokes = mStrokes; - final int count = strokes.size(); - - for (int i = 0; i < count; i++) { - len += strokes.get(i).length; - } - - return len; - } - - /** - * @return the bounding box of the gesture - */ - public RectF getBoundingBox() { - return mBoundingBox; - } - - /** - * Set the id of the gesture - * - * @param id - */ - void setID(long id) { - mGestureID = id; - } - - /** - * @return the id of the gesture - */ - public long getID() { - return mGestureID; - } - - /** - * draw the gesture - * - * @param canvas - */ - void draw(Canvas canvas, Paint paint) { - final ArrayList<GestureStroke> strokes = mStrokes; - final int count = strokes.size(); - - for (int i = 0; i < count; i++) { - strokes.get(i).draw(canvas, paint); - } - } - - /** - * Create a bitmap of the gesture with a transparent background - * - * @param width width of the target bitmap - * @param height height of the target bitmap - * @param edge the edge - * @param numSample - * @param color - * @return the bitmap - */ - public Bitmap toBitmap(int width, int height, int edge, int numSample, int color) { - final Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); - final Canvas canvas = new Canvas(bitmap); - - canvas.translate(edge, edge); - - final Paint paint = new Paint(); - paint.setAntiAlias(BITMAP_RENDERING_ANTIALIAS); - paint.setDither(BITMAP_RENDERING_DITHER); - paint.setColor(color); - paint.setStyle(Paint.Style.STROKE); - paint.setStrokeJoin(Paint.Join.ROUND); - paint.setStrokeCap(Paint.Cap.ROUND); - paint.setStrokeWidth(BITMAP_RENDERING_WIDTH); - - final ArrayList<GestureStroke> strokes = mStrokes; - final int count = strokes.size(); - - for (int i = 0; i < count; i++) { - Path path = strokes.get(i).toPath(width - 2 * edge, height - 2 * edge, numSample); - canvas.drawPath(path, paint); - } - - return bitmap; - } - - /** - * Create a bitmap of the gesture with a transparent background - * - * @param width - * @param height - * @param edge - * @param color - * @return the bitmap - */ - public Bitmap toBitmap(int width, int height, int edge, int color) { - final Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); - final Canvas canvas = new Canvas(bitmap); - - canvas.translate(edge, edge); - - final Paint paint = new Paint(); - paint.setAntiAlias(BITMAP_RENDERING_ANTIALIAS); - paint.setDither(BITMAP_RENDERING_DITHER); - paint.setColor(color); - paint.setStyle(Paint.Style.STROKE); - paint.setStrokeJoin(Paint.Join.ROUND); - paint.setStrokeCap(Paint.Cap.ROUND); - paint.setStrokeWidth(BITMAP_RENDERING_WIDTH); - - final ArrayList<GestureStroke> strokes = mStrokes; - final int count = strokes.size(); - - for (int i = 0; i < count; i++) { - strokes.get(i).draw(canvas, paint); - } - - return bitmap; - } - - void serialize(DataOutputStream out) throws IOException { - final ArrayList<GestureStroke> strokes = mStrokes; - final int count = strokes.size(); - - // Write gesture ID - out.writeLong(mGestureID); - // Write number of strokes - out.writeInt(count); - - for (int i = 0; i < count; i++) { - strokes.get(i).serialize(out); - } - } - - static Gesture deserialize(DataInputStream in) throws IOException { - final Gesture gesture = new Gesture(); - - // Gesture ID - gesture.mGestureID = in.readLong(); - // Number of strokes - final int count = in.readInt(); - - for (int i = 0; i < count; i++) { - gesture.addStroke(GestureStroke.deserialize(in)); - } - - return gesture; - } - - /** - * Convert the gesture to string - */ - @Override - public String toString() { - final StringBuilder str = new StringBuilder(); - str.append(mGestureID); - - final ArrayList<GestureStroke> strokes = mStrokes; - final int count = strokes.size(); - - for (int i = 0; i < count; i++) { - final GestureStroke stroke = strokes.get(i); - str.append(GestureConstants.STRING_GESTURE_DELIIMITER); - str.append(stroke.toString()); - } - - return str.toString(); - } - - public static final Parcelable.Creator<Gesture> CREATOR = new Parcelable.Creator<Gesture>() { - public Gesture createFromParcel(Parcel in) { - Gesture gesture = null; - final long gestureID = in.readLong(); - - final DataInputStream inStream = new DataInputStream( - new ByteArrayInputStream(in.createByteArray())); - - try { - gesture = deserialize(inStream); - } catch (IOException e) { - Log.e(LOG_TAG, "Error reading Gesture from parcel:", e); - } finally { - GestureUtilities.closeStream(inStream); - } - - if (gesture != null) { - gesture.mGestureID = gestureID; - } - - return gesture; - } - - public Gesture[] newArray(int size) { - return new Gesture[size]; - } - }; - - public void writeToParcel(Parcel out, int flags) { - out.writeLong(mGestureID); - - boolean result = false; - final ByteArrayOutputStream byteStream = - new ByteArrayOutputStream(GestureConstants.IO_BUFFER_SIZE); - final DataOutputStream outStream = new DataOutputStream(byteStream); - - try { - serialize(outStream); - result = true; - } catch (IOException e) { - Log.e(LOG_TAG, "Error writing Gesture to parcel:", e); - } finally { - GestureUtilities.closeStream(outStream); - GestureUtilities.closeStream(byteStream); - } - - if (result) { - out.writeByteArray(byteStream.toByteArray()); - } - } - - public int describeContents() { - return 0; - } -} - diff --git a/tests/sketch/src/com/android/gesture/GestureActionListener.java b/tests/sketch/src/com/android/gesture/GestureActionListener.java deleted file mode 100644 index c9c5232..0000000 --- a/tests/sketch/src/com/android/gesture/GestureActionListener.java +++ /dev/null @@ -1,21 +0,0 @@ -/* - * 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; - -public interface GestureActionListener { - public void onGesturePerformed(GestureOverlay overlay, Gesture gesture); -} diff --git a/tests/sketch/src/com/android/gesture/GestureConstants.java b/tests/sketch/src/com/android/gesture/GestureConstants.java deleted file mode 100644 index c0f2f3d..0000000 --- a/tests/sketch/src/com/android/gesture/GestureConstants.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright (C) 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; - -interface GestureConstants { - static final String STRING_GESTURE_DELIIMITER = "#"; - static final String STRING_STROKE_DELIIMITER = ","; - - static final int STROKE_STRING_BUFFER_SIZE = 1024; - static final int STROKE_POINT_BUFFER_SIZE = 100; // number of points - - static final int IO_BUFFER_SIZE = 32 * 1024; // 32K - - static final String LOG_TAG = "Gestures"; -} diff --git a/tests/sketch/src/com/android/gesture/GestureLibrary.java b/tests/sketch/src/com/android/gesture/GestureLibrary.java deleted file mode 100644 index 7b5480c..0000000 --- a/tests/sketch/src/com/android/gesture/GestureLibrary.java +++ /dev/null @@ -1,346 +0,0 @@ -/* - * 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.util.Log; -import android.os.SystemClock; - -import java.io.BufferedInputStream; -import java.io.BufferedOutputStream; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.DataOutputStream; -import java.io.DataInputStream; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Set; -import java.util.Map; - -import static com.android.gesture.GestureConstants.LOG_TAG; - -/** - * GestureLibrary maintains gesture examples and makes predictions on a new - * gesture - */ -// -// File format for GestureLibrary: -// -// Nb. bytes Java type Description -// ----------------------------------- -// Header -// 2 bytes short File format version number -// 4 bytes int Number of entries -// Entry -// X bytes UTF String Entry name -// 4 bytes int Number of gestures -// Gesture -// 8 bytes long Gesture ID -// 4 bytes int Number of strokes -// Stroke -// 4 bytes int Number of points -// Point -// 4 bytes float X coordinate of the point -// 4 bytes float Y coordinate of the point -// 8 bytes long Time stamp -// -public class GestureLibrary { - public static final int SEQUENCE_INVARIANT = 1; - // when SEQUENCE_SENSITIVE is used, only single stroke gestures are currently allowed - public static final int SEQUENCE_SENSITIVE = 2; - - // ORIENTATION_SENSITIVE and ORIENTATION_INVARIANT are only for SEQUENCE_SENSITIVE gestures - public static final int ORIENTATION_INVARIANT = 1; - public static final int ORIENTATION_SENSITIVE = 2; - - private static final short FILE_FORMAT_VERSION = 1; - - private static final boolean PROFILE_LOADING_SAVING = false; - - private int mSequenceType = SEQUENCE_SENSITIVE; - private int mOrientationStyle = ORIENTATION_SENSITIVE; - - private final String mGestureFileName; - - private final HashMap<String, ArrayList<Gesture>> mNamedGestures = - new HashMap<String, ArrayList<Gesture>>(); - - private Learner mClassifier; - - private boolean mChanged = false; - - /** - * @param path where gesture data is stored - */ - public GestureLibrary(String path) { - mGestureFileName = path; - mClassifier = new InstanceLearner(); - } - - /** - * Specify how the gesture library will handle orientation. - * Use ORIENTATION_INVARIANT or ORIENTATION_SENSITIVE - * - * @param style - */ - public void setOrientationStyle(int style) { - mOrientationStyle = style; - } - - public int getOrientationStyle() { - return mOrientationStyle; - } - - /** - * @param type SEQUENCE_INVARIANT or SEQUENCE_SENSITIVE - */ - public void setSequenceType(int type) { - mSequenceType = type; - } - - /** - * @return SEQUENCE_INVARIANT or SEQUENCE_SENSITIVE - */ - public int getSequenceType() { - return mSequenceType; - } - - /** - * Get all the gesture entry names in the library - * - * @return a set of strings - */ - public Set<String> getGestureEntries() { - return mNamedGestures.keySet(); - } - - /** - * Recognize a gesture - * - * @param gesture the query - * @return a list of predictions of possible entries for a given gesture - */ - public ArrayList<Prediction> recognize(Gesture gesture) { - Instance instance = Instance.createInstance(mSequenceType, gesture, null); - return mClassifier.classify(mSequenceType, instance.vector); - } - - /** - * Add a gesture for the entry - * - * @param entryName entry name - * @param gesture - */ - public void addGesture(String entryName, Gesture gesture) { - if (entryName == null || entryName.length() == 0) { - return; - } - ArrayList<Gesture> gestures = mNamedGestures.get(entryName); - if (gestures == null) { - gestures = new ArrayList<Gesture>(); - mNamedGestures.put(entryName, gestures); - } - gestures.add(gesture); - mClassifier.addInstance(Instance.createInstance(mSequenceType, gesture, entryName)); - mChanged = true; - } - - /** - * Remove a gesture from the library. If there are no more gestures for the - * given entry, the gesture entry will be removed. - * - * @param entryName entry name - * @param gesture - */ - public void removeGesture(String entryName, Gesture gesture) { - ArrayList<Gesture> gestures = mNamedGestures.get(entryName); - if (gestures == null) { - return; - } - - gestures.remove(gesture); - - // if there are no more samples, remove the entry automatically - if (gestures.isEmpty()) { - mNamedGestures.remove(entryName); - } - - mClassifier.removeInstance(gesture.getID()); - - mChanged = true; - } - - /** - * Remove a entry of gestures - * - * @param entryName the entry name - */ - public void removeEntireEntry(String entryName) { - mNamedGestures.remove(entryName); - mClassifier.removeInstances(entryName); - mChanged = true; - } - - /** - * Get all the gestures of an entry - * - * @param entryName - * @return the list of gestures that is under this name - */ - public ArrayList<Gesture> getGestures(String entryName) { - ArrayList<Gesture> gestures = mNamedGestures.get(entryName); - if (gestures != null) { - return new ArrayList<Gesture>(gestures); - } else { - return null; - } - } - - /** - * Save the gesture library - */ - public boolean save() { - if (!mChanged) { - return true; - } - - boolean result = false; - DataOutputStream out = null; - - try { - File file = new File(mGestureFileName); - if (!file.getParentFile().exists()) { - if (!file.getParentFile().mkdirs()) { - return false; - } - } - - long start; - if (PROFILE_LOADING_SAVING) { - start = SystemClock.elapsedRealtime(); - } - - final HashMap<String, ArrayList<Gesture>> maps = mNamedGestures; - - out = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(file), - GestureConstants.IO_BUFFER_SIZE)); - // Write version number - out.writeShort(FILE_FORMAT_VERSION); - // Write number of entries - out.writeInt(maps.size()); - - for (Map.Entry<String, ArrayList<Gesture>> entry : maps.entrySet()) { - final String key = entry.getKey(); - final ArrayList<Gesture> examples = entry.getValue(); - final int count = examples.size(); - - // Write entry name - out.writeUTF(key); - // Write number of examples for this entry - out.writeInt(count); - - for (int i = 0; i < count; i++) { - examples.get(i).serialize(out); - } - } - - out.flush(); - - if (PROFILE_LOADING_SAVING) { - long end = SystemClock.elapsedRealtime(); - Log.d(LOG_TAG, "Saving gestures library = " + (end - start) + " ms"); - } - - mChanged = false; - result = true; - } catch (IOException ex) { - Log.d(LOG_TAG, "Failed to save gestures:", ex); - } finally { - GestureUtilities.closeStream(out); - } - - return result; - } - - /** - * Load the gesture library - */ - public boolean load() { - boolean result = false; - - final File file = new File(mGestureFileName); - if (file.exists()) { - DataInputStream in = null; - try { - in = new DataInputStream(new BufferedInputStream( - new FileInputStream(mGestureFileName), GestureConstants.IO_BUFFER_SIZE)); - - long start; - if (PROFILE_LOADING_SAVING) { - start = SystemClock.elapsedRealtime(); - } - - // Read file format version number - final short versionNumber = in.readShort(); - switch (versionNumber) { - case 1: - readFormatV1(in); - break; - } - - if (PROFILE_LOADING_SAVING) { - long end = SystemClock.elapsedRealtime(); - Log.d(LOG_TAG, "Loading gestures library = " + (end - start) + " ms"); - } - - result = true; - } catch (IOException ex) { - Log.d(LOG_TAG, "Failed to load gestures:", ex); - } finally { - GestureUtilities.closeStream(in); - } - } - - return result; - } - - private void readFormatV1(DataInputStream in) throws IOException { - final Learner classifier = mClassifier; - final HashMap<String, ArrayList<Gesture>> namedGestures = mNamedGestures; - namedGestures.clear(); - - // Number of entries in the library - final int entriesCount = in.readInt(); - - for (int i = 0; i < entriesCount; i++) { - // Entry name - final String name = in.readUTF(); - // Number of gestures - final int gestureCount = in.readInt(); - - final ArrayList<Gesture> gestures = new ArrayList<Gesture>(gestureCount); - for (int j = 0; j < gestureCount; j++) { - final Gesture gesture = Gesture.deserialize(in); - gestures.add(gesture); - classifier.addInstance(Instance.createInstance(mSequenceType, gesture, name)); - } - - namedGestures.put(name, gestures); - } - } -} diff --git a/tests/sketch/src/com/android/gesture/GestureListener.java b/tests/sketch/src/com/android/gesture/GestureListener.java deleted file mode 100755 index 9b50714..0000000 --- a/tests/sketch/src/com/android/gesture/GestureListener.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * 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.view.MotionEvent; - -/** - * An interface for processing gesture events - */ -public interface GestureListener { - public void onStartGesture(GestureOverlay overlay, MotionEvent event); - - public void onGesture(GestureOverlay overlay, MotionEvent event); - - public void onFinishGesture(GestureOverlay overlay, MotionEvent event); -} diff --git a/tests/sketch/src/com/android/gesture/GestureOverlay.java b/tests/sketch/src/com/android/gesture/GestureOverlay.java deleted file mode 100755 index 454cecb..0000000 --- a/tests/sketch/src/com/android/gesture/GestureOverlay.java +++ /dev/null @@ -1,390 +0,0 @@ -/* - * 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.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; - - // TODO: Move all these values into XML attributes - private static final int TRANSPARENT_BACKGROUND = 0x00000000; - - // TODO: SHOULD BE A TOTAL DURATION - private static final float FADING_ALPHA_CHANGE = 0.15f; - private static final long FADING_OFFSET = 300; - private static final long FADING_REFRESHING_RATE = 16; - - private static final int GESTURE_STROKE_WIDTH = 12; - private static final boolean GESTURE_RENDERING_ANTIALIAS = true; - - private static final boolean DITHER_FLAG = true; - - public static final int DEFAULT_GESTURE_COLOR = 0xFFFFFF00; - - private static final int REFRESH_RANGE = 10; - - private static final BlurMaskFilter BLUR_MASK_FILTER = - new BlurMaskFilter(1, BlurMaskFilter.Blur.NORMAL); - - - // double buffering - private Paint mGesturePaint; - - private final Paint mBitmapPaint = new Paint(Paint.DITHER_FLAG); - 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; - - // TODO: Make this a list of WeakReferences - private final 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 final 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(); - - final Paint gesturePaint = mGesturePaint; - gesturePaint.setAntiAlias(GESTURE_RENDERING_ANTIALIAS); - gesturePaint.setColor(DEFAULT_GESTURE_COLOR); - gesturePaint.setStyle(Paint.Style.STROKE); - gesturePaint.setStrokeJoin(Paint.Join.ROUND); - gesturePaint.setStrokeCap(Paint.Cap.ROUND); - gesturePaint.setStrokeWidth(GESTURE_STROKE_WIDTH); - gesturePaint.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; - - if (mBitmap != null) mBitmap.recycle(); - - mBitmap = Bitmap.createBitmap(targetWidth, targetHeight, Bitmap.Config.ARGB_8888); - if (mBitmapCanvas != null) { - mBitmapCanvas.setBitmap(mBitmap); - } else { - 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_OFFSET); - } 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 - final ArrayList<GestureListener> listeners = mGestureListeners; - final 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 - final ArrayList<GestureListener> listeners = mGestureListeners; - final int count = listeners.size(); - for (int i = 0; i < count; i++) { - listeners.get(i).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 - final ArrayList<GestureListener> listeners = mGestureListeners; - final int count = listeners.size(); - for (int i = 0; i < count; i++) { - listeners.get(i).onFinishGesture(this, event); - } - - mPath = null; - mPointBuffer = null; - } - -} diff --git a/tests/sketch/src/com/android/gesture/GesturePoint.java b/tests/sketch/src/com/android/gesture/GesturePoint.java deleted file mode 100644 index 560f893..0000000 --- a/tests/sketch/src/com/android/gesture/GesturePoint.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * 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 java.io.DataInputStream; -import java.io.IOException; - -/** - * A timed point of a gesture stroke - */ - -public class GesturePoint { - public final float x; - public final float y; - - public final long timestamp; - - public GesturePoint(float x, float y, long t) { - this.x = x; - this.y = y; - timestamp = t; - } - - static GesturePoint deserialize(DataInputStream in) throws IOException { - // Read X and Y - final float x = in.readFloat(); - final float y = in.readFloat(); - // Read timestamp - final long timeStamp = in.readLong(); - return new GesturePoint(x, y, timeStamp); - } -} diff --git a/tests/sketch/src/com/android/gesture/GestureStroke.java b/tests/sketch/src/com/android/gesture/GestureStroke.java deleted file mode 100644 index 79b42fe..0000000 --- a/tests/sketch/src/com/android/gesture/GestureStroke.java +++ /dev/null @@ -1,233 +0,0 @@ -/* - * 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.graphics.Canvas; -import android.graphics.Matrix; -import android.graphics.Paint; -import android.graphics.Path; -import android.graphics.RectF; - -import java.io.IOException; -import java.io.DataOutputStream; -import java.io.DataInputStream; -import java.util.ArrayList; - -/** - * A gesture stroke started on a touch down and ended on a touch up. - */ -public class GestureStroke { - public final RectF boundingBox; - - public final float length; - public final float[] points; - - private final long[] timestamps; - private Path mCachedPath; - - /** - * Construct a gesture stroke from a list of gesture points - * - * @param points - */ - public GestureStroke(ArrayList<GesturePoint> points) { - final int count = points.size(); - final float[] tmpPoints = new float[count * 2]; - final long[] times = new long[count]; - - RectF bx = null; - float len = 0; - int index = 0; - - for (int i = 0; i < count; i++) { - final GesturePoint p = points.get(i); - tmpPoints[i * 2] = p.x; - tmpPoints[i * 2 + 1] = p.y; - times[index] = p.timestamp; - - if (bx == null) { - bx = new RectF(); - bx.top = p.y; - bx.left = p.x; - bx.right = p.x; - bx.bottom = p.y; - len = 0; - } else { - len += Math.sqrt(Math.pow(p.x - tmpPoints[(i - 1) * 2], 2) - + Math.pow(p.y - tmpPoints[(i -1 ) * 2 + 1], 2)); - bx.union(p.x, p.y); - } - index++; - } - - timestamps = times; - this.points = tmpPoints; - boundingBox = bx; - length = len; - } - - /** - * Draw the gesture with a given canvas and paint - * - * @param canvas - */ - void draw(Canvas canvas, Paint paint) { - if (mCachedPath == null) { - final float[] localPoints = points; - final int count = localPoints.length; - - Path path = null; - - float mX = 0; - float mY = 0; - - for (int i = 0; i < count; i += 2) { - float x = localPoints[i]; - float y = localPoints[i + 1]; - if (path == null) { - path = new Path(); - path.moveTo(x, y); - mX = x; - mY = y; - } else { - float dx = Math.abs(x - mX); - float dy = Math.abs(y - mY); - if (dx >= 3 || dy >= 3) { - path.quadTo(mX, mY, (x + mX) / 2, (y + mY) / 2); - mX = x; - mY = y; - } - } - } - - mCachedPath = path; - } - - canvas.drawPath(mCachedPath, paint); - } - - /** - * Convert the stroke to a Path based on the number of points - * - * @param width the width of the bounding box of the target path - * @param height the height of the bounding box of the target path - * @param numSample the number of points needed - * @return the path - */ - public Path toPath(float width, float height, int numSample) { - final float[] pts = GestureUtilities.temporalSampling(this, numSample); - final RectF rect = boundingBox; - final float scale = height / rect.height(); - - final Matrix matrix = new Matrix(); - matrix.setTranslate(-rect.left, -rect.top); - matrix.postScale(scale, scale); - matrix.mapPoints(pts); - - float mX = 0; - float mY = 0; - - Path path = null; - - final int count = pts.length; - - for (int i = 0; i < count; i += 2) { - float x = pts[i]; - float y = pts[i + 1]; - if (path == null) { - path = new Path(); - path.moveTo(x, y); - mX = x; - mY = y; - } else { - float dx = Math.abs(x - mX); - float dy = Math.abs(y - mY); - if (dx >= GestureOverlay.TOUCH_TOLERANCE || dy >= GestureOverlay.TOUCH_TOLERANCE) { - path.quadTo(mX, mY, (x + mX) / 2, (y + mY) / 2); - mX = x; - mY = y; - } - } - } - - return path; - } - - void serialize(DataOutputStream out) throws IOException { - final float[] pts = points; - final long[] times = timestamps; - final int count = points.length; - - // Write number of points - out.writeInt(count / 2); - - for (int i = 0; i < count; i += 2) { - // Write X - out.writeFloat(pts[i]); - // Write Y - out.writeFloat(pts[i + 1]); - // Write timestamp - out.writeLong(times[i / 2]); - } - } - - static GestureStroke deserialize(DataInputStream in) throws IOException { - // Number of points - final int count = in.readInt(); - - final ArrayList<GesturePoint> points = new ArrayList<GesturePoint>(count); - for (int i = 0; i < count; i++) { - points.add(GesturePoint.deserialize(in)); - } - - return new GestureStroke(points); - } - - /** - * Convert the stroke to string - */ - @Override - public String toString() { - final StringBuilder str = new StringBuilder(GestureConstants.STROKE_STRING_BUFFER_SIZE); - final float[] pts = points; - final long[] times = timestamps; - final int count = points.length; - - for (int i = 0; i < count; i += 2) { - str.append(pts[i]).append(GestureConstants.STRING_STROKE_DELIIMITER); - str.append(pts[i + 1]).append(GestureConstants.STRING_STROKE_DELIIMITER); - str.append(times[i / 2]).append(GestureConstants.STRING_STROKE_DELIIMITER); - } - - return str.toString(); - } - - /** - * Invalidate the cached path that is used for rendering the stroke - */ - public void invalidate() { - mCachedPath = null; - } - - /** - * Compute an oriented bounding box of the stroke - * @return OrientedBoundingBox - */ - public OrientedBoundingBox computeOrientedBoundingBox() { - return GestureUtilities.computeOrientedBoundingBox(points); - } -} diff --git a/tests/sketch/src/com/android/gesture/GestureUtilities.java b/tests/sketch/src/com/android/gesture/GestureUtilities.java deleted file mode 100755 index 6d73c2d..0000000 --- a/tests/sketch/src/com/android/gesture/GestureUtilities.java +++ /dev/null @@ -1,444 +0,0 @@ -/* - * 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.graphics.RectF; -import android.graphics.Matrix; -import android.util.Log; - -import java.util.ArrayList; -import java.util.Arrays; -import java.io.Closeable; -import java.io.IOException; - -import static com.android.gesture.GestureConstants.*; - -final class GestureUtilities { - private static final int TEMPORAL_SAMPLING_RATE = 16; - - private GestureUtilities() { - } - - /** - * Closes the specified stream. - * - * @param stream The stream to close. - */ - static void closeStream(Closeable stream) { - if (stream != null) { - try { - stream.close(); - } catch (IOException e) { - Log.e(LOG_TAG, "Could not close stream", e); - } - } - } - - static float[] spatialSampling(Gesture gesture, int sampleMatrixDimension) { - final float targetPatchSize = sampleMatrixDimension - 1; // edge inclusive - float[] sample = new float[sampleMatrixDimension * sampleMatrixDimension]; - Arrays.fill(sample, 0); - - RectF rect = gesture.getBoundingBox(); - float sx = targetPatchSize / rect.width(); - float sy = targetPatchSize / rect.height(); - float scale = sx < sy ? sx : sy; - - Matrix trans = new Matrix(); - trans.setScale(scale, scale); - trans.preTranslate(-rect.centerX(), -rect.centerY()); - trans.postTranslate(targetPatchSize / 2, targetPatchSize / 2); - - final ArrayList<GestureStroke> strokes = gesture.getStrokes(); - final int count = strokes.size(); - - int size; - float xpos; - float ypos; - - for (int index = 0; index < count; index++) { - final GestureStroke stroke = strokes.get(index); - size = stroke.points.length; - - final float[] pts = new float[size]; - - trans.mapPoints(pts, 0, stroke.points, 0, size / 2); - float segmentEndX = -1; - float segmentEndY = -1; - - for (int i = 0; i < size; i += 2) { - - float segmentStartX = pts[i] < 0 ? 0 : pts[i]; - float segmentStartY = pts[i + 1] < 0 ? 0 : pts[i + 1]; - - if (segmentStartX > targetPatchSize) { - segmentStartX = targetPatchSize; - } - - if (segmentStartY > targetPatchSize) { - segmentStartY = targetPatchSize; - } - - plot(segmentStartX, segmentStartY, sample, sampleMatrixDimension); - - if (segmentEndX != -1) { - // evaluate horizontally - if (segmentEndX > segmentStartX) { - xpos = (float) Math.ceil(segmentStartX); - float slope = (segmentEndY - segmentStartY) / (segmentEndX - segmentStartX); - while (xpos < segmentEndX) { - ypos = slope * (xpos - segmentStartX) + segmentStartY; - plot(xpos, ypos, sample, sampleMatrixDimension); - xpos++; - } - } else if (segmentEndX < segmentStartX){ - xpos = (float) Math.ceil(segmentEndX); - float slope = (segmentEndY - segmentStartY) / (segmentEndX - segmentStartX); - while (xpos < segmentStartX) { - ypos = slope * (xpos - segmentStartX) + segmentStartY; - plot(xpos, ypos, sample, sampleMatrixDimension); - xpos++; - } - } - - // evaluating vertically - if (segmentEndY > segmentStartY) { - ypos = (float) Math.ceil(segmentStartY); - float invertSlope = (segmentEndX - segmentStartX) / (segmentEndY - segmentStartY); - while (ypos < segmentEndY) { - xpos = invertSlope * (ypos - segmentStartY) + segmentStartX; - plot(xpos, ypos, sample, sampleMatrixDimension); - ypos++; - } - } else if (segmentEndY < segmentStartY) { - ypos = (float) Math.ceil(segmentEndY); - float invertSlope = (segmentEndX - segmentStartX) / (segmentEndY - segmentStartY); - while (ypos < segmentStartY) { - xpos = invertSlope * (ypos - segmentStartY) + segmentStartX; - plot(xpos, ypos, sample, sampleMatrixDimension); - ypos++; - } - } - } - - segmentEndX = segmentStartX; - segmentEndY = segmentStartY; - } - } - - - return sample; - } - - private static void plot(float x, float y, float[] sample, int sampleSize) { - x = x < 0 ? 0 : x; - y = y < 0 ? 0 : y; - int xFloor = (int) Math.floor(x); - int xCeiling = (int) Math.ceil(x); - int yFloor = (int) Math.floor(y); - int yCeiling = (int) Math.ceil(y); - - // if it's an integer - if (x == xFloor && y == yFloor) { - int index = yCeiling * sampleSize + xCeiling; - if (sample[index] < 1){ - sample[index] = 1; - } - } else { - double topLeft = Math.sqrt(Math.pow(xFloor - x, 2) + Math.pow(yFloor - y, 2)); - double topRight = Math.sqrt(Math.pow(xCeiling - x, 2) + Math.pow(yFloor - y, 2)); - double btmLeft = Math.sqrt(Math.pow(xFloor - x, 2) + Math.pow(yCeiling - y, 2)); - double btmRight = Math.sqrt(Math.pow(xCeiling - x, 2) + Math.pow(yCeiling - y, 2)); - double sum = topLeft + topRight + btmLeft + btmRight; - - double value = topLeft / sum; - int index = yFloor * sampleSize + xFloor; - if (value > sample[index]){ - sample[index] = (float) value; - } - - value = topRight / sum; - index = yFloor * sampleSize + xCeiling; - if (value > sample[index]){ - sample[index] = (float) value; - } - - value = btmLeft / sum; - index = yCeiling * sampleSize + xFloor; - if (value > sample[index]){ - sample[index] = (float) value; - } - - value = btmRight / sum; - index = yCeiling * sampleSize + xCeiling; - if (value > sample[index]){ - sample[index] = (float) value; - } - } - } - - /** - * Featurize a stroke into a vector of a given number of elements - * - * @param stroke - * @param sampleSize - * @return a float array - */ - static float[] temporalSampling(GestureStroke stroke, int sampleSize) { - final float increment = stroke.length / (sampleSize - 1); - int vectorLength = sampleSize * 2; - float[] vector = new float[vectorLength]; - float distanceSoFar = 0; - float[] pts = stroke.points; - float lstPointX = pts[0]; - float lstPointY = pts[1]; - int index = 0; - float currentPointX = Float.MIN_VALUE; - float currentPointY = Float.MIN_VALUE; - vector[index] = lstPointX; - index++; - vector[index] = lstPointY; - index++; - int i = 0; - int count = pts.length / 2; - while (i < count) { - if (currentPointX == Float.MIN_VALUE) { - i++; - if (i >= count) { - break; - } - currentPointX = pts[i * 2]; - currentPointY = pts[i * 2 + 1]; - } - float deltaX = currentPointX - lstPointX; - float deltaY = currentPointY - lstPointY; - float distance = (float) Math.sqrt(deltaX * deltaX + deltaY * deltaY); - if (distanceSoFar + distance >= increment) { - float ratio = (increment - distanceSoFar) / distance; - float nx = lstPointX + ratio * deltaX; - float ny = lstPointY + ratio * deltaY; - vector[index] = nx; - index++; - vector[index] = ny; - index++; - lstPointX = nx; - lstPointY = ny; - distanceSoFar = 0; - } else { - lstPointX = currentPointX; - lstPointY = currentPointY; - currentPointX = Float.MIN_VALUE; - currentPointY = Float.MIN_VALUE; - distanceSoFar += distance; - } - } - - for (i = index; i < vectorLength; i += 2) { - vector[i] = lstPointX; - vector[i + 1] = lstPointY; - } - return vector; - } - - /** - * Calculate the centroid - * - * @param points - * @return the centroid - */ - static float[] computeCentroid(float[] points) { - float centerX = 0; - float centerY = 0; - int count = points.length; - for (int i = 0; i < count; i++) { - centerX += points[i]; - i++; - centerY += points[i]; - } - float[] center = new float[2]; - center[0] = 2 * centerX / count; - center[1] = 2 * centerY / count; - - return center; - } - - /** - * calculate the variance-covariance matrix, treat each point as a sample - * - * @param points - * @return the covariance matrix - */ - private static double[][] computeCoVariance(float[] points) { - double[][] array = new double[2][2]; - array[0][0] = 0; - array[0][1] = 0; - array[1][0] = 0; - array[1][1] = 0; - int count = points.length; - for (int i = 0; i < count; i++) { - float x = points[i]; - i++; - float y = points[i]; - array[0][0] += x * x; - array[0][1] += x * y; - array[1][0] = array[0][1]; - array[1][1] += y * y; - } - array[0][0] /= (count / 2); - array[0][1] /= (count / 2); - array[1][0] /= (count / 2); - array[1][1] /= (count / 2); - - return array; - } - - static float computeTotalLength(float[] points) { - float sum = 0; - int count = points.length - 4; - for (int i = 0; i < count; i += 2) { - float dx = points[i + 2] - points[i]; - float dy = points[i + 3] - points[i + 1]; - sum += Math.sqrt(dx * dx + dy * dy); - } - return sum; - } - - static double computeStraightness(float[] points) { - float totalLen = computeTotalLength(points); - float dx = points[2] - points[0]; - float dy = points[3] - points[1]; - return Math.sqrt(dx * dx + dy * dy) / totalLen; - } - - static double computeStraightness(float[] points, float totalLen) { - float dx = points[2] - points[0]; - float dy = points[3] - points[1]; - return Math.sqrt(dx * dx + dy * dy) / totalLen; - } - - /** - * Calculate the squared Euclidean distance between two vectors - * - * @param vector1 - * @param vector2 - * @return the distance - */ - static double squaredEuclideanDistance(float[] vector1, float[] vector2) { - double squaredDistance = 0; - int size = vector1.length; - for (int i = 0; i < size; i++) { - float difference = vector1[i] - vector2[i]; - squaredDistance += difference * difference; - } - return squaredDistance / size; - } - - /** - * Calculate the cosine distance between two instances - * - * @param vector1 - * @param vector2 - * @return the distance between 0 and Math.PI - */ - static double cosineDistance(float[] vector1, float[] vector2) { - float sum = 0; - int len = vector1.length; - for (int i = 0; i < len; i++) { - sum += vector1[i] * vector2[i]; - } - return Math.acos(sum); - } - - static OrientedBoundingBox computeOrientedBoundingBox(ArrayList<GesturePoint> pts) { - GestureStroke stroke = new GestureStroke(pts); - float[] points = temporalSampling(stroke, TEMPORAL_SAMPLING_RATE); - return computeOrientedBoundingBox(points); - } - - static OrientedBoundingBox computeOrientedBoundingBox(float[] points) { - float[] meanVector = computeCentroid(points); - return computeOrientedBoundingBox(points, meanVector); - } - - static OrientedBoundingBox computeOrientedBoundingBox(float[] points, float[] centroid) { - Matrix tr = new Matrix(); - tr.setTranslate(-centroid[0], -centroid[1]); - tr.mapPoints(points); - - double[][] array = computeCoVariance(points); - double[] targetVector = computeOrientation(array); - - float angle; - if (targetVector[0] == 0 && targetVector[1] == 0) { - angle = -90; - } else { // -PI<alpha<PI - angle = (float) Math.atan2(targetVector[1], targetVector[0]); - angle = (float) (180 * angle / Math.PI); - android.graphics.Matrix trans = new android.graphics.Matrix(); - trans.setRotate(-angle); - trans.mapPoints(points); - } - - float minx = Float.MAX_VALUE; - float miny = Float.MAX_VALUE; - float maxx = Float.MIN_VALUE; - float maxy = Float.MIN_VALUE; - int count = points.length; - for (int i = 0; i < count; i++) { - if (points[i] < minx) { - minx = points[i]; - } - if (points[i] > maxx) { - maxx = points[i]; - } - i++; - if (points[i] < miny) { - miny = points[i]; - } - if (points[i] > maxy) { - maxy = points[i]; - } - } - - return new OrientedBoundingBox(angle, centroid[0], centroid[1], maxx - minx, maxy - miny); - } - - private static double[] computeOrientation(double[][] covarianceMatrix) { - double[] targetVector = new double[2]; - if (covarianceMatrix[0][1] == 0 || covarianceMatrix[1][0] == 0) { - targetVector[0] = 1; - targetVector[1] = 0; - } - - double a = -covarianceMatrix[0][0] - covarianceMatrix[1][1]; - double b = covarianceMatrix[0][0] * covarianceMatrix[1][1] - covarianceMatrix[0][1] - * covarianceMatrix[1][0]; - double value = a / 2; - double rightside = Math.sqrt(Math.pow(value, 2) - b); - double lambda1 = -value + rightside; - double lambda2 = -value - rightside; - if (lambda1 == lambda2) { - targetVector[0] = 0; - targetVector[1] = 0; - } else { - double lambda = lambda1 > lambda2 ? lambda1 : lambda2; - targetVector[0] = 1; - targetVector[1] = (lambda - covarianceMatrix[0][0]) / covarianceMatrix[0][1]; - } - return targetVector; - } -} diff --git a/tests/sketch/src/com/android/gesture/Instance.java b/tests/sketch/src/com/android/gesture/Instance.java deleted file mode 100755 index 502a0fa..0000000 --- a/tests/sketch/src/com/android/gesture/Instance.java +++ /dev/null @@ -1,115 +0,0 @@ -/* - * 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.graphics.Matrix; - -/** - * An instance represents a sample if the label is available or a query if the - * label is null. - */ -class Instance { - private static final int SEQUENCE_SAMPLE_SIZE = 16; - - private static final int PATCH_SAMPLE_SIZE = 16; - - private final static float[] ORIENTATIONS = { - 0, 45, 90, 135, 180, -0, -45, -90, -135, -180 - }; - - // the feature vector - final float[] vector; - - // the label can be null - final String label; - - // the id of the instance - final long id; - - private Instance(long id, float[] sample, String sampleName) { - this.id = id; - vector = sample; - label = sampleName; - } - - private void normalize() { - float[] sample = vector; - float sum = 0; - - int size = sample.length; - for (int i = 0; i < size; i++) { - sum += sample[i] * sample[i]; - } - - float magnitude = (float) Math.sqrt(sum); - for (int i = 0; i < size; i++) { - sample[i] /= magnitude; - } - } - - /** - * create a learning instance for a single stroke gesture - * - * @param gesture - * @param label - * @return the instance - */ - static Instance createInstance(int samplingType, Gesture gesture, String label) { - float[] pts; - Instance instance; - if (samplingType == GestureLibrary.SEQUENCE_SENSITIVE) { - pts = temporalSampler(samplingType, gesture); - instance = new Instance(gesture.getID(), pts, label); - instance.normalize(); - } else { - pts = spatialSampler(gesture); - instance = new Instance(gesture.getID(), pts, label); - } - return instance; - } - - private static float[] spatialSampler(Gesture gesture) { - return GestureUtilities.spatialSampling(gesture, PATCH_SAMPLE_SIZE); - } - - private static float[] temporalSampler(int samplingType, Gesture gesture) { - float[] pts = GestureUtilities.temporalSampling(gesture.getStrokes().get(0), - SEQUENCE_SAMPLE_SIZE); - float[] center = GestureUtilities.computeCentroid(pts); - float orientation = (float) Math.atan2(pts[1] - center[1], pts[0] - center[0]); - orientation *= 180 / Math.PI; - - float adjustment = -orientation; - if (samplingType == GestureLibrary.ORIENTATION_SENSITIVE) { - int count = ORIENTATIONS.length; - for (int i = 0; i < count; i++) { - float delta = ORIENTATIONS[i] - orientation; - if (Math.abs(delta) < Math.abs(adjustment)) { - adjustment = delta; - } - } - } - - Matrix m = new Matrix(); - m.setTranslate(-center[0], -center[1]); - m.postRotate(adjustment); - m.mapPoints(pts); - - return pts; - } - -} diff --git a/tests/sketch/src/com/android/gesture/InstanceLearner.java b/tests/sketch/src/com/android/gesture/InstanceLearner.java deleted file mode 100644 index 4495256..0000000 --- a/tests/sketch/src/com/android/gesture/InstanceLearner.java +++ /dev/null @@ -1,105 +0,0 @@ -/* - * 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.util.Config; -import android.util.Log; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.Comparator; -import java.util.Iterator; -import java.util.TreeMap; - -/** - * An implementation of an instance-based learner - */ - -class InstanceLearner extends Learner { - - private static final String LOGTAG = "InstanceLearner"; - - @Override - ArrayList<Prediction> classify(int gestureType, float[] vector) { - ArrayList<Prediction> predictions = new ArrayList<Prediction>(); - ArrayList<Instance> instances = getInstances(); - int count = instances.size(); - TreeMap<String, Double> label2score = new TreeMap<String, Double>(); - for (int i = 0; i < count; i++) { - Instance sample = instances.get(i); - if (sample.vector.length != vector.length) { - continue; - } - double distance; - if (gestureType == GestureLibrary.SEQUENCE_SENSITIVE) { - distance = GestureUtilities.cosineDistance(sample.vector, vector); - } else { - distance = GestureUtilities.squaredEuclideanDistance(sample.vector, vector); - } - double weight; - if (distance == 0) { - weight = Double.MAX_VALUE; - } else { - weight = 1 / distance; - } - Double score = label2score.get(sample.label); - if (score == null || weight > score) { - label2score.put(sample.label, weight); - } - } - - double sum = 0; - Iterator<String> lableIterator = label2score.keySet().iterator(); - while (lableIterator.hasNext()) { - String name = lableIterator.next(); - double score = label2score.get(name); - sum += score; - predictions.add(new Prediction(name, score)); - } - - // normalize - Iterator<Prediction> predictionIterator = predictions.iterator(); - while (predictionIterator.hasNext()) { - Prediction name = predictionIterator.next(); - name.score /= sum; - } - - Collections.sort(predictions, new Comparator<Prediction>() { - public int compare(Prediction object1, Prediction object2) { - double score1 = object1.score; - double score2 = object2.score; - if (score1 > score2) { - return -1; - } else if (score1 < score2) { - return 1; - } else { - return 0; - } - } - }); - - if (Config.DEBUG) { - predictionIterator = predictions.iterator(); - while (predictionIterator.hasNext()) { - Prediction name = predictionIterator.next(); - Log.v(LOGTAG, "prediction [" + name.name + " = " + name.score + "]"); - } - } - - return predictions; - } -} diff --git a/tests/sketch/src/com/android/gesture/Learner.java b/tests/sketch/src/com/android/gesture/Learner.java deleted file mode 100755 index 15b2053..0000000 --- a/tests/sketch/src/com/android/gesture/Learner.java +++ /dev/null @@ -1,83 +0,0 @@ -/* - * 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 java.util.ArrayList; - -/** - * The abstract class of a gesture learner - */ -abstract class Learner { - private final ArrayList<Instance> mInstances = new ArrayList<Instance>(); - - /** - * Add an instance to the learner - * - * @param instance - */ - void addInstance(Instance instance) { - mInstances.add(instance); - } - - /** - * Retrieve all the instances - * - * @return instances - */ - ArrayList<Instance> getInstances() { - return mInstances; - } - - /** - * Remove an instance based on its id - * - * @param id - */ - void removeInstance(long id) { - ArrayList<Instance> instances = mInstances; - int count = instances.size(); - for (int i = 0; i < count; i++) { - Instance instance = instances.get(i); - if (id == instance.id) { - instances.remove(instance); - return; - } - } - } - - /** - * Remove all the instances of a category - * - * @param name the category name - */ - void removeInstances(String name) { - final ArrayList<Instance> toDelete = new ArrayList<Instance>(); - final ArrayList<Instance> instances = mInstances; - final int count = instances.size(); - - for (int i = 0; i < count; i++) { - final Instance instance = instances.get(i); - // the label can be null, as specified in Instance - if ((instance.label == null && name == null) || instance.label.equals(name)) { - toDelete.add(instance); - } - } - instances.removeAll(toDelete); - } - - abstract ArrayList<Prediction> classify(int gestureType, float[] vector); -} diff --git a/tests/sketch/src/com/android/gesture/LetterRecognizer.java b/tests/sketch/src/com/android/gesture/LetterRecognizer.java deleted file mode 100644 index 07a5f31..0000000 --- a/tests/sketch/src/com/android/gesture/LetterRecognizer.java +++ /dev/null @@ -1,228 +0,0 @@ -/* - * Copyright (C) 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.content.res.Resources; -import android.util.Log; - -import java.io.BufferedInputStream; -import java.io.DataInputStream; -import java.io.IOException; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Comparator; -import java.util.HashMap; - -import static com.android.gesture.GestureConstants.LOG_TAG; - -public class LetterRecognizer { - public final static int LATIN_LOWERCASE = 0; - - private SigmoidUnit[] mHiddenLayer; - private SigmoidUnit[] mOutputLayer; - - private final String[] mClasses; - - private final int mPatchSize; - - static final String GESTURE_FILE_NAME = "letters.gestures"; - - private GestureLibrary mGestureLibrary; - private final static int ADJUST_RANGE = 3; - - private static class SigmoidUnit { - final float[] mWeights; - - SigmoidUnit(float[] weights) { - mWeights = weights; - } - - private float compute(float[] inputs) { - float sum = 0; - - final int count = inputs.length; - final float[] weights = mWeights; - - for (int i = 0; i < count; i++) { - sum += inputs[i] * weights[i]; - } - sum += weights[weights.length - 1]; - - return 1.0f / (float) (1 + Math.exp(-sum)); - } - } - - private LetterRecognizer(int numOfInput, int numOfHidden, String[] classes) { - mPatchSize = (int)Math.sqrt(numOfInput); - mHiddenLayer = new SigmoidUnit[numOfHidden]; - mClasses = classes; - mOutputLayer = new SigmoidUnit[classes.length]; - } - - public void save() { - mGestureLibrary.save(); - } - - public static LetterRecognizer getLetterRecognizer(Context context, int type) { - switch (type) { - case LATIN_LOWERCASE: { - return createFromResource(context, com.android.internal.R.raw.latin_lowercase); - } - } - return null; - } - - public ArrayList<Prediction> recognize(Gesture gesture) { - float[] query = GestureUtilities.spatialSampling(gesture, mPatchSize); - ArrayList<Prediction> predictions = classify(query); - if (mGestureLibrary != null) { - adjustPrediction(gesture, predictions); - } - return predictions; - } - - private ArrayList<Prediction> classify(float[] vector) { - final float[] intermediateOutput = compute(mHiddenLayer, vector); - final float[] output = compute(mOutputLayer, intermediateOutput); - final ArrayList<Prediction> predictions = new ArrayList<Prediction>(); - - double sum = 0; - - final String[] classes = mClasses; - final int count = classes.length; - - for (int i = 0; i < count; i++) { - double score = output[i]; - sum += score; - predictions.add(new Prediction(classes[i], score)); - } - - for (int i = 0; i < count; i++) { - predictions.get(i).score /= sum; - } - - Collections.sort(predictions, new Comparator<Prediction>() { - public int compare(Prediction object1, Prediction object2) { - double score1 = object1.score; - double score2 = object2.score; - if (score1 > score2) { - return -1; - } else if (score1 < score2) { - return 1; - } else { - return 0; - } - } - }); - return predictions; - } - - private float[] compute(SigmoidUnit[] layer, float[] input) { - final float[] output = new float[layer.length]; - final int count = layer.length; - - for (int i = 0; i < count; i++) { - output[i] = layer[i].compute(input); - } - - return output; - } - - private static LetterRecognizer createFromResource(Context context, int resourceID) { - final Resources resources = context.getResources(); - - DataInputStream in = null; - LetterRecognizer classifier = null; - - try { - in = new DataInputStream(new BufferedInputStream(resources.openRawResource(resourceID), - GestureConstants.IO_BUFFER_SIZE)); - - final int iCount = in.readInt(); - final int hCount = in.readInt(); - final int oCount = in.readInt(); - - final String[] classes = new String[oCount]; - for (int i = 0; i < classes.length; i++) { - classes[i] = in.readUTF(); - } - - classifier = new LetterRecognizer(iCount, hCount, classes); - SigmoidUnit[] hiddenLayer = new SigmoidUnit[hCount]; - SigmoidUnit[] outputLayer = new SigmoidUnit[oCount]; - - for (int i = 0; i < hCount; i++) { - float[] weights = new float[iCount + 1]; - for (int j = 0; j <= iCount; j++) { - weights[j] = in.readFloat(); - } - hiddenLayer[i] = new SigmoidUnit(weights); - } - - for (int i = 0; i < oCount; i++) { - float[] weights = new float[hCount + 1]; - for (int j = 0; j <= hCount; j++) { - weights[j] = in.readFloat(); - } - outputLayer[i] = new SigmoidUnit(weights); - } - - classifier.mHiddenLayer = hiddenLayer; - classifier.mOutputLayer = outputLayer; - - } catch (IOException e) { - Log.d(LOG_TAG, "Failed to load handwriting data:", e); - } finally { - GestureUtilities.closeStream(in); - } - - return classifier; - } - - public void enablePersonalization(boolean enable) { - if (enable) { - mGestureLibrary = new GestureLibrary(GESTURE_FILE_NAME); - mGestureLibrary.setSequenceType(GestureLibrary.SEQUENCE_INVARIANT); - mGestureLibrary.load(); - } else { - mGestureLibrary = null; - } - } - - public void addExample(String letter, Gesture example) { - mGestureLibrary.addGesture(letter, example); - } - - private void adjustPrediction(Gesture query, ArrayList<Prediction> predictions) { - ArrayList<Prediction> results = mGestureLibrary.recognize(query); - HashMap<String, Prediction> topNList = new HashMap<String, Prediction>(); - for (int j = 0; j < ADJUST_RANGE; j++) { - Prediction prediction = predictions.remove(0); - topNList.put(prediction.name, prediction); - } - int count = results.size(); - for (int j = count - 1; j >= 0 && !topNList.isEmpty(); j--) { - Prediction item = results.get(j); - Prediction original = topNList.get(item.name); - if (original != null) { - predictions.add(0, original); - topNList.remove(item.name); - } - } - } -} diff --git a/tests/sketch/src/com/android/gesture/OrientedBoundingBox.java b/tests/sketch/src/com/android/gesture/OrientedBoundingBox.java deleted file mode 100644 index a07d125..0000000 --- a/tests/sketch/src/com/android/gesture/OrientedBoundingBox.java +++ /dev/null @@ -1,80 +0,0 @@ -/* - * 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.graphics.Matrix; -import android.graphics.Path; - -/** - * An oriented bounding box - */ -public class OrientedBoundingBox { - public final float squareness; - - public final float width; - public final float height; - - public final float orientation; - - public final float centerX; - public final float centerY; - - OrientedBoundingBox(float angle, float cx, float cy, float w, float h) { - orientation = angle; - width = w; - height = h; - centerX = cx; - centerY = cy; - float ratio = w / h; - if (ratio > 1) { - squareness = 1 / ratio; - } else { - squareness = ratio; - } - } - - public Path toPath() { - Path path = new Path(); - float[] point = new float[2]; - point[0] = -width / 2; - point[1] = height / 2; - Matrix matrix = new Matrix(); - matrix.setRotate(orientation); - matrix.postTranslate(centerX, centerY); - matrix.mapPoints(point); - path.moveTo(point[0], point[1]); - - point[0] = -width / 2; - point[1] = -height / 2; - matrix.mapPoints(point); - path.lineTo(point[0], point[1]); - - point[0] = width / 2; - point[1] = -height / 2; - matrix.mapPoints(point); - path.lineTo(point[0], point[1]); - - point[0] = width / 2; - point[1] = height / 2; - matrix.mapPoints(point); - path.lineTo(point[0], point[1]); - - path.close(); - - return path; - } -} diff --git a/tests/sketch/src/com/android/gesture/Prediction.java b/tests/sketch/src/com/android/gesture/Prediction.java deleted file mode 100755 index 92d3ba4..0000000 --- a/tests/sketch/src/com/android/gesture/Prediction.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * 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; - -public class Prediction { - public final String name; - - public double score; - - Prediction(String label, double predictionScore) { - name = label; - score = predictionScore; - } - - @Override - public String toString() { - return name; - } -} diff --git a/tests/sketch/src/com/android/gesture/TouchThroughGesturing.java b/tests/sketch/src/com/android/gesture/TouchThroughGesturing.java deleted file mode 100644 index fc878c8..0000000 --- a/tests/sketch/src/com/android/gesture/TouchThroughGesturing.java +++ /dev/null @@ -1,165 +0,0 @@ -/* - * 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.graphics.Color; -import android.view.MotionEvent; -import android.view.View; - -import java.util.ArrayList; - -/** - * TouchThroughGesturing implements the interaction behavior that allows a user - * to gesture over a regular UI widget such as ListView and at the same time, - * still allows a user to perform basic interactions (clicking, scrolling and panning) - * with the underlying widget. - */ - -public class TouchThroughGesturing implements GestureListener { - public static final int SINGLE_STROKE = 0; - public static final int MULTIPLE_STROKE = 1; - - private static final float STROKE_LENGTH_THRESHOLD = 30; - private static final float SQUARENESS_THRESHOLD = 0.275f; - private static final float ANGLE_THRESHOLD = 40; - - private static final boolean STEAL_EVENTS = false; - - public static final int DEFAULT_UNCERTAIN_GESTURE_COLOR = Color.argb(60, 255, 255, 0); - - private boolean mIsGesturing = false; - - private float mTotalLength; - - private float mX; - private float mY; - - // TODO: Use WeakReference? - private View mModel; - - private int mGestureType = SINGLE_STROKE; - private int mUncertainGestureColor = DEFAULT_UNCERTAIN_GESTURE_COLOR; - - // TODO: Use WeakReferences - private final ArrayList<GestureActionListener> mActionListeners = - new ArrayList<GestureActionListener>(); - - public TouchThroughGesturing(View model) { - mModel = model; - } - - /** - * - * @param type SINGLE_STROKE or MULTIPLE_STROKE - */ - public void setGestureType(int type) { - mGestureType = type; - } - - public void setUncertainGestureColor(int color) { - mUncertainGestureColor = color; - } - - public void onStartGesture(GestureOverlay overlay, MotionEvent event) { - if (mGestureType == MULTIPLE_STROKE) { - overlay.cancelFadingOut(); - } - - mX = event.getX(); - mY = event.getY(); - mTotalLength = 0; - mIsGesturing = false; - - if (mGestureType == SINGLE_STROKE || overlay.getCurrentGesture() == null - || overlay.getCurrentGesture().getStrokesCount() == 0) { - overlay.setGestureColor(mUncertainGestureColor); - } - - mModel.dispatchTouchEvent(event); - } - - public void onGesture(GestureOverlay overlay, MotionEvent event) { - //noinspection PointlessBooleanExpression - if (!STEAL_EVENTS) { - mModel.dispatchTouchEvent(event); - } - - if (mIsGesturing) { - return; - } - - final float x = event.getX(); - final float y = event.getY(); - final float dx = x - mX; - final float dy = y - mY; - - mTotalLength += (float)Math.sqrt(dx * dx + dy * dy); - mX = x; - mY = y; - - if (mTotalLength > STROKE_LENGTH_THRESHOLD) { - final OrientedBoundingBox box = - GestureUtilities.computeOrientedBoundingBox(overlay.getCurrentStroke()); - float angle = Math.abs(box.orientation); - if (angle > 90) { - angle = 180 - angle; - } - if (box.squareness > SQUARENESS_THRESHOLD || angle < ANGLE_THRESHOLD) { - mIsGesturing = true; - overlay.setGestureColor(GestureOverlay.DEFAULT_GESTURE_COLOR); - if (STEAL_EVENTS) { - event = MotionEvent.obtain(event.getDownTime(), System.currentTimeMillis(), - MotionEvent.ACTION_UP, x, y, event.getPressure(), event.getSize(), - event.getMetaState(), event.getXPrecision(), event.getYPrecision(), - event.getDeviceId(), event.getEdgeFlags()); - } - } - } - - if (STEAL_EVENTS) { - mModel.dispatchTouchEvent(event); - } - } - - public void onFinishGesture(GestureOverlay overlay, MotionEvent event) { - if (mIsGesturing) { - overlay.clear(true); - - final ArrayList<GestureActionListener> listeners = mActionListeners; - final int count = listeners.size(); - - for (int i = 0; i < count; i++) { - listeners.get(i).onGesturePerformed(overlay, overlay.getCurrentGesture()); - } - } else { - mModel.dispatchTouchEvent(event); - overlay.clear(false); - } - } - - public void addGestureActionListener(GestureActionListener listener) { - mActionListeners.add(listener); - } - - public void removeGestureActionListener(GestureActionListener listener) { - mActionListeners.remove(listener); - } - - public boolean isGesturing() { - return mIsGesturing; - } -} diff --git a/tests/sketch/src/com/android/gesture/example/ContactListGestureOverlay.java b/tests/sketch/src/com/android/gesture/example/ContactListGestureOverlay.java index 6eb2f23..eda4224 100644 --- a/tests/sketch/src/com/android/gesture/example/ContactListGestureOverlay.java +++ b/tests/sketch/src/com/android/gesture/example/ContactListGestureOverlay.java @@ -30,12 +30,11 @@ import android.view.Window; import android.widget.AdapterView; import android.widget.ListView; -import com.android.gesture.Gesture; -import com.android.gesture.GestureActionListener; -import com.android.gesture.GestureOverlay; -import com.android.gesture.LetterRecognizer; -import com.android.gesture.Prediction; -import com.android.gesture.TouchThroughGesturing; +import android.gesture.Gesture; +import android.gesture.GestureOverlayView; +import android.gesture.LetterRecognizer; +import android.gesture.Prediction; +import android.gesture.TouchThroughGestureListener; import java.util.ArrayList; @@ -52,7 +51,7 @@ public class ContactListGestureOverlay extends Activity { private ContactAdapter mContactAdapter; - private TouchThroughGesturing mGestureProcessor; + private TouchThroughGestureListener mGestureProcessor; private LetterRecognizer mRecognizer; @@ -67,7 +66,7 @@ public class ContactListGestureOverlay extends Activity { setProgressBarIndeterminateVisibility(true); // create a letter recognizer - mRecognizer = LetterRecognizer.getLetterRecognizer(this, LetterRecognizer.LATIN_LOWERCASE); + mRecognizer = LetterRecognizer.getLetterRecognizer(this, LetterRecognizer.RECOGNIZER_LATIN_LOWERCASE); // load the contact list mContactList = (ListView) findViewById(R.id.list); @@ -95,11 +94,11 @@ public class ContactListGestureOverlay extends Activity { setProgressBarIndeterminateVisibility(false); // add a gesture overlay on top of the ListView - GestureOverlay overlay = new GestureOverlay(this); - mGestureProcessor = new TouchThroughGesturing(mContactList); - mGestureProcessor.setGestureType(TouchThroughGesturing.MULTIPLE_STROKE); - mGestureProcessor.addGestureActionListener(new GestureActionListener() { - public void onGesturePerformed(GestureOverlay overlay, Gesture gesture) { + GestureOverlayView overlay = new GestureOverlayView(this); + mGestureProcessor = new TouchThroughGestureListener(mContactList); + mGestureProcessor.setGestureType(TouchThroughGestureListener.MULTIPLE_STROKE); + mGestureProcessor.addOnGestureActionListener(new TouchThroughGestureListener.OnGesturePerformedListener() { + public void onGesturePerformed(GestureOverlayView overlay, Gesture gesture) { ArrayList<Prediction> predictions = mRecognizer.recognize(gesture); if (!predictions.isEmpty()) { Log.v(LOGTAG, "1st Prediction : " + predictions.get(0).name); @@ -112,7 +111,7 @@ public class ContactListGestureOverlay extends Activity { } } }); - overlay.addGestureListener(mGestureProcessor); + overlay.addOnGestureListener(mGestureProcessor); ViewGroup.LayoutParams params = new ViewGroup.LayoutParams( ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.FILL_PARENT); this.addContentView(overlay, params); diff --git a/tests/sketch/src/com/android/gesture/example/GestureEntry.java b/tests/sketch/src/com/android/gesture/example/GestureEntry.java index 53ba481..200f89f 100644 --- a/tests/sketch/src/com/android/gesture/example/GestureEntry.java +++ b/tests/sketch/src/com/android/gesture/example/GestureEntry.java @@ -34,12 +34,11 @@ import android.widget.ArrayAdapter; import android.widget.EditText; import android.widget.Spinner; import android.widget.AdapterView.OnItemSelectedListener; +import android.gesture.Gesture; -import com.android.gesture.Gesture; -import com.android.gesture.GestureLibrary; -import com.android.gesture.GestureListener; -import com.android.gesture.GestureOverlay; -import com.android.gesture.Prediction; +import android.gesture.GestureLibrary; +import android.gesture.GestureOverlayView; +import android.gesture.Prediction; import java.io.File; import java.util.ArrayList; @@ -57,7 +56,7 @@ public class GestureEntry extends Activity { private static final int VIEW_ID = Menu.FIRST + 1; - private GestureOverlay mGesturePad; + private GestureOverlayView mGesturePad; private Spinner mRecognitionResult; @@ -96,17 +95,17 @@ public class GestureEntry extends Activity { }); // create the area for drawing a gesture - mGesturePad = (GestureOverlay) findViewById(R.id.drawingpad); + mGesturePad = (GestureOverlayView) findViewById(R.id.drawingpad); mGesturePad.setBackgroundColor(Color.BLACK); - mGesturePad.addGestureListener(new GestureListener() { - public void onFinishGesture(GestureOverlay overlay, MotionEvent event) { + mGesturePad.addOnGestureListener(new GestureOverlayView.OnGestureListener() { + public void onGestureEnded(GestureOverlayView overlay, MotionEvent event) { recognize(overlay.getCurrentGesture()); } - public void onGesture(GestureOverlay overlay, MotionEvent event) { + public void onGesture(GestureOverlayView overlay, MotionEvent event) { } - public void onStartGesture(GestureOverlay overlay, MotionEvent event) { + public void onGestureStarted(GestureOverlayView overlay, MotionEvent event) { overlay.clear(false); } }); diff --git a/tests/sketch/src/com/android/gesture/example/GestureLibViewer.java b/tests/sketch/src/com/android/gesture/example/GestureLibViewer.java index ca54110..aa07e7b 100755 --- a/tests/sketch/src/com/android/gesture/example/GestureLibViewer.java +++ b/tests/sketch/src/com/android/gesture/example/GestureLibViewer.java @@ -26,10 +26,10 @@ import android.widget.ArrayAdapter; import android.widget.Button; import android.widget.Spinner; import android.widget.AdapterView.OnItemSelectedListener; +import android.gesture.Gesture; -import com.android.gesture.Gesture; -import com.android.gesture.GestureLibrary; -import com.android.gesture.GestureOverlay; +import android.gesture.GestureLibrary; +import android.gesture.GestureOverlayView; import java.util.ArrayList; import java.util.Collections; @@ -41,7 +41,7 @@ import java.util.Collections; public class GestureLibViewer extends Activity { - private GestureOverlay mGesturePad; + private GestureOverlayView mGesturePad; private Spinner mGestureCategory; @@ -90,7 +90,7 @@ public class GestureLibViewer extends Activity { setContentView(R.layout.gestureviewer); // create the area for drawing a gesture - mGesturePad = (GestureOverlay) findViewById(R.id.drawingpad); + mGesturePad = (GestureOverlayView) findViewById(R.id.drawingpad); mGesturePad.setEnabled(false); // init the gesture library |