diff options
29 files changed, 712 insertions, 3060 deletions
diff --git a/tests/sketch/AndroidManifest.xml b/tests/sketch/AndroidManifest.xml index 1f4333c5d86a..c44b54e5e201 100755 --- a/tests/sketch/AndroidManifest.xml +++ b/tests/sketch/AndroidManifest.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2008-2009 The Android Open Source Project +<!-- Copyright (C) 2008 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. @@ -14,12 +14,11 @@ limitations under the License. --> <manifest xmlns:android="http://schemas.android.com/apk/res/android" - package="com.android.gesture.example" + package="com.android.gesture" android:versionCode="1" android:versionName="1.0.0"> - <uses-permission android:name="android.permission.READ_CONTACTS" /> <application android:icon="@drawable/icon" android:label="@string/app_name"> - <activity android:name="com.android.gesture.example.GestureEntry" + <activity android:name="com.android.gesture.example.GestureEntryDemo" android:label="@string/app_name"> <intent-filter> <action android:name="android.intent.action.MAIN" /> @@ -27,12 +26,5 @@ </intent-filter> </activity> <activity android:name="com.android.gesture.example.GestureLibViewer"/> - <activity android:name="com.android.gesture.example.ContactListGestureOverlay" - android:label="@string/overlay_name"> - <intent-filter> - <action android:name="android.intent.action.MAIN" /> - <category android:name="android.intent.category.LAUNCHER" /> - </intent-filter> - </activity> </application> </manifest> diff --git a/tests/sketch/res/layout/demo.xml b/tests/sketch/res/layout/demo.xml index 8c9161ae2429..e516229234d9 100644..100755 --- a/tests/sketch/res/layout/demo.xml +++ b/tests/sketch/res/layout/demo.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2009 The Android Open Source Project +<!-- Copyright (C) 2008 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. @@ -13,7 +13,6 @@ See the License for the specific language governing permissions and limitations under the License. --> - <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" @@ -25,7 +24,7 @@ android:drawSelectorOnTop="true" android:prompt="@string/recognition_result"/> - <com.android.gesture.GestureOverlay + <com.android.gesture.GesturePad android:id="@+id/drawingpad" android:layout_width="fill_parent" android:layout_height="wrap_content" diff --git a/tests/sketch/res/layout/gestureviewer.xml b/tests/sketch/res/layout/gestureviewer.xml index 73d6a357d204..5302d34cd253 100644..100755 --- a/tests/sketch/res/layout/gestureviewer.xml +++ b/tests/sketch/res/layout/gestureviewer.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2009 The Android Open Source Project +<!-- Copyright (C) 2008 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. @@ -13,7 +13,6 @@ See the License for the specific language governing permissions and limitations under the License. --> - <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" @@ -26,7 +25,7 @@ android:drawSelectorOnTop="true" android:prompt="@string/recognition_result"/> - <com.android.gesture.GestureOverlay + <com.android.gesture.GesturePad android:id="@+id/drawingpad" android:layout_width="fill_parent" android:layout_height="wrap_content" diff --git a/tests/sketch/res/layout/newgesture_dialog.xml b/tests/sketch/res/layout/newgesture_dialog.xml index 91e76458bd77..6e45d81a424d 100644..100755 --- a/tests/sketch/res/layout/newgesture_dialog.xml +++ b/tests/sketch/res/layout/newgesture_dialog.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2009 The Android Open Source Project +<!-- Copyright (C) 2008 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. diff --git a/tests/sketch/res/layout/overlaydemo.xml b/tests/sketch/res/layout/overlaydemo.xml deleted file mode 100644 index b6bbab33ee13..000000000000 --- a/tests/sketch/res/layout/overlaydemo.xml +++ /dev/null @@ -1,12 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" - android:orientation="vertical" - android:layout_width="fill_parent" - android:layout_height="fill_parent" - > - <ListView - android:id="@+id/list" - android:layout_width="fill_parent" - android:layout_height="0dip" - android:layout_weight="1"/> -</LinearLayout> diff --git a/tests/sketch/res/values/strings.xml b/tests/sketch/res/values/strings.xml index 42f14da8818c..4c6aa205ae3d 100755 --- a/tests/sketch/res/values/strings.xml +++ b/tests/sketch/res/values/strings.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2009 The Android Open Source Project +<!-- Copyright (C) 2008 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. @@ -15,7 +15,6 @@ --> <resources> <string name="app_name">Gesture Demo</string> - <string name="overlay_name">Overlay Demo</string> <string name="recognition_result">Recognition Result</string> <string name="clear">Clear</string> <string name="newgesture">Add</string> diff --git a/tests/sketch/src/com/android/gesture/Gesture.java b/tests/sketch/src/com/android/gesture/Gesture.java index a5e7a2556a91..29c07adbc18a 100755 --- a/tests/sketch/src/com/android/gesture/Gesture.java +++ b/tests/sketch/src/com/android/gesture/Gesture.java @@ -18,290 +18,343 @@ package com.android.gesture; import android.graphics.Bitmap; import android.graphics.Canvas; +import android.graphics.Matrix; import android.graphics.Paint; import android.graphics.Path; +import android.graphics.PointF; import android.graphics.RectF; import android.os.Parcel; import android.os.Parcelable; +import com.android.gesture.recognizer.RecognitionUtil; + import org.xmlpull.v1.XmlSerializer; import java.io.IOException; import java.util.ArrayList; +import java.util.Iterator; +import java.util.StringTokenizer; /** - * A gesture can have a single or multiple strokes + * A single stroke gesture. */ 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 ArrayList<GestureStroke> mStrokes = new ArrayList<GestureStroke>(); + private RectF mBBX; + private float mLength = 0; + private int mColor; + private float mWidth; + private ArrayList<PointF> mPtsBuffer = new ArrayList<PointF>(); + private long mTimestamp = 0; + private long mID; + + private static final long systemStartupTime = System.currentTimeMillis(); + private static int instanceCount = 0; public Gesture() { - mGestureID = GESTURE_ID_BASE + sGestureCount++; + mID = systemStartupTime + instanceCount++; } - /** - * @return all the strokes of the gesture - */ - public ArrayList<GestureStroke> getStrokes() { - return mStrokes; + public void setColor(int c) { + mColor = c; } - - /** - * @return the number of strokes included by this gesture - */ - public int getStrokesCount() { - return mStrokes.size(); + + public void setStrokeWidth(float w) { + mWidth = w; + } + + public int getColor() { + return mColor; + } + + public float getStrokeWidth() { + return mWidth; + } + + public ArrayList<PointF> getPoints() { + return this.mPtsBuffer; + } + + public int numOfPoints() { + return this.mPtsBuffer.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); + public void addPoint(float x, float y) { + mPtsBuffer.add(new PointF(x, y)); + if (mBBX == null) { + mBBX = new RectF(); + mBBX.top = y; + mBBX.left = x; + mBBX.right = x; + mBBX.bottom = y; + mLength = 0; + } + else { + PointF lst = mPtsBuffer.get(mPtsBuffer.size()-2); + mLength += Math.sqrt(Math.pow(x-lst.x, 2)+Math.pow(y-lst.y, 2)); + mBBX.union(x, y); } + mTimestamp = System.currentTimeMillis(); } /** - * 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; - ArrayList<GestureStroke> strokes = mStrokes; - int count = strokes.size(); - for (int i = 0; i < count; i++) { - GestureStroke stroke = strokes.get(i); - len += stroke.length; - } - return len; + return this.mLength; } - - /** - * @return the bounding box of the gesture - */ - public RectF getBoundingBox() { - return mBoundingBox; + + public RectF getBBX() { + return mBBX; } - - /** - * Set the id of the gesture - * - * @param id - */ - void setID(long id) { - mGestureID = id; + + public void setID(long id) { + mID = id; } - - /** - * @return the id of the gesture - */ + public long getID() { - return mGestureID; + return mID; } - + + public long getTimeStamp() { + return mTimestamp; + } + + public void setTimestamp(long t) { + this.mTimestamp = t; + } + /** * draw the gesture - * * @param canvas */ - void draw(Canvas canvas, Paint paint) { - ArrayList<GestureStroke> strokes = mStrokes; - int count = strokes.size(); - for (int i = 0; i < count; i++) { - GestureStroke stroke = strokes.get(i); - stroke.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) { - RectF bbx = getBoundingBox(); - Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); - Canvas canvas = new Canvas(bitmap); - canvas.translate(edge, edge); + public void draw(Canvas canvas) { Paint paint = new Paint(); - paint.setAntiAlias(BITMAP_RENDERING_ANTIALIAS); - paint.setDither(BITMAP_RENDERING_DITHER); - paint.setColor(color); + paint.setAntiAlias(true); + paint.setDither(true); + paint.setColor(mColor); paint.setStyle(Paint.Style.STROKE); paint.setStrokeJoin(Paint.Join.ROUND); paint.setStrokeCap(Paint.Cap.ROUND); - paint.setStrokeWidth(BITMAP_RENDERING_WIDTH); - ArrayList<GestureStroke> strokes = mStrokes; - int count = strokes.size(); - for (int i = 0; i < count; i++) { - GestureStroke stroke = strokes.get(i); - Path path = stroke.toPath(width - 2 * edge, height - 2 * edge, numSample); - canvas.drawPath(path, paint); + paint.setStrokeWidth(mWidth); + + Path path = null; + float mX = 0, mY = 0; + Iterator<PointF> it = mPtsBuffer.iterator(); + while (it.hasNext()) { + PointF p = it.next(); + float x = p.x; + float y = p.y; + 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; + } + } } - - return bitmap; + + canvas.drawPath(path, paint); } - + /** - * Create a bitmap of the gesture with a transparent background - * - * @param width - * @param height + * convert the gesture to a Path + * @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 num of points needed + * @return the path + */ + public Path toPath(float width, float height, int numSample) { + float[] pts = RecognitionUtil.resample(this, numSample); + RectF rect = this.getBBX(); + float scale = height / rect.height(); + Matrix matrix = new Matrix(); + matrix.setTranslate(-rect.left, -rect.top); + Matrix scalem = new Matrix(); + scalem.setScale(scale, scale); + matrix.postConcat(scalem); + Matrix translate = new Matrix(); + matrix.postConcat(translate); + matrix.mapPoints(pts); + + Path path = null; + float mX = 0, mY = 0; + for (int i=0; i<pts.length-1; 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 >= 3 || dy >= 3) { + path.quadTo(mX, mY, (x + mX)/2, (y + mY)/2); + mX = x; + mY = y; + } + } + } + return path; + } + + /** + * get a bitmap thumbnail of the gesture with a transparent background + * @param w + * @param h * @param edge - * @param color - * @return the bitmap + * @param numSample + * @param foreground + * @return */ - public Bitmap toBitmap(int width, int height, int edge, int color) { - RectF bbx = getBoundingBox(); - Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); - Canvas canvas = new Canvas(bitmap); - canvas.translate(edge, edge); + public Bitmap toBitmap(int w, int h, + int edge, int numSample) { + RectF bbx = this.getBBX(); + Bitmap bitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888); + Path path = this.toPath(w - 2 * edge, h - 2 * edge, numSample); + Canvas c = new Canvas(bitmap); + //c.drawColor(background); + c.translate(edge, edge); Paint paint = new Paint(); - paint.setAntiAlias(BITMAP_RENDERING_ANTIALIAS); - paint.setDither(BITMAP_RENDERING_DITHER); - paint.setColor(color); + paint.setAntiAlias(true); + paint.setDither(true); + paint.setColor(mColor); paint.setStyle(Paint.Style.STROKE); paint.setStrokeJoin(Paint.Join.ROUND); paint.setStrokeCap(Paint.Cap.ROUND); - paint.setStrokeWidth(BITMAP_RENDERING_WIDTH); - ArrayList<GestureStroke> strokes = mStrokes; - int count = strokes.size(); - for (int i = 0; i < count; i++) { - GestureStroke stroke = strokes.get(i); - stroke.draw(canvas, paint); - } - + paint.setStrokeWidth(2); + c.drawPath(path, paint); return bitmap; } - + /** - * Save the gesture as XML - * + * save the gesture as XML * @param namespace * @param serializer * @throws IOException */ - void toXML(String namespace, XmlSerializer serializer) throws IOException { - serializer.startTag(namespace, GestureConstants.XML_TAG_GESTURE); - serializer.attribute(namespace, GestureConstants.XML_TAG_ID, Long.toString(mGestureID)); - ArrayList<GestureStroke> strokes = mStrokes; - int count = strokes.size(); - for (int i = 0; i < count; i++) { - GestureStroke stroke = strokes.get(i); - stroke.toXML(namespace, serializer); + public void toXML(String namespace, XmlSerializer serializer) throws IOException { + serializer.startTag(namespace, "stroke"); + serializer.attribute(namespace, "timestamp", Long.toString(mTimestamp)); + serializer.attribute(namespace, "id", Long.toString(mID)); + serializer.attribute(namespace, "color", Integer.toString(mColor)); + serializer.attribute(namespace, "width", Float.toString(mWidth)); + Iterator it = this.mPtsBuffer.iterator(); + String pts = ""; + while (it.hasNext()) { + PointF fp = (PointF)it.next(); + if (pts.length() > 0) + pts += ","; + pts += fp.x + "," + fp.y; } - serializer.endTag(namespace, GestureConstants.XML_TAG_GESTURE); + serializer.text(pts); + serializer.endTag(namespace, "stroke"); } - - /** - * Create the gesture from a string - * - * @param str - */ + + public void createFromString(String str) { - int startIndex = 0; - int endIndex; - while ((endIndex = str.indexOf(GestureConstants.STRING_GESTURE_DELIIMITER, startIndex + 1)) != -1) { - String token = str.substring(startIndex, endIndex); - if (startIndex > 0) { // stroke tokens - addStroke(GestureStroke.createFromString(token)); - } else { // id token - mGestureID = Long.parseLong(token); - } - startIndex = endIndex + 1; + StringTokenizer st = new StringTokenizer(str, "#"); + + String para = st.nextToken(); + StringTokenizer innerst = new StringTokenizer(para, ","); + this.mBBX = new RectF(); + this.mBBX.left = Float.parseFloat(innerst.nextToken()); + this.mBBX.top = Float.parseFloat(innerst.nextToken()); + this.mBBX.right = Float.parseFloat(innerst.nextToken()); + this.mBBX.bottom = Float.parseFloat(innerst.nextToken()); + + para = st.nextToken(); + innerst = new StringTokenizer(para, ","); + while (innerst.hasMoreTokens()) { + String s = innerst.nextToken().trim(); + if (s.length()==0) + break; + float x = Float.parseFloat(s); + float y = Float.parseFloat(innerst.nextToken()); + this.mPtsBuffer.add(new PointF(x, y)); } + + para = st.nextToken(); + this.mColor = Integer.parseInt(para); + + para = st.nextToken(); + this.mWidth = Float.parseFloat(para); + + para = st.nextToken(); + this.mLength = Float.parseFloat(para); + + para = st.nextToken(); + this.mTimestamp = Long.parseLong(para); } - - /** - * Convert the gesture to string - */ + @Override public String toString() { - StringBuilder str = new StringBuilder(); - str.append(mGestureID); - ArrayList<GestureStroke> strokes = mStrokes; - int count = strokes.size(); - for (int i = 0; i < count; i++) { - GestureStroke stroke = strokes.get(i); - str.append(GestureConstants.STRING_GESTURE_DELIIMITER); - str.append(stroke.toString()); + String str = ""; + + str += "#" + this.mBBX.left + "," + this.mBBX.top + "," + + this.mBBX.right + "," + this.mBBX.bottom; + + str += "#"; + Iterator<PointF> it = this.mPtsBuffer.iterator(); + while (it.hasNext()) { + PointF fp = it.next(); + str += fp.x + "," + fp.y + ","; } - return str.toString(); + str += "#"; + str += this.mColor; + + str += "#"; + str += this.mWidth; + + str += "#"; + str += this.mLength; + + str += "#"; + str += this.mTimestamp; + + return str; } - - public static final Parcelable.Creator<Gesture> CREATOR = new Parcelable.Creator<Gesture>() { + + public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { public Gesture createFromParcel(Parcel in) { String str = in.readString(); - Gesture gesture = new Gesture(); - gesture.createFromString(str); - return gesture; + Gesture stk = new Gesture(); + stk.createFromString(str); + return stk; } - + public Gesture[] newArray(int size) { return new Gesture[size]; } }; - - /** - * Build a gesture from a byte array - * - * @param bytes - * @return the gesture - */ - static Gesture buildFromArray(byte[] bytes) { + + public static Gesture buildFromArray(byte[] bytes) { String str = new String(bytes); - Gesture gesture = new Gesture(); - gesture.createFromString(str); - return gesture; + Gesture stk = new Gesture(); + stk.createFromString(str); + return stk; } - - /** - * Save a gesture to a byte array - * - * @param stroke - * @return the byte array - */ - static byte[] saveToArray(Gesture stroke) { - String str = stroke.toString(); + + public static byte[] saveToArray(Gesture stk) { + String str = stk.toString(); return str.getBytes(); } - + public void writeToParcel(Parcel out, int flags) { - out.writeString(toString()); + out.writeString(this.toString()); } - + public int describeContents() { return CONTENTS_FILE_DESCRIPTOR; } 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 130ac190fde9..000000000000 --- a/tests/sketch/src/com/android/gesture/GestureActionListener.java +++ /dev/null @@ -1,22 +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/GestureAdapter.java b/tests/sketch/src/com/android/gesture/GestureAdapter.java deleted file mode 100644 index 3cf9b4cbb09c..000000000000 --- a/tests/sketch/src/com/android/gesture/GestureAdapter.java +++ /dev/null @@ -1,124 +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; - -public class GestureAdapter implements GestureListener { - - public static final int SINGLE_STROKE = 0; - - public static final int MULTIPLE_STROKE = 1; - - private static final float STROKE_LENGTH_THRESHOLD = 100; - - private static final float SQUARENESS_THRESHOLD = 0.24f; - - private static final int UNCERTAIN_GESTURE_COLOR = Color.argb(60, 255, 255, 0); - - private boolean mIsGesturing = false; - - private float mTotalLength; - - private float mX, mY; - - private View mModel; - - private int mGestureType = SINGLE_STROKE; - - private ArrayList<GestureActionListener> mActionListeners = new ArrayList<GestureActionListener>(); - - public GestureAdapter(View model) { - mModel = model; - } - - public void setGestureType(int type) { - mGestureType = type; - } - - 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(UNCERTAIN_GESTURE_COLOR); - } - mModel.dispatchTouchEvent(event); - } - - public void onGesture(GestureOverlay overlay, MotionEvent event) { - if (mIsGesturing) { - return; - } - float x = event.getX(); - float y = event.getY(); - float dx = x - mX; - float dy = y - mY; - mTotalLength += (float)Math.sqrt(dx * dx + dy * dy); - mX = x; - mY = y; - - if (mTotalLength > STROKE_LENGTH_THRESHOLD) { - OrientedBoundingBox bbx = GestureUtils.computeOrientedBBX(overlay.getCurrentStroke()); - if (bbx.squareness > SQUARENESS_THRESHOLD) { - mIsGesturing = true; - overlay.setGestureColor(GestureOverlay.DEFAULT_GESTURE_COLOR); - 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()); - } - } - mModel.dispatchTouchEvent(event); - } - - public void onFinishGesture(GestureOverlay overlay, MotionEvent event) { - if (mIsGesturing) { - overlay.clear(true); - ArrayList<GestureActionListener> listeners = mActionListeners; - int count = listeners.size(); - for (int i = 0; i < count; i++) { - GestureActionListener listener = listeners.get(i); - listener.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/GestureConstants.java b/tests/sketch/src/com/android/gesture/GestureConstants.java deleted file mode 100644 index 0e17c8ac0e86..000000000000 --- a/tests/sketch/src/com/android/gesture/GestureConstants.java +++ /dev/null @@ -1,31 +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 XML_TAG_LIBRARY = "library"; - static final String XML_TAG_ENTRY = "entry"; - static final String XML_TAG_GESTURE = "gesture"; - static final String XML_TAG_STROKE = "stroke"; - static final String XML_TAG_ID = "id"; - static final String XML_TAG_NAME = "name"; - 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 = 8 * 1024; // 8K -} 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 32c1ac4fdb6a..000000000000 --- a/tests/sketch/src/com/android/gesture/GestureLibrary.java +++ /dev/null @@ -1,332 +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 android.util.Xml; -import android.util.Xml.Encoding; - -import org.xml.sax.Attributes; -import org.xml.sax.ContentHandler; -import org.xml.sax.Locator; -import org.xml.sax.SAXException; -import org.xmlpull.v1.XmlSerializer; - -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.PrintWriter; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Iterator; -import java.util.Set; - -/** - * GestureLibrary maintains gesture examples and makes predictions on a new - * gesture - */ -public class GestureLibrary { - - public static final int SEQUENCE_INVARIANT = 1; - - public static final int SEQUENCE_SENSITIVE = 2; - - private int mSequenceType = SEQUENCE_SENSITIVE; - - public static final int ORIENTATION_INVARIANT = 1; - - public static final int ORIENTATION_SENSITIVE = 2; - - private int mOrientationStyle = ORIENTATION_SENSITIVE; - - private static final String LOGTAG = "GestureLibrary"; - - private static final String NAMESPACE = ""; - - private final String mGestureFileName; - - private HashMap<String, ArrayList<Gesture>> mEntryName2gestures = 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 whether the gesture library will handle orientation sensitive - * gestures. Use ORIENTATION_INVARIANT or ORIENTATION_SENSITIVE - * - * @param style - */ - public void setOrientationStyle(int style) { - mOrientationStyle = style; - } - - public int getOrientationStyle() { - return mOrientationStyle; - } - - public void setGestureType(int type) { - mSequenceType = type; - } - - public int getGestureType() { - return mSequenceType; - } - - /** - * Get all the gesture entry names in the library - * - * @return a set of strings - */ - public Set<String> getGestureEntries() { - return mEntryName2gestures.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(this, gesture, null); - return mClassifier.classify(this, instance); - } - - /** - * Add a gesture for the entry - * - * @param entryName entry name - * @param gesture - */ - public void addGesture(String entryName, Gesture gesture) { - if (Config.DEBUG) { - Log.v(LOGTAG, "Add an example for gesture: " + entryName); - } - ArrayList<Gesture> gestures = mEntryName2gestures.get(entryName); - if (gestures == null) { - gestures = new ArrayList<Gesture>(); - mEntryName2gestures.put(entryName, gestures); - } - gestures.add(gesture); - mClassifier.addInstance(Instance.createInstance(this, 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 = mEntryName2gestures.get(entryName); - if (gestures == null) { - return; - } - - gestures.remove(gesture); - - // if there are no more samples, remove the entry automatically - if (gestures.isEmpty()) { - mEntryName2gestures.remove(entryName); - } - - mClassifier.removeInstance(gesture.getID()); - - mChanged = true; - } - - /** - * Remove a entry of gestures - * - * @param entryName the entry name - */ - public void removeEntireEntry(String entryName) { - mEntryName2gestures.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 - */ - @SuppressWarnings("unchecked") - public ArrayList<Gesture> getGestures(String entryName) { - ArrayList<Gesture> gestures = mEntryName2gestures.get(entryName); - if (gestures != null) { - return (ArrayList<Gesture>)gestures.clone(); - } else { - return null; - } - } - - /** - * Save the gesture library - */ - public void save() { - if (!mChanged) - return; - - try { - File file = new File(mGestureFileName); - if (!file.getParentFile().exists()) { - file.getParentFile().mkdirs(); - } - if (Config.DEBUG) { - Log.v(LOGTAG, "Save to " + mGestureFileName); - } - BufferedOutputStream outputStream = new BufferedOutputStream(new FileOutputStream( - mGestureFileName), GestureConstants.IO_BUFFER_SIZE); - - PrintWriter writer = new PrintWriter(outputStream); - XmlSerializer serializer = Xml.newSerializer(); - serializer.setOutput(writer); - serializer.startDocument(Encoding.ISO_8859_1.name(), null); - serializer.startTag(NAMESPACE, GestureConstants.XML_TAG_LIBRARY); - HashMap<String, ArrayList<Gesture>> maps = mEntryName2gestures; - Iterator<String> it = maps.keySet().iterator(); - while (it.hasNext()) { - String key = it.next(); - ArrayList<Gesture> examples = maps.get(key); - // save an entry - serializer.startTag(NAMESPACE, GestureConstants.XML_TAG_ENTRY); - serializer.attribute(NAMESPACE, GestureConstants.XML_TAG_NAME, key); - int count = examples.size(); - for (int i = 0; i < count; i++) { - Gesture gesture = examples.get(i); - // save each gesture in the entry - gesture.toXML(NAMESPACE, serializer); - } - serializer.endTag(NAMESPACE, GestureConstants.XML_TAG_ENTRY); - } - serializer.endTag(NAMESPACE, GestureConstants.XML_TAG_LIBRARY); - serializer.endDocument(); - serializer.flush(); - writer.close(); - outputStream.close(); - mChanged = false; - } catch (IOException ex) { - Log.d(LOGTAG, "Failed to save gestures:", ex); - } - } - - /** - * Load the gesture library - */ - public void load() { - File file = new File(mGestureFileName); - if (file.exists()) { - try { - if (Config.DEBUG) { - Log.v(LOGTAG, "Load from " + mGestureFileName); - } - BufferedInputStream in = new BufferedInputStream(new FileInputStream( - mGestureFileName), GestureConstants.IO_BUFFER_SIZE); - Xml.parse(in, Encoding.ISO_8859_1, new CompactInkHandler()); - in.close(); - } catch (SAXException ex) { - Log.d(LOGTAG, "Failed to load gestures:", ex); - } catch (IOException ex) { - Log.d(LOGTAG, "Failed to load gestures:", ex); - } - } - } - - private class CompactInkHandler implements ContentHandler { - Gesture currentGesture = null; - - StringBuilder buffer = new StringBuilder(GestureConstants.STROKE_STRING_BUFFER_SIZE); - - String entryName; - - ArrayList<Gesture> gestures; - - CompactInkHandler() { - } - - public void characters(char[] ch, int start, int length) { - buffer.append(ch, start, length); - } - - public void endDocument() { - } - - public void endElement(String uri, String localName, String qName) { - if (localName.equals(GestureConstants.XML_TAG_ENTRY)) { - mEntryName2gestures.put(entryName, gestures); - gestures = null; - } else if (localName.equals(GestureConstants.XML_TAG_GESTURE)) { - gestures.add(currentGesture); - mClassifier.addInstance(Instance.createInstance(GestureLibrary.this, - currentGesture, entryName)); - currentGesture = null; - } else if (localName.equals(GestureConstants.XML_TAG_STROKE)) { - currentGesture.addStroke(GestureStroke.createFromString(buffer.toString())); - buffer.setLength(0); - } - } - - public void endPrefixMapping(String prefix) { - } - - public void ignorableWhitespace(char[] ch, int start, int length) { - } - - public void processingInstruction(String target, String data) { - } - - public void setDocumentLocator(Locator locator) { - } - - public void skippedEntity(String name) { - } - - public void startDocument() { - } - - public void startElement(String uri, String localName, String qName, Attributes attributes) { - if (localName.equals(GestureConstants.XML_TAG_ENTRY)) { - gestures = new ArrayList<Gesture>(); - entryName = attributes.getValue(NAMESPACE, GestureConstants.XML_TAG_NAME); - } else if (localName.equals(GestureConstants.XML_TAG_GESTURE)) { - currentGesture = new Gesture(); - currentGesture.setID(Long.parseLong(attributes.getValue(NAMESPACE, - GestureConstants.XML_TAG_ID))); - } - } - - public void startPrefixMapping(String prefix, String uri) { - } - } -} diff --git a/tests/sketch/src/com/android/gesture/GestureListener.java b/tests/sketch/src/com/android/gesture/GestureListener.java index 9b5071401fd0..ebb41494a2ff 100755 --- a/tests/sketch/src/com/android/gesture/GestureListener.java +++ b/tests/sketch/src/com/android/gesture/GestureListener.java @@ -18,13 +18,8 @@ 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); + public void onStartGesture(GesturePad pad, MotionEvent event); + public void onGesture(GesturePad pad, MotionEvent event); + public void onFinishGesture(GesturePad pad, 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 5cef8c870ad1..000000000000 --- a/tests/sketch/src/com/android/gesture/GestureOverlay.java +++ /dev/null @@ -1,340 +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.Color; -import android.graphics.Paint; -import android.graphics.Path; -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 int BLUR_MASK_RADIUS = 1; - - 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 Path mPath; - - private float mX; - - private float mY; - - // 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 - .setMaskFilter(new BlurMaskFilter(BLUR_MASK_RADIUS, BlurMaskFilter.Blur.NORMAL)); - - 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: - touch_start(event); - invalidate(); - break; - case MotionEvent.ACTION_MOVE: - touch_move(event); - invalidate(); - break; - case MotionEvent.ACTION_UP: - touch_up(event); - invalidate(); - break; - } - - return true; - } - - private void touch_start(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); - } - - private void touch_move(MotionEvent event) { - 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) { - mPath.quadTo(mX, mY, (x + mX) / 2, (y + mY) / 2); - 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); - } - } - - private void touch_up(MotionEvent event) { - // add the stroke to the current gesture - mCurrentGesture.addStroke(new GestureStroke(mPointBuffer)); - mPointBuffer = null; - - // add the stroke to the double buffer - mGesturePaint.setDither(true); - mBitmapCanvas.drawPath(mPath, mGesturePaint); - mGesturePaint.setDither(false); - mPath = 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); - } - } - -} diff --git a/tests/sketch/src/com/android/gesture/GesturePad.java b/tests/sketch/src/com/android/gesture/GesturePad.java index 04dbe3a38ebc..45a09e6eca98 100755 --- a/tests/sketch/src/com/android/gesture/GesturePad.java +++ b/tests/sketch/src/com/android/gesture/GesturePad.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2009 Google Inc. + * Copyright (C) 2008 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. @@ -18,67 +18,64 @@ 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.Matrix; import android.graphics.Paint; import android.graphics.Path; +import android.graphics.PointF; import android.os.Handler; import android.util.AttributeSet; import android.view.MotionEvent; import android.view.View; import java.util.ArrayList; - +import java.util.Iterator; /** - * A (transparent) view for gesture input that can be placed on top of other - * widgets. The background of the view is customizable. - * - * @author liyang@google.com (Yang Li) - * + * A view for rendering and processing gestures */ public class GesturePad extends View { - private static final float TOUCH_TOLERANCE = 4; - 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 Path mPath; - private float mX; - private float mY; + public static final float TOUCH_TOLERANCE = 4; + public static final int default_foreground = Color.argb(255, 255, 255, 0); + private int background = Color.argb(0, 0, 0, 0); + private int foreground = default_foreground; + private int uncertain_foreground = Color.argb(55, 255, 255, 0); + private Bitmap mBitmap; + private Canvas mCanvas; + private Path mPath; + private Paint mBitmapPaint; + private Paint mPaint; + private Paint mDebugPaint; + private float mX, mY; + private boolean mEnableInput = true; + private boolean mEnableRendering = true; + private boolean mCacheGesture = true; + private Gesture mCurrentGesture = null; + ArrayList<GestureListener> mGestureListeners = new ArrayList<GestureListener>(); - // current gesture - private Gesture mCurrentGesture = null; + private boolean mShouldFadingOut = true; + private boolean mIsFadingOut = false; + private float mFadingAlpha = 1; - // 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 boolean reconstruct = false; + + private ArrayList<Path> debug = new ArrayList<Path>(); private Handler mHandler = new Handler(); + private Runnable mFadingOut = new Runnable() { - public void run() { - mFadingAlpha -= 0.03f; - if (mFadingAlpha <= 0) { - mIsFadingOut = false; - mPath = null; - mCurrentGesture = null; - mBitmap.eraseColor(Color.argb(0, 0, 0, 0)); - } else { - mHandler.postDelayed(this, 100); - } - invalidate(); - } - }; + public void run() { + mFadingAlpha -= 0.03f; + if (mFadingAlpha <= 0) { + mIsFadingOut = false; + mPath.reset(); + } else { + mHandler.postDelayed(this, 100); + } + invalidate(); + } + }; public GesturePad(Context context) { super(context); @@ -90,76 +87,82 @@ public class GesturePad extends View { init(); } - public ArrayList<GesturePoint> getCurrentStroke() { - return this.mPointBuffer; + public boolean isEnableRendering() { + return this.mEnableRendering; } public Gesture getCurrentGesture() { return mCurrentGesture; } - /** - * Set Gesture color - * @param c - */ - public void setGestureColor(int c) { - this.mGesturePaint.setColor(c); - if (mCurrentGesture != null) { - mBitmap.eraseColor(Color.argb(0, 0, 0, 0)); - mCurrentGesture.draw(mBitmapCanvas, mGesturePaint); - } + public Paint getPaint() { + return mPaint; } - /** - * Set the gesture to be shown in the view - * @param gesture - */ - public void setCurrentGesture(Gesture gesture) { - if (this.mCurrentGesture != null) { - clear(false); - } - - this.mCurrentGesture = gesture; - - if (this.mCurrentGesture != null) { - if (mBitmapCanvas != null) { - this.mCurrentGesture.draw(mBitmapCanvas, mGesturePaint); - this.invalidate(); - } - } + public void setColor(int c) { + this.foreground = c; + } + + public void setFadingAlpha(float f) { + mFadingAlpha = f; + } + + public void setCurrentGesture(Gesture stk) { + this.mCurrentGesture = stk; + reconstruct = true; } private void init() { - mGesturePaint = new Paint(); - mGesturePaint.setAntiAlias(true); - mGesturePaint.setDither(true); - mGesturePaint.setColor(DEFAULT_GESTURE_COLOR); - mGesturePaint.setStyle(Paint.Style.STROKE); - mGesturePaint.setStrokeJoin(Paint.Join.ROUND); - mGesturePaint.setStrokeCap(Paint.Cap.ROUND); - mGesturePaint.setStrokeWidth(12); - mGesturePaint.setMaskFilter( - new BlurMaskFilter(1, BlurMaskFilter.Blur.NORMAL)); + mDebugPaint = new Paint(); + mDebugPaint.setColor(Color.WHITE); + mDebugPaint.setStrokeWidth(4); + mDebugPaint.setAntiAlias(true); + mDebugPaint.setStyle(Paint.Style.STROKE); - mPath = null; + mPaint = new Paint(); + mPaint.setAntiAlias(true); + mPaint.setDither(true); + mPaint.setColor(foreground); + mPaint.setStyle(Paint.Style.STROKE); + mPaint.setStrokeJoin(Paint.Join.ROUND); + mPaint.setStrokeCap(Paint.Cap.ROUND); + mPaint.setStrokeWidth(12); + + mBitmapPaint = new Paint(Paint.DITHER_FLAG); + mPath = new Path(); + + reconstruct = false; } + + public void cacheGesture(boolean b) { + mCacheGesture = b; + } + + public void enableRendering(boolean b) { + mEnableRendering = b; + } + @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { // TODO Auto-generated method stub super.onSizeChanged(w, h, oldw, oldh); - if (w <= 0 || h <= 0) { + + if (w <=0 || h <=0) return; + + int width = w>oldw? w : oldw; + int height = h>oldh? h : oldh; + Bitmap newBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); + mCanvas = new Canvas(newBitmap); + + if (mBitmap != null) { + mCanvas.drawColor(background); + mCanvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint); + mCanvas.drawPath(mPath, mPaint); } - int width = w > oldw? w : oldw; - int height = h > oldh? h : oldh; - mBitmap = Bitmap.createBitmap( - width, height, Bitmap.Config.ARGB_8888); - mBitmapCanvas = new Canvas(mBitmap); - mBitmapCanvas.drawColor(Color.argb(0, 0, 0, 0)); - if (mCurrentGesture != null) { - mCurrentGesture.draw(mBitmapCanvas, mGesturePaint); - } + + mBitmap = newBitmap; } public void addGestureListener(GestureListener l) { @@ -172,50 +175,111 @@ public class GesturePad extends View { @Override protected void onDraw(Canvas canvas) { - super.onDraw(canvas); - - // draw double buffer - Paint paint = new Paint(Paint.DITHER_FLAG); + canvas.drawColor(background); + + if (mCacheGesture) + canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint); + if (mIsFadingOut) { - paint.setAlpha((int)(255 * mFadingAlpha)); - canvas.drawBitmap(mBitmap, 0, 0, paint); + int color = foreground; + int alpha = (int)(Color.alpha(color) * mFadingAlpha); + mPaint.setColor(Color.argb(alpha, + Color.red(color), + Color.green(color), + Color.blue(color))); + } else if (mEnableRendering == false) { + mPaint.setColor(uncertain_foreground); } else { - canvas.drawBitmap(mBitmap, 0, 0, paint); + mPaint.setColor(foreground); + } + + if (reconstruct) { + + if (this.mCurrentGesture != null) { + float xedge = 30; + float yedge = 30; + float w = this.getWidth() - 2 * xedge; + float h = this.getHeight() - 2 * yedge; + float sx = w / this.mCurrentGesture.getBBX().width(); + float sy = h / mCurrentGesture.getBBX().height(); + float scale = sx>sy?sy:sx; + convertFromStroke(mCurrentGesture); + Matrix matrix = new Matrix(); + matrix.preTranslate(-mCurrentGesture.getBBX().centerX(), -mCurrentGesture.getBBX().centerY()); + matrix.postScale(scale, scale); + matrix.postTranslate(this.getWidth()/2, this.getHeight()/2); + this.mPath.transform(matrix); + } else { + mPath.reset(); + } + + reconstruct = false; } - // draw the current stroke - if (mPath != null) { - canvas.drawPath(mPath, mGesturePaint); + canvas.drawPath(mPath, mPaint); + + Iterator<Path> it = debug.iterator(); + while (it.hasNext()) { + Path path = it.next(); + canvas.drawPath(path, mDebugPaint); } } - - /** - * Clear up the gesture pad - * @param fadeOut whether the gesture on the pad should fade out gradually - * or disappear immediately - */ - public void clear(boolean fadeOut) { - if (fadeOut) { - mFadingAlpha = 1; - mIsFadingOut = true; - mHandler.removeCallbacks(mFadingOut); - mHandler.postDelayed(mFadingOut, 100); - } else { - mPath = null; - this.mCurrentGesture = null; - if (mBitmap != null) { - mBitmap.eraseColor(Color.argb(0, 0, 0, 0)); - this.invalidate(); + + public void clearDebugPath() { + debug.clear(); + } + + public void addDebugPath(Path path) { + debug.add(path); + } + + public void addDebugPath(ArrayList<Path> paths) { + debug.addAll(paths); + } + + public void clear() { + mPath = new Path(); + this.mCurrentGesture = null; + mCanvas.drawColor(background); + this.invalidate(); + } + + private void convertFromStroke(Gesture stk) { + mPath = null; + Iterator it = stk.getPoints().iterator(); + while (it.hasNext()) { + PointF p = (PointF) it.next(); + if (mPath == null) { + mPath = new Path(); + mPath.moveTo(p.x, p.y); + mX = p.x; + mY = p.y; + } else { + float dx = Math.abs(p.x - mX); + float dy = Math.abs(p.y - mY); + if (dx >= TOUCH_TOLERANCE || dy >= TOUCH_TOLERANCE) { + mPath.quadTo(mX, mY, (p.x + mX)/2, (p.y + mY)/2); + mX = p.x; + mY = p.y; + } } } + mPath.lineTo(mX, mY); + } + + public void setEnableInput(boolean b) { + mEnableInput = b; + } + + public boolean isEnableInput() { + return mEnableInput; } @Override public boolean onTouchEvent(MotionEvent event) { - if(this.isEnabled() == false) { + if(mEnableInput == false) return true; - } switch (event.getAction()) { case MotionEvent.ACTION_DOWN: @@ -231,41 +295,28 @@ public class GesturePad extends View { invalidate(); break; } - return true; } private void touch_start(MotionEvent event) { - // if there is fading-out effect, stop it. - if (mIsFadingOut) { - mIsFadingOut = false; - mHandler.removeCallbacks(mFadingOut); - mBitmap.eraseColor(Color.argb(0, 0, 0, 0)); - this.mCurrentGesture = null; - } + mIsFadingOut = false; + mHandler.removeCallbacks(mFadingOut); float x = event.getX(); float y = event.getY(); + mCurrentGesture = new Gesture(); + mCurrentGesture.addPoint(x, y); + + mPath.reset(); + mPath.moveTo(x, y); mX = x; mY = y; - // pass the event to handlers - int count = mGestureListeners.size(); - for (int i = 0; i < count; i++) { - GestureListener listener = mGestureListeners.get(i); - listener.onStartGesture(this, event); + Iterator<GestureListener> it = mGestureListeners.iterator(); + while (it.hasNext()) { + it.next().onStartGesture(this, event); } - - 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); } private void touch_move(MotionEvent event) { @@ -280,32 +331,41 @@ public class GesturePad extends View { mY = y; } - mPointBuffer.add(new GesturePoint(x, y, event.getEventTime())); - - // pass the event to handlers - int count = mGestureListeners.size(); - for (int i = 0; i < count; i++) { - GestureListener listener = mGestureListeners.get(i); - listener.onGesture(this, event); + mCurrentGesture.addPoint(x, y); + + Iterator<GestureListener> it = mGestureListeners.iterator(); + while (it.hasNext()) { + it.next().onGesture(this, event); } } - + + public void setFadingOut(boolean b) { + mShouldFadingOut = b; + mIsFadingOut = false; + } + + public boolean shouldFadingOut() { + return mShouldFadingOut; + } private void touch_up(MotionEvent event) { - // add the stroke to the current gesture - mCurrentGesture.addStroke(new GestureStroke(mPointBuffer)); - mPointBuffer = null; - - // add the stroke to the double buffer - mBitmapCanvas.drawPath(mPath, mGesturePaint); - mPath = null; + mPath.lineTo(mX, mY); + + if (mCacheGesture) + mCanvas.drawPath(mPath, mPaint); - // pass the event to handlers - int count = mGestureListeners.size(); - for (int i = 0; i < count; i++) { - GestureListener listener = mGestureListeners.get(i); - listener.onFinishGesture(this, event); + // kill this so we don't double draw + if (shouldFadingOut()) { + mFadingAlpha = 1; + mIsFadingOut = true; + mHandler.removeCallbacks(mFadingOut); + mHandler.postDelayed(mFadingOut, 100); + } + + Iterator<GestureListener> it = mGestureListeners.iterator(); + while (it.hasNext()) { + it.next().onFinishGesture(this, event); } } - + } 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 d06eff47811c..000000000000 --- a/tests/sketch/src/com/android/gesture/GesturePoint.java +++ /dev/null @@ -1,35 +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; - -/** - * A timed point of a gesture stroke - */ - -public class GesturePoint { - public final float xpos; - - public final float ypos; - - public final long timestamp; - - public GesturePoint(float x, float y, long t) { - xpos = x; - ypos = y; - timestamp = t; - } -} diff --git a/tests/sketch/src/com/android/gesture/GestureProcessor.java b/tests/sketch/src/com/android/gesture/GestureProcessor.java deleted file mode 100644 index feddeadb8c49..000000000000 --- a/tests/sketch/src/com/android/gesture/GestureProcessor.java +++ /dev/null @@ -1,128 +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; - -public class GestureProcessor implements GestureListener { - - public static final int SINGLE_STROKE = 0; - - public static final int MULTIPLE_STROKE = 1; - - private static final float STROKE_LENGTH_THRESHOLD = 100; - - private static final float SQUARENESS_THRESHOLD = 0.24f; - - private static final int UNCERTAIN_GESTURE_COLOR = Color.argb(60, 255, 255, 0); - - private boolean mIsGesturing = false; - - private float mTotalLength; - - private float mX, mY; - - private View mModel; - - private int mGestureType = SINGLE_STROKE; - - private ArrayList<GestureActionListener> mActionListeners = new ArrayList<GestureActionListener>(); - - public GestureProcessor(View model) { - mModel = model; - } - - /** - * - * @param type SINGLE_STROKE or MULTIPLE_STROKE - */ - public void setGestureType(int type) { - mGestureType = type; - } - - 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(UNCERTAIN_GESTURE_COLOR); - } - mModel.dispatchTouchEvent(event); - } - - public void onGesture(GestureOverlay overlay, MotionEvent event) { - if (mIsGesturing) { - return; - } - float x = event.getX(); - float y = event.getY(); - float dx = x - mX; - float dy = y - mY; - mTotalLength += (float)Math.sqrt(dx * dx + dy * dy); - mX = x; - mY = y; - - if (mTotalLength > STROKE_LENGTH_THRESHOLD) { - OrientedBoundingBox bbx = GestureUtils.computeOrientedBBX(overlay.getCurrentStroke()); - if (bbx.squareness > SQUARENESS_THRESHOLD) { - mIsGesturing = true; - overlay.setGestureColor(GestureOverlay.DEFAULT_GESTURE_COLOR); - 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()); - } - } - mModel.dispatchTouchEvent(event); - } - - public void onFinishGesture(GestureOverlay overlay, MotionEvent event) { - if (mIsGesturing) { - overlay.clear(true); - ArrayList<GestureActionListener> listeners = mActionListeners; - int count = listeners.size(); - for (int i = 0; i < count; i++) { - GestureActionListener listener = listeners.get(i); - listener.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/GestureStroke.java b/tests/sketch/src/com/android/gesture/GestureStroke.java deleted file mode 100644 index b1081e55236d..000000000000 --- a/tests/sketch/src/com/android/gesture/GestureStroke.java +++ /dev/null @@ -1,244 +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 org.xmlpull.v1.XmlSerializer; - -import java.io.IOException; -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[] xPoints; - - public final float[] yPoints; - - public final long[] timestamps; - - private Path mCachedPath; - - /** - * Construct a gesture stroke from a list of gesture points - * - * @param pts - */ - public GestureStroke(ArrayList<GesturePoint> pts) { - xPoints = new float[pts.size()]; - yPoints = new float[pts.size()]; - timestamps = new long[pts.size()]; - - RectF bx = null; - float len = 0; - int index = 0; - int count = pts.size(); - float[] xpts = xPoints; - float[] ypts = yPoints; - long[] times = timestamps; - - for (int i = 0; i < count; i++) { - GesturePoint p = pts.get(i); - xpts[index] = p.xpos; - ypts[index] = p.ypos; - times[index] = p.timestamp; - - if (bx == null) { - bx = new RectF(); - bx.top = p.ypos; - bx.left = p.xpos; - bx.right = p.xpos; - bx.bottom = p.ypos; - len = 0; - } else { - len += Math.sqrt(Math.pow(p.xpos - xpts[index - 1], 2) - + Math.pow(p.ypos - ypts[index - 1], 2)); - bx.union(p.xpos, p.ypos); - } - index++; - } - - boundingBox = bx; - length = len; - } - - /** - * Draw the gesture with a given canvas and paint - * - * @param canvas - */ - void draw(Canvas canvas, Paint paint) { - if (mCachedPath == null) { - float[] xpts = xPoints; - float[] ypts = yPoints; - int count = xpts.length; - Path path = null; - float mX = 0, mY = 0; - for (int i = 0; i < count; i++) { - float x = xpts[i]; - float y = ypts[i]; - 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) { - float[] pts = GestureUtils.sequentialFeaturize(this, numSample); - RectF rect = boundingBox; - float scale = height / rect.height(); - Matrix matrix = new Matrix(); - matrix.setTranslate(-rect.left, -rect.top); - Matrix scaleMatrix = new Matrix(); - scaleMatrix.setScale(scale, scale); - matrix.postConcat(scaleMatrix); - Matrix translate = new Matrix(); - matrix.postConcat(translate); - matrix.mapPoints(pts); - - Path path = null; - float mX = 0; - float mY = 0; - 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; - } - - /** - * Save the gesture stroke as XML - * - * @param namespace - * @param serializer - * @throws IOException - */ - void toXML(String namespace, XmlSerializer serializer) throws IOException { - serializer.startTag(namespace, GestureConstants.XML_TAG_STROKE); - serializer.text(toString()); - serializer.endTag(namespace, GestureConstants.XML_TAG_STROKE); - } - - /** - * Create a gesture stroke from a string - * - * @param str - * @return the gesture stroke - */ - public static GestureStroke createFromString(String str) { - ArrayList<GesturePoint> points = new ArrayList<GesturePoint>( - GestureConstants.STROKE_POINT_BUFFER_SIZE); - int endIndex; - int startIndex = 0; - while ((endIndex = str.indexOf(GestureConstants.STRING_STROKE_DELIIMITER, startIndex + 1)) != -1) { - - // parse x - String token = str.substring(startIndex, endIndex); - float x = Float.parseFloat(token); - startIndex = endIndex + 1; - - // parse y - endIndex = str.indexOf(GestureConstants.STRING_STROKE_DELIIMITER, startIndex + 1); - token = str.substring(startIndex, endIndex); - float y = Float.parseFloat(token); - startIndex = endIndex + 1; - - // parse t - endIndex = str.indexOf(GestureConstants.STRING_STROKE_DELIIMITER, startIndex + 1); - token = str.substring(startIndex, endIndex); - long time = Long.parseLong(token); - startIndex = endIndex + 1; - - points.add(new GesturePoint(x, y, time)); - } - return new GestureStroke(points); - } - - /** - * Convert the stroke to string - */ - @Override - public String toString() { - StringBuilder str = new StringBuilder(GestureConstants.STROKE_STRING_BUFFER_SIZE); - float[] xpts = xPoints; - float[] ypts = yPoints; - long[] times = timestamps; - int count = xpts.length; - for (int i = 0; i < count; i++) { - str.append(xpts[i] + GestureConstants.STRING_STROKE_DELIIMITER + ypts[i] - + GestureConstants.STRING_STROKE_DELIIMITER + times[i] - + GestureConstants.STRING_STROKE_DELIIMITER); - } - return str.toString(); - } - - /** - * Invalidate the cached path that is used for rendering the stroke - */ - public void invalidate() { - mCachedPath = null; - } -} diff --git a/tests/sketch/src/com/android/gesture/GestureUtils.java b/tests/sketch/src/com/android/gesture/GestureUtils.java deleted file mode 100755 index 7c3237a3d807..000000000000 --- a/tests/sketch/src/com/android/gesture/GestureUtils.java +++ /dev/null @@ -1,358 +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 java.util.ArrayList; -import java.util.Arrays; - -public class GestureUtils { - - private static final int SEQUENCE_SAMPLE_SIZE = 16; - - protected static float[] spatialFeaturize(Gesture gesture, int sampleSize) { - float[] sample = new float[sampleSize * sampleSize]; - Arrays.fill(sample, 0); - - RectF rect = gesture.getBoundingBox(); - float sx = sampleSize / rect.width(); - float sy = sampleSize / rect.height(); - float scale = sx < sy ? sx : sy; - android.graphics.Matrix trans = new android.graphics.Matrix(); - trans.setScale(scale, scale); - android.graphics.Matrix translate1 = new android.graphics.Matrix(); - translate1.setTranslate(-rect.centerX(), -rect.centerY()); - trans.preConcat(translate1); - android.graphics.Matrix translate2 = new android.graphics.Matrix(); - translate2.setTranslate(sampleSize / 2, sampleSize / 2); - trans.postConcat(translate2); - - ArrayList<GestureStroke> strokes = gesture.getStrokes(); - int count = strokes.size(); - int size; - for (int index = 0; index < count; index++) { - GestureStroke stroke = strokes.get(index); - float[] pts = sequentialFeaturize(stroke, SEQUENCE_SAMPLE_SIZE); - trans.mapPoints(pts); - - size = pts.length; - for (int i = 0; i < size; i += 2) { - float x = pts[i]; - int xFloor = (int) Math.floor(x); - int xCeiling = (int) Math.ceil(x); - float y = pts[i + 1]; - int yFloor = (int) Math.floor(y); - int yCeiling = (int) Math.ceil(y); - - if (yFloor >= 0 && yFloor < sampleSize && xFloor >= 0 && xFloor < sampleSize) { - int pos = yFloor * sampleSize + xFloor; - float value = (1 - x + xFloor) * (1 - y + yFloor); - if (sample[pos] < value) { - sample[pos] = value; - } - } - - if (yFloor >= 0 && yFloor < sampleSize && xCeiling >= 0 && xCeiling < sampleSize) { - int pos = yFloor * sampleSize + xCeiling; - float value = (1 - xCeiling + x) * (1 - y + yFloor); - if (sample[pos] < value) { - sample[pos] = value; - } - } - - if (yCeiling >= 0 && yCeiling < sampleSize && xFloor >= 0 && xFloor < sampleSize) { - int pos = yCeiling * sampleSize + xFloor; - float value = (1 - x + xFloor) * (1 - yCeiling + y); - if (sample[pos] < value) { - sample[pos] = value; - } - - } - - if (yCeiling >= 0 && yCeiling < sampleSize && xCeiling >= 0 - && xCeiling < sampleSize) { - int pos = yCeiling * sampleSize + xCeiling; - float value = (1 - xCeiling + x) * (1 - yCeiling + y); - if (sample[pos] < value) { - sample[pos] = value; - } - } - } - } - - return sample; - } - - /** - * Featurize a stroke into a vector of a given number of elements - * - * @param stroke - * @param sampleSize - * @return a float array - */ - protected static float[] sequentialFeaturize(GestureStroke stroke, int sampleSize) { - final float increment = stroke.length / (sampleSize - 1); - int vectorLength = sampleSize * 2; - float[] vector = new float[vectorLength]; - float distanceSoFar = 0; - float[] xpts = stroke.xPoints; - float[] ypts = stroke.yPoints; - float lstPointX = xpts[0]; - float lstPointY = ypts[0]; - 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 = xpts.length; - while (i < count) { - if (currentPointX == Float.MIN_VALUE) { - i++; - if (i >= count) { - break; - } - currentPointX = xpts[i]; - currentPointY = ypts[i]; - } - 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 - */ - public 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 - */ - protected 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; - } - - public 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; - } - - public 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; - } - - public 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 - */ - protected static double euclideanDistance(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 in1 - * @param in2 - * @return the distance between 0 and Math.PI - */ - protected static double cosineDistance(Instance in1, Instance in2) { - float sum = 0; - float[] vector1 = in1.vector; - float[] vector2 = in2.vector; - int len = vector1.length; - for (int i = 0; i < len; i++) { - sum += vector1[i] * vector2[i]; - } - return Math.acos(sum / (in1.magnitude * in2.magnitude)); - } - - public static OrientedBoundingBox computeOrientedBBX(ArrayList<GesturePoint> pts) { - GestureStroke stroke = new GestureStroke(pts); - float[] points = sequentialFeaturize(stroke, SEQUENCE_SAMPLE_SIZE); - return computeOrientedBBX(points); - } - - public static OrientedBoundingBox computeOrientedBBX(float[] points) { - float[] meanVector = computeCentroid(points); - return computeOrientedBBX(points, meanVector); - } - - public static OrientedBoundingBox computeOrientedBBX(float[] points, float[] centroid) { - - android.graphics.Matrix tr = new android.graphics.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]; - } - } - - OrientedBoundingBox bbx = new OrientedBoundingBox(angle, centroid[0], centroid[1], maxx - - minx, maxy - miny); - return bbx; - } - - 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; - } - - // lamda^2 + a * lamda + b = 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 4eb10f9962dd..000000000000 --- a/tests/sketch/src/com/android/gesture/Instance.java +++ /dev/null @@ -1,106 +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; - -/** - * An instance represents a sample if the label is available or a query if the - * label is null. - */ -public class Instance { - - private static final int SEQUENCE_SAMPLE_SIZE = 16; - - private static final int PATCH_SAMPLE_SIZE = 8; - - private final static float[] ORIENTATIONS = { - 0, 45, 90, 135, 180, -0, -45, -90, -135, -180 - }; - - // the feature vector - public final float[] vector; - - // the label can be null - public final String label; - - // the length of the vector - public final float magnitude; - - // the id of the instance - public final long instanceID; - - private Instance(long id, float[] sample, String sampleName) { - instanceID = id; - vector = sample; - label = sampleName; - float sum = 0; - int size = sample.length; - for (int i = 0; i < size; i++) { - sum += sample[i] * sample[i]; - } - magnitude = (float) Math.sqrt(sum); - } - - /** - * create a learning instance for a single stroke gesture - * - * @param gesture - * @param label - * @return the instance - */ - public static Instance createInstance(GestureLibrary gesturelib, Gesture gesture, String label) { - float[] pts; - if (gesturelib.getGestureType() == GestureLibrary.SEQUENCE_SENSITIVE) { - pts = sequenceSampler(gesturelib, gesture); - } else { - pts = spatialSampler(gesture); - } - return new Instance(gesture.getID(), pts, label); - } - - private static float[] spatialSampler(Gesture gesture) { - float[] pts = GestureUtils.spatialFeaturize(gesture, PATCH_SAMPLE_SIZE); - return pts; - } - - private static float[] sequenceSampler(GestureLibrary gesturelib, Gesture gesture) { - float[] pts = GestureUtils.sequentialFeaturize(gesture.getStrokes().get(0), - SEQUENCE_SAMPLE_SIZE); - float[] center = GestureUtils.computeCentroid(pts); - float orientation = (float) Math.atan2(pts[1] - center[1], pts[0] - center[0]); - orientation *= 180 / Math.PI; - - float adjustment = -orientation; - if (gesturelib.getOrientationStyle() == 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; - } - } - } - - android.graphics.Matrix m = new android.graphics.Matrix(); - m.setTranslate(-center[0], -center[1]); - android.graphics.Matrix rotation = new android.graphics.Matrix(); - rotation.setRotate(adjustment); - m.postConcat(rotation); - 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 3bd875b7a517..000000000000 --- 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(GestureLibrary lib, Instance instance) { - 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 != instance.vector.length) { - continue; - } - double distance; - if (lib.getGestureType() == GestureLibrary.SEQUENCE_SENSITIVE) { - distance = GestureUtils.cosineDistance(sample, instance); - } else { - distance = GestureUtils.euclideanDistance(sample.vector, instance.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.predictionScore /= sum; - } - - Collections.sort(predictions, new Comparator<Prediction>() { - public int compare(Prediction object1, Prediction object2) { - double score1 = object1.predictionScore; - double score2 = object2.predictionScore; - 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.gestureName + " = " + name.predictionScore + "]"); - } - } - - 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 63f315640ad3..000000000000 --- a/tests/sketch/src/com/android/gesture/Learner.java +++ /dev/null @@ -1,82 +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.instanceID) { - instances.remove(instance); - return; - } - } - } - - /** - * Remove all the instances of a category - * - * @param name the category name - */ - void removeInstances(String name) { - ArrayList<Instance> toDelete = new ArrayList<Instance>(); - ArrayList<Instance> instances = mInstances; - int count = instances.size(); - for (int i = 0; i < count; i++) { - Instance instance = instances.get(i); - if (instance.label.equals(name)) { - toDelete.add(instance); - } - } - mInstances.removeAll(toDelete); - } - - abstract ArrayList<Prediction> classify(GestureLibrary library, Instance instance); -} 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 fe1984c2086d..000000000000 --- a/tests/sketch/src/com/android/gesture/OrientedBoundingBox.java +++ /dev/null @@ -1,81 +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; // -PI<alpha<PI - - 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 60cca8b127e1..000000000000 --- 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 gestureName; - - public double predictionScore; - - Prediction(String label, double score) { - gestureName = label; - predictionScore = score; - } - - @Override - public String toString() { - return gestureName; - } -} diff --git a/tests/sketch/src/com/android/gesture/example/ContactAdapter.java b/tests/sketch/src/com/android/gesture/example/ContactAdapter.java deleted file mode 100644 index 008a972c773c..000000000000 --- a/tests/sketch/src/com/android/gesture/example/ContactAdapter.java +++ /dev/null @@ -1,100 +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.example; - -import android.app.Activity; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.ArrayAdapter; -import android.widget.TextView; - -import java.util.ArrayList; - -class ContactAdapter extends ArrayAdapter<ContactItem> { - - private LayoutInflater mInflater; - - public ContactAdapter(Activity activity, ArrayList<ContactItem> contacts) { - super(activity, 0, contacts); - mInflater = activity.getLayoutInflater(); - } - - @Override - public ContactItem getItem(int position) { - return super.getItem(position); - } - - @Override - public long getItemId(int position) { - return getItem(position).itemID; - } - - @Override - public View getView(int position, View convertView, ViewGroup parent) { - final ContactItem info = getItem(position); - - View view = convertView; - if (view == null) { - view = mInflater.inflate(android.R.layout.simple_list_item_1, parent, false); - view.setTag(view.findViewById(android.R.id.text1)); - } - - final TextView textView = (TextView)view.getTag(); - textView.setText(info.toString()); - - return view; - } - - public int search(String query) { - if (query != null && query.length() > 0) { - int start = 0; - int end = getCount() - 1; - int index = binarySearch(query, start, end); - for (index = index - 1; index >= 0; index--) { - String str = getItem(index).toString().toLowerCase(); - if (!str.startsWith(query)) { - return index + 1; - } - if (index == 0) { - return 0; - } - } - return -1; - } else { - return -1; - } - } - - private int binarySearch(String prefix, int start, int end) { - if (start > end) { - return -1; - } - int mid = (start + end) / 2; - String str = getItem(mid).toString().toLowerCase(); - if (prefix.compareTo(str) <= 0) { - if (str.startsWith(prefix)) { - return mid; - } else { - return binarySearch(prefix, start, mid - 1); - } - } else { - return binarySearch(prefix, mid + 1, end); - } - } - -} diff --git a/tests/sketch/src/com/android/gesture/example/ContactItem.java b/tests/sketch/src/com/android/gesture/example/ContactItem.java deleted file mode 100644 index 557c4d9d8348..000000000000 --- a/tests/sketch/src/com/android/gesture/example/ContactItem.java +++ /dev/null @@ -1,34 +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.example; - - -class ContactItem { - final String itemName; - - final long itemID; - - public ContactItem(long id, String name) { - itemID = id; - itemName = name; - } - - @Override - public String toString() { - return itemName; - } -} diff --git a/tests/sketch/src/com/android/gesture/example/ContactListGestureOverlay.java b/tests/sketch/src/com/android/gesture/example/ContactListGestureOverlay.java deleted file mode 100644 index 50d349a9a402..000000000000 --- a/tests/sketch/src/com/android/gesture/example/ContactListGestureOverlay.java +++ /dev/null @@ -1,122 +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.example; - -import android.app.Activity; -import android.content.ContentResolver; -import android.content.ContentUris; -import android.content.Intent; -import android.database.Cursor; -import android.os.Bundle; -import android.os.Environment; -import android.provider.Contacts.People; -import android.view.View; -import android.view.ViewGroup; -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.GestureProcessor; -import com.android.gesture.GestureLibrary; -import com.android.gesture.GestureOverlay; -import com.android.gesture.Prediction; - -import java.io.File; -import java.util.ArrayList; - -public class ContactListGestureOverlay extends Activity { - - static final String GESTURE_FILE_NAME = Environment.getExternalStorageDirectory().getAbsolutePath() - + File.separator + "gestureOverlay.xml"; - - private static final String SORT_ORDER = People.DISPLAY_NAME + " COLLATE LOCALIZED ASC"; - - private static final String[] CONTACTS_PROJECTION = new String[] { - People._ID, // 0 - People.DISPLAY_NAME, // 1 - }; - - private GestureOverlay mOverlay; - - private ContactAdapter mContactAdapter; - - private GestureProcessor mGestureProcessor; - - private GestureLibrary mLibrary; - - private ListView mContactList; - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS); - setContentView(R.layout.overlaydemo); - - setProgressBarIndeterminateVisibility(true); - - // load the gesture library - mLibrary = new GestureLibrary(GESTURE_FILE_NAME); - mLibrary.load(); - - // load the contact list - mContactList = (ListView)this.findViewById(R.id.list); - registerForContextMenu(mContactList); - mContactList.setTextFilterEnabled(true); - mContactList.setVerticalScrollBarEnabled(true); - mContactList.setOnItemClickListener(new AdapterView.OnItemClickListener() { - public void onItemClick(AdapterView<?> parent, View v, int position, long id) { - if (!mGestureProcessor.isGesturing()) { - Intent intent = new Intent(Intent.ACTION_VIEW, ContentUris.withAppendedId( - People.CONTENT_URI, id)); - startActivity(intent); - } - } - }); - ContentResolver resolver = getContentResolver(); - Cursor cursor = resolver.query(People.CONTENT_URI, CONTACTS_PROJECTION, null, null, - SORT_ORDER); - ArrayList<ContactItem> list = new ArrayList<ContactItem>(); - while (cursor.moveToNext()) { - list.add(new ContactItem(cursor.getLong(0), cursor.getString(1))); - } - mContactAdapter = new ContactAdapter(this, list); - mContactList.setAdapter(mContactAdapter); - - setProgressBarIndeterminateVisibility(false); - - // add a gesture overlay on top of the ListView - mOverlay = new GestureOverlay(this); - mGestureProcessor = new GestureProcessor(mContactList); - mGestureProcessor.addGestureActionListener(new GestureActionListener() { - public void onGesturePerformed(GestureOverlay overlay, Gesture gesture) { - ArrayList<Prediction> predictions = mLibrary.recognize(gesture); - if (!predictions.isEmpty()) { - int index = mContactAdapter.search(predictions.get(0).gestureName); - if (index != -1) { - mContactList.setSelection(index); - } - } - } - }); - mOverlay.addGestureListener(mGestureProcessor); - ViewGroup.LayoutParams params = new ViewGroup.LayoutParams( - ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.FILL_PARENT); - this.addContentView(mOverlay, params); - } -} diff --git a/tests/sketch/src/com/android/gesture/example/GestureEntry.java b/tests/sketch/src/com/android/gesture/example/GestureEntry.java deleted file mode 100644 index 6a54b493ed4a..000000000000 --- a/tests/sketch/src/com/android/gesture/example/GestureEntry.java +++ /dev/null @@ -1,209 +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.example; - -import android.app.Activity; -import android.app.AlertDialog; -import android.app.Dialog; -import android.content.DialogInterface; -import android.content.Intent; -import android.graphics.Color; -import android.os.Bundle; -import android.os.Environment; -import android.view.LayoutInflater; -import android.view.Menu; -import android.view.MenuItem; -import android.view.MotionEvent; -import android.view.View; -import android.view.View.OnClickListener; -import android.widget.AdapterView; -import android.widget.ArrayAdapter; -import android.widget.Button; -import android.widget.EditText; -import android.widget.Spinner; -import android.widget.AdapterView.OnItemSelectedListener; - -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 java.io.File; -import java.util.ArrayList; - -public class GestureEntry extends Activity { - - private static final String PARCEL_KEY = "gesture"; - - static final String GESTURE_FILE_NAME = Environment.getExternalStorageDirectory().getAbsolutePath() - + File.separator + "gestureEntry.xml"; - - private static final int DIALOG_NEW_ENTRY = 1; - - private static final int NEW_ID = Menu.FIRST; - - private static final int VIEW_ID = Menu.FIRST + 1; - - private GestureOverlay mGesturePad; - - private Spinner mRecognitionResult; - - private GestureLibrary mGestureLibrary; - - private boolean mChangedByRecognizer = false; - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.demo); - - // init the gesture library - mGestureLibrary = new GestureLibrary(GESTURE_FILE_NAME); - mGestureLibrary.load(); - - // create the spinner for showing the recognition results - // the spinner also allows a user to correct a prediction - mRecognitionResult = (Spinner) findViewById(R.id.spinner); - mRecognitionResult.setOnItemSelectedListener(new OnItemSelectedListener() { - - public void onItemSelected(AdapterView<?> parent, View view, int position, long id) { - // correct the recognition result by adding the new example - if (!mChangedByRecognizer) { - mGestureLibrary.addGesture(parent.getSelectedItem().toString(), mGesturePad - .getCurrentGesture()); - } else { - mChangedByRecognizer = false; - } - } - - public void onNothingSelected(AdapterView<?> parent) { - - } - - }); - - // create the area for drawing a gesture - mGesturePad = (GestureOverlay) findViewById(R.id.drawingpad); - mGesturePad.setBackgroundColor(Color.BLACK); - mGesturePad.addGestureListener(new GestureListener() { - public void onFinishGesture(GestureOverlay pad, MotionEvent event) { - recognize(pad.getCurrentGesture()); - pad.clear(true); - } - - public void onGesture(GestureOverlay pad, MotionEvent event) { - } - - public void onStartGesture(GestureOverlay pad, MotionEvent event) { - } - }); - - if (savedInstanceState != null) { - Gesture g = (Gesture) savedInstanceState.getParcelable(PARCEL_KEY); - if (g != null) { - mGesturePad.setCurrentGesture(g); - } - } - } - - @Override - protected Dialog onCreateDialog(int id) { - LayoutInflater factory = LayoutInflater.from(this); - final View textEntryView = factory.inflate(R.layout.newgesture_dialog, null); - return new AlertDialog.Builder(GestureEntry.this).setTitle( - R.string.newgesture_text_entry).setView(textEntryView).setPositiveButton( - R.string.newgesture_dialog_ok, new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int whichButton) { - EditText edittext = (EditText) ((AlertDialog) dialog) - .findViewById(R.id.gesturename_edit); - String text = edittext.getText().toString().trim(); - if (text.length() > 0) { - mGestureLibrary.addGesture(text, mGesturePad.getCurrentGesture()); - } - } - }).setNegativeButton(R.string.newgesture_dialog_cancel, - new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int whichButton) { - } - }).create(); - } - - @Override - public boolean onCreateOptionsMenu(Menu menu) { - super.onCreateOptionsMenu(menu); - menu.add(0, NEW_ID, 0, R.string.newgesture).setShortcut('0', 'n').setIcon( - android.R.drawable.ic_menu_add); - menu.add(0, VIEW_ID, 0, R.string.viewgesture).setShortcut('1', 'v').setIcon( - android.R.drawable.ic_menu_view); - return true; - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - switch (item.getItemId()) { - case NEW_ID: - if (mGesturePad.getCurrentGesture() != null) { - showDialog(DIALOG_NEW_ENTRY); - } - break; - - case VIEW_ID: - startActivityForResult(new Intent(this, GestureLibViewer.class), VIEW_ID); - break; - } - - return super.onOptionsItemSelected(item); - } - - @Override - protected void onActivityResult(int requestCode, int resultCode, Intent data) { - mGestureLibrary.load(); - mGesturePad.clear(false); - } - - @Override - protected void onPause() { - super.onPause(); - mGestureLibrary.save(); - } - - @Override - protected void onPrepareDialog(int id, Dialog dialog) { - super.onPrepareDialog(id, dialog); - } - - @Override - protected void onSaveInstanceState(Bundle outState) { - super.onSaveInstanceState(outState); - Gesture gesture = mGesturePad.getCurrentGesture(); - if (gesture != null) { - outState.putParcelable(PARCEL_KEY, gesture); - } - mGestureLibrary.save(); - } - - private void recognize(Gesture ink) { - mChangedByRecognizer = true; - ArrayList<Prediction> predictions = mGestureLibrary.recognize(ink); - ArrayAdapter<Prediction> adapter = new ArrayAdapter<Prediction>(this, - android.R.layout.simple_spinner_item, predictions); - adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); - mRecognitionResult.setAdapter(adapter); - } - -} diff --git a/tests/sketch/src/com/android/gesture/example/GestureEntryDemo.java b/tests/sketch/src/com/android/gesture/example/GestureEntryDemo.java index 52a2ba8fa5cd..8fee21ac490b 100644..100755 --- a/tests/sketch/src/com/android/gesture/example/GestureEntryDemo.java +++ b/tests/sketch/src/com/android/gesture/example/GestureEntryDemo.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009 Google Inc. + * Copyright (C) 2008 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. @@ -21,34 +21,29 @@ import android.app.AlertDialog; import android.app.Dialog; import android.content.DialogInterface; import android.content.Intent; -import android.graphics.Color; import android.os.Bundle; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuItem; import android.view.MotionEvent; import android.view.View; -import android.view.View.OnClickListener; import android.widget.AdapterView; import android.widget.ArrayAdapter; -import android.widget.Button; import android.widget.EditText; import android.widget.Spinner; import android.widget.AdapterView.OnItemSelectedListener; import com.android.gesture.Gesture; -import com.android.gesture.GestureLibrary; +import com.android.gesture.GestureLib; import com.android.gesture.GestureListener; import com.android.gesture.GesturePad; -import com.android.gesture.Prediction; +import com.android.gesture.R; +import com.android.gesture.recognizer.Prediction; import java.util.ArrayList; /** * The demo shows how to construct a gesture-based user interface on Android. - * - * @author liyang@google.com (Yang Li) - * */ public class GestureEntryDemo extends Activity { @@ -57,35 +52,31 @@ public class GestureEntryDemo extends Activity { private static final int NEW_ID = Menu.FIRST; private static final int VIEW_ID = Menu.FIRST + 1; - private GesturePad mGesturePad; - private Spinner mRecognitionResult; - private GestureLibrary mGestureLibrary; - private boolean mChangedByRecognizer = false; + GesturePad mView; + Spinner mResult; + GestureLib mRecognizer; + boolean mChangedByRecognizer = false; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.demo); - // init the gesture library - mGestureLibrary = new GestureLibrary( - "/sdcard/gestureentry/gestures.xml"); - mGestureLibrary.load(); + // init the recognizer + mRecognizer = new GestureLib("/sdcard/gestureentry"); + mRecognizer.load(); // create the spinner for showing the recognition results // the spinner also allows a user to correct a prediction - mRecognitionResult = (Spinner) findViewById(R.id.spinner); - mRecognitionResult.setOnItemSelectedListener( - new OnItemSelectedListener() { + mResult = (Spinner) findViewById(R.id.spinner); + mResult.setOnItemSelectedListener(new OnItemSelectedListener() { - public void onItemSelected( - AdapterView<?> parent, View view, int position, long id) { + public void onItemSelected(AdapterView<?> parent, View view, int position, long id) { // TODO Auto-generated method stub // correct the recognition result by adding the new example if (mChangedByRecognizer == false) { - mGestureLibrary.addGesture( - parent.getSelectedItem().toString(), - mGesturePad.getCurrentGesture()); + mRecognizer.addGesture(parent.getSelectedItem().toString(), + mView.getCurrentGesture()); } else { mChangedByRecognizer = false; } @@ -99,35 +90,28 @@ public class GestureEntryDemo extends Activity { }); // create the area for drawing a gesture - mGesturePad = (GesturePad)this.findViewById(R.id.drawingpad); - mGesturePad.setBackgroundColor(Color.BLACK); - mGesturePad.addGestureListener(new GestureListener() { - public void onFinishGesture(GesturePad pad, MotionEvent event) { + mView = (GesturePad)this.findViewById(R.id.drawingpad); + mView.cacheGesture(false); + mView.setFadingOut(false); + mView.addGestureListener(new GestureListener() { + public void onFinishGesture(GesturePad patch, MotionEvent event) { // TODO Auto-generated method stub - recognize(pad.getCurrentGesture()); + recognize(patch.getCurrentGesture()); } - public void onGesture(GesturePad pad, MotionEvent event) { + public void onGesture(GesturePad patch, MotionEvent event) { // TODO Auto-generated method stub + } - public void onStartGesture(GesturePad pad, MotionEvent event) { - // TODO Auto-generated method stub + public void onStartGesture(GesturePad patch, MotionEvent event) { + // TODO Auto-generated method stub + } }); - Button clear = (Button)this.findViewById(R.id.clear); - clear.setOnClickListener(new OnClickListener() { - public void onClick(View v) { - // TODO Auto-generated method stub - mGesturePad.clear(false); - mGesturePad.invalidate(); - } - }); if (savedInstanceState != null) { - Gesture g = (Gesture)savedInstanceState.getParcelable("gesture"); - if (g != null) { - mGesturePad.setCurrentGesture(g); - } + mView.setCurrentGesture( + (Gesture)savedInstanceState.getParcelable("gesture")); } } @@ -145,12 +129,10 @@ public class GestureEntryDemo extends Activity { public void onClick(DialogInterface dialog, int whichButton) { /* User clicked OK so do some stuff */ EditText edittext = - (EditText)((AlertDialog)dialog).findViewById( - R.id.gesturename_edit); + (EditText)((AlertDialog)dialog).findViewById(R.id.gesturename_edit); String text = edittext.getText().toString().trim(); if (text.length() > 0) { - mGestureLibrary.addGesture( - text, mGesturePad.getCurrentGesture()); + mRecognizer.addGesture(text, mView.getCurrentGesture()); } } }) @@ -182,7 +164,7 @@ public class GestureEntryDemo extends Activity { switch (item.getItemId()) { case NEW_ID: // if there has been a gesture on the canvas - if (mGesturePad.getCurrentGesture() != null) { + if (mView.getCurrentGesture() != null) { showDialog(DIALOG_NEW_ENTRY); } break; @@ -198,17 +180,16 @@ public class GestureEntryDemo extends Activity { @Override - protected void onActivityResult( - int requestCode, int resultCode, Intent data) { - mGestureLibrary.load(); - mGesturePad.clear(false); + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + mRecognizer.load(); + mView.clear(); } @Override protected void onPause() { // TODO Auto-generated method stub super.onPause(); - mGestureLibrary.save(); + mRecognizer.save(); } @@ -222,20 +203,18 @@ public class GestureEntryDemo extends Activity { protected void onSaveInstanceState(Bundle outState) { // TODO Auto-generated method stub super.onSaveInstanceState(outState); - Gesture gesture = mGesturePad.getCurrentGesture(); - if (gesture != null) - outState.putParcelable("gesture", gesture); - mGestureLibrary.save(); + outState.putParcelable("gesture", mView.getCurrentGesture()); + mRecognizer.save(); } public void recognize(Gesture ink) { mChangedByRecognizer = true; - ArrayList<Prediction> predictions = mGestureLibrary.recognize(ink); - ArrayAdapter<Prediction> adapter = new ArrayAdapter<Prediction>(this, + ArrayList<Prediction> predictions = mRecognizer.recognize(ink); + ArrayAdapter adapter = new ArrayAdapter(this, android.R.layout.simple_spinner_item, predictions); adapter.setDropDownViewResource( android.R.layout.simple_spinner_dropdown_item); - mRecognitionResult.setAdapter(adapter); + mResult.setAdapter(adapter); } } diff --git a/tests/sketch/src/com/android/gesture/example/GestureLibViewer.java b/tests/sketch/src/com/android/gesture/example/GestureLibViewer.java index ca541105e603..7ae7fc5e84d3 100644..100755 --- a/tests/sketch/src/com/android/gesture/example/GestureLibViewer.java +++ b/tests/sketch/src/com/android/gesture/example/GestureLibViewer.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2009 The Android Open Source Project + * Copyright (C) 2008 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. @@ -17,6 +17,8 @@ package com.android.gesture.example; import android.app.Activity; +import android.graphics.Matrix; +import android.graphics.Path; import android.os.Bundle; import android.view.KeyEvent; import android.view.View; @@ -28,156 +30,228 @@ import android.widget.Spinner; import android.widget.AdapterView.OnItemSelectedListener; import com.android.gesture.Gesture; -import com.android.gesture.GestureLibrary; -import com.android.gesture.GestureOverlay; +import com.android.gesture.GestureLib; +import com.android.gesture.GesturePad; +import com.android.gesture.R; +import com.android.gesture.recognizer.Instance; import java.util.ArrayList; import java.util.Collections; /** - * GestureLibViewer gives an example on how to browse existing gestures and + * GestureLibViewer is for viewing existing gestures and * removing unwanted gestures. */ -public class GestureLibViewer extends Activity { - - private GestureOverlay mGesturePad; - - private Spinner mGestureCategory; - - private GestureLibrary mGesureLibrary; - - private ArrayList<Gesture> mGestures; - - private int mCurrentGestureIndex; - - private class RemoveGestureListener implements OnClickListener { - public void onClick(View v) { - if (mGestures.isEmpty()) { - return; - } - - String name = (String) mGestureCategory.getSelectedItem(); - Gesture gesture = mGestures.get(mCurrentGestureIndex); - mGesureLibrary.removeGesture(name, gesture); - - mGestures = mGesureLibrary.getGestures(name); - - if (mGestures == null) { - // delete the entire entry - mCurrentGestureIndex = 0; - ArrayList<String> list = new ArrayList<String>(); - list.addAll(mGesureLibrary.getGestureEntries()); - Collections.sort(list); - ArrayAdapter<String> adapter = new ArrayAdapter<String>(GestureLibViewer.this, - android.R.layout.simple_spinner_item, list); - adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); - mGestureCategory.setAdapter(adapter); - } else { - if (mCurrentGestureIndex > mGestures.size() - 1) { - mCurrentGestureIndex--; - } - gesture = mGestures.get(mCurrentGestureIndex); - mGesturePad.setCurrentGesture(gesture); - mGesturePad.invalidate(); - } - } - } +public class GestureLibViewer extends Activity { + + GesturePad mView; + Spinner mResult; + GestureLib mRecognizer; + ArrayList<Gesture> mSamples; + int mCurrentGestureIndex; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.gestureviewer); + + // create the area for drawing a glyph + mView = (GesturePad)this.findViewById(R.id.drawingpad); + mView.cacheGesture(false); + mView.setFadingOut(false); + mView.setEnableInput(false); + + // init the recognizer + mRecognizer = new GestureLib("/sdcard/gestureentry"); + mRecognizer.load(); - // create the area for drawing a gesture - mGesturePad = (GestureOverlay) findViewById(R.id.drawingpad); - mGesturePad.setEnabled(false); - - // init the gesture library - mGesureLibrary = new GestureLibrary(GestureEntry.GESTURE_FILE_NAME); - mGesureLibrary.load(); - - mGestureCategory = (Spinner) findViewById(R.id.spinner); + mResult = (Spinner) findViewById(R.id.spinner); ArrayList<String> list = new ArrayList<String>(); - if (!mGesureLibrary.getGestureEntries().isEmpty()) { - list.addAll(mGesureLibrary.getGestureEntries()); - Collections.sort(list); - ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, - android.R.layout.simple_spinner_item, list); - adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); - mGestureCategory.setAdapter(adapter); - mGestures = mGesureLibrary.getGestures(list.get(0)); + list.addAll(mRecognizer.getLabels()); + Collections.sort(list); + ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, + android.R.layout.simple_spinner_item, + list); + adapter.setDropDownViewResource( + android.R.layout.simple_spinner_dropdown_item); + mResult.setAdapter(adapter); + mSamples = mRecognizer.getGestures(list.get(0)); + if (mSamples.isEmpty() == false) { mCurrentGestureIndex = 0; - Gesture gesture = mGestures.get(mCurrentGestureIndex); - mGesturePad.setCurrentGesture(gesture); + Gesture gesture = mSamples.get(mCurrentGestureIndex); + mView.setCurrentGesture(gesture); + mView.clearDebugPath(); + mView.addDebugPath( + toPath(mRecognizer.getClassifier().getInstance(gesture.getID()))); } - - mGestureCategory.setOnItemSelectedListener(new OnItemSelectedListener() { + + mResult.setOnItemSelectedListener(new OnItemSelectedListener() { public void onItemSelected(AdapterView<?> parent, View view, int position, long id) { - mGestures = mGesureLibrary.getGestures((String) mGestureCategory.getSelectedItem()); - if (!mGestures.isEmpty()) { + // TODO Auto-generated method stub + mSamples = mRecognizer.getGestures( + (String)mResult.getSelectedItem()); + if (mSamples.isEmpty() == false) { mCurrentGestureIndex = 0; - Gesture gesture = mGestures.get(mCurrentGestureIndex); - mGesturePad.setCurrentGesture(gesture); + Gesture gesture = mSamples.get(mCurrentGestureIndex); + mView.setCurrentGesture(gesture); + mView.clearDebugPath(); + mView.addDebugPath( + toPath(mRecognizer.getClassifier().getInstance(gesture.getID()))); } - mGesturePad.invalidate(); + mView.invalidate(); } - + public void onNothingSelected(AdapterView<?> parent) { + // TODO Auto-generated method stub + } - + }); - - Button remove = (Button) findViewById(R.id.remove); - remove.setOnClickListener(new RemoveGestureListener()); - - Button next = (Button) findViewById(R.id.next); - next.setOnClickListener(new OnClickListener() { + + Button remove = (Button)this.findViewById(R.id.remove); + remove.setOnClickListener(new OnClickListener() { public void onClick(View v) { - if (mCurrentGestureIndex >= mGestures.size() - 1) { + // TODO Auto-generated method stub + if (mSamples.isEmpty()) return; + + String name = (String)mResult.getSelectedItem(); + Gesture gesture = mSamples.get(mCurrentGestureIndex); + mRecognizer.removeGesture(name, gesture); + + mSamples = mRecognizer.getGestures(name); + + if (mSamples == null) { + // delete the entire entry + mCurrentGestureIndex = 0; + ArrayList<String> list = new ArrayList<String>(); + list.addAll(mRecognizer.getLabels()); + Collections.sort(list); + ArrayAdapter<String> adapter = new ArrayAdapter<String>( + GestureLibViewer.this, + android.R.layout.simple_spinner_item, + list); + adapter.setDropDownViewResource( + android.R.layout.simple_spinner_dropdown_item); + mResult.setAdapter(adapter); + } else { + if (mCurrentGestureIndex > mSamples.size()-1) { + mCurrentGestureIndex--; + } + gesture = mSamples.get(mCurrentGestureIndex); + mView.setCurrentGesture(gesture); + mView.clearDebugPath(); + mView.addDebugPath( + toPath(mRecognizer.getClassifier().getInstance(gesture.getID()))); + mView.invalidate(); } + } + }); + + Button next = (Button)this.findViewById(R.id.next); + next.setOnClickListener(new OnClickListener() { + public void onClick(View v) { + // TODO Auto-generated method stub + if (mCurrentGestureIndex >= mSamples.size()-1) + return; + mCurrentGestureIndex++; - Gesture gesture = mGestures.get(mCurrentGestureIndex); - mGesturePad.setCurrentGesture(gesture); - mGesturePad.invalidate(); + Gesture gesture = mSamples.get(mCurrentGestureIndex); + mView.setCurrentGesture(gesture); + mView.clearDebugPath(); + mView.addDebugPath( + toPath(mRecognizer.getClassifier().getInstance(gesture.getID()))); + mView.invalidate(); } }); - Button previous = (Button) findViewById(R.id.previous); + Button previous = (Button)this.findViewById(R.id.previous); previous.setOnClickListener(new OnClickListener() { public void onClick(View v) { - if (mCurrentGestureIndex >= 1 && !mGestures.isEmpty()) { + // TODO Auto-generated method stub + if (mCurrentGestureIndex >= 1 && + mSamples.isEmpty() == false) { mCurrentGestureIndex--; - Gesture gesture = mGestures.get(mCurrentGestureIndex); - mGesturePad.setCurrentGesture(gesture); - mGesturePad.invalidate(); + Gesture gesture = mSamples.get(mCurrentGestureIndex); + mView.setCurrentGesture(gesture); + mView.clearDebugPath(); + mView.addDebugPath( + toPath(mRecognizer.getClassifier().getInstance(gesture.getID()))); + mView.invalidate(); } } }); } - + + public static ArrayList<Path> toPath(Instance instance) { + ArrayList<Path> paths = new ArrayList(); + Path path = null; + float minx = 0, miny = 0; + float mX = 0, mY = 0; + for (int i=0; i<instance.vector.length; i+=2) { + float x = instance.vector[i]; + float y = instance.vector[i+1]; + if (x < minx) + minx = x; + if (y < miny) + miny = y; + 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; + } + } + } + Matrix matrix = new Matrix(); + matrix.setTranslate(-minx + 10, -miny + 10); + path.transform(matrix); + paths.add(path); + + path = new Path(); + path.moveTo(instance.vector[0]-5, instance.vector[1]-5); + path.lineTo(instance.vector[0]-5, instance.vector[1]+5); + path.lineTo(instance.vector[0]+5, instance.vector[1]+5); + path.lineTo(instance.vector[0]+5, instance.vector[1]-5); + path.close(); + path.transform(matrix); + paths.add(path); + + return paths; + } + @Override public boolean onKeyUp(int keyCode, KeyEvent event) { - if (keyCode == KeyEvent.KEYCODE_BACK) { - mGesureLibrary.save(); - setResult(RESULT_OK); - finish(); - return true; - } else { - return false; - } + // TODO Auto-generated method stub + if (keyCode == KeyEvent.KEYCODE_BACK) { + mRecognizer.save(); + this.setResult(RESULT_OK); + finish(); + return true; + } + else + return false; } - + @Override protected void onPause() { + // TODO Auto-generated method stub super.onPause(); - mGesureLibrary.save(); + mRecognizer.save(); } @Override protected void onSaveInstanceState(Bundle outState) { + // TODO Auto-generated method stub super.onSaveInstanceState(outState); - mGesureLibrary.save(); + mRecognizer.save(); } } |