diff --git a/api/current.xml b/api/current.xml index 5bbf35242924f..085d8b16ef3c5 100644 --- a/api/current.xml +++ b/api/current.xml @@ -46164,6 +46164,1097 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + strokes = mStrokes; - final int count = strokes.size(); - - for (int i = 0; i < count; i++) { - final GestureStroke stroke = strokes.get(i); - str.append(GestureConstants.STRING_GESTURE_DELIIMITER); - str.append(stroke.toString()); - } - - return str.toString(); - } - public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { public Gesture createFromParcel(Parcel in) { Gesture gesture = null; @@ -273,7 +251,7 @@ public class Gesture implements Parcelable { try { gesture = deserialize(inStream); } catch (IOException e) { - Log.e(LOG_TAG, "Error reading Gesture from parcel:", e); + Log.e(GestureConstants.LOG_TAG, "Error reading Gesture from parcel:", e); } finally { GestureUtilities.closeStream(inStream); } @@ -302,7 +280,7 @@ public class Gesture implements Parcelable { serialize(outStream); result = true; } catch (IOException e) { - Log.e(LOG_TAG, "Error writing Gesture to parcel:", e); + Log.e(GestureConstants.LOG_TAG, "Error writing Gesture to parcel:", e); } finally { GestureUtilities.closeStream(outStream); GestureUtilities.closeStream(byteStream); diff --git a/tests/sketch/src/com/android/gesture/GestureConstants.java b/core/java/android/gesture/GestureConstants.java similarity index 86% rename from tests/sketch/src/com/android/gesture/GestureConstants.java rename to core/java/android/gesture/GestureConstants.java index c0f2f3d4c1563..230db0c00c501 100644 --- a/tests/sketch/src/com/android/gesture/GestureConstants.java +++ b/core/java/android/gesture/GestureConstants.java @@ -14,12 +14,9 @@ * limitations under the License. */ -package com.android.gesture; +package android.gesture; interface GestureConstants { - static final String STRING_GESTURE_DELIIMITER = "#"; - static final String STRING_STROKE_DELIIMITER = ","; - static final int STROKE_STRING_BUFFER_SIZE = 1024; static final int STROKE_POINT_BUFFER_SIZE = 100; // number of points diff --git a/tests/sketch/src/com/android/gesture/GestureLibrary.java b/core/java/android/gesture/GestureLibrary.java similarity index 98% rename from tests/sketch/src/com/android/gesture/GestureLibrary.java rename to core/java/android/gesture/GestureLibrary.java index 7b5480caf5191..1cf192ec34461 100644 --- a/tests/sketch/src/com/android/gesture/GestureLibrary.java +++ b/core/java/android/gesture/GestureLibrary.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.gesture; +package android.gesture; import android.util.Log; import android.os.SystemClock; @@ -32,7 +32,7 @@ import java.util.HashMap; import java.util.Set; import java.util.Map; -import static com.android.gesture.GestureConstants.LOG_TAG; +import static android.gesture.GestureConstants.LOG_TAG; /** * GestureLibrary maintains gesture examples and makes predictions on a new @@ -190,7 +190,7 @@ public class GestureLibrary { * * @param entryName the entry name */ - public void removeEntireEntry(String entryName) { + public void removeEntry(String entryName) { mNamedGestures.remove(entryName); mClassifier.removeInstances(entryName); mChanged = true; diff --git a/tests/sketch/src/com/android/gesture/GestureOverlay.java b/core/java/android/gesture/GestureOverlayView.java similarity index 85% rename from tests/sketch/src/com/android/gesture/GestureOverlay.java rename to core/java/android/gesture/GestureOverlayView.java index 454cecbf2fa2a..bffd12e636f4d 100755 --- a/tests/sketch/src/com/android/gesture/GestureOverlay.java +++ b/core/java/android/gesture/GestureOverlayView.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.gesture; +package android.gesture; import android.content.Context; import android.graphics.Bitmap; @@ -23,6 +23,7 @@ import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.Path; import android.graphics.Rect; +import android.graphics.Color; import android.os.Handler; import android.util.AttributeSet; import android.view.MotionEvent; @@ -35,7 +36,7 @@ import java.util.ArrayList; * widgets. The view can also be opaque. */ -public class GestureOverlay extends View { +public class GestureOverlayView extends View { static final float TOUCH_TOLERANCE = 3; // TODO: Move all these values into XML attributes @@ -52,20 +53,22 @@ public class GestureOverlay extends View { private static final boolean DITHER_FLAG = true; public static final int DEFAULT_GESTURE_COLOR = 0xFFFFFF00; + public static final int DEFAULT_UNCERTAIN_GESTURE_COLOR = Color.argb(60, 255, 255, 0); private static final int REFRESH_RANGE = 10; private static final BlurMaskFilter BLUR_MASK_FILTER = new BlurMaskFilter(1, BlurMaskFilter.Blur.NORMAL); - - // double buffering private Paint mGesturePaint; private final Paint mBitmapPaint = new Paint(Paint.DITHER_FLAG); private Bitmap mBitmap; // with transparent background private Canvas mBitmapCanvas; + private int mCertainGestureColor = DEFAULT_GESTURE_COLOR; + private int mUncertainGestureColor = DEFAULT_UNCERTAIN_GESTURE_COLOR; + // for rendering immediate ink feedback private Rect mInvalidRect = new Rect(); @@ -81,7 +84,7 @@ public class GestureOverlay extends View { private Gesture mCurrentGesture = null; // TODO: Make this a list of WeakReferences - private final ArrayList mGestureListeners = new ArrayList(); + private final ArrayList mOnGestureListeners = new ArrayList(); private ArrayList mPointBuffer = null; // fading out effect @@ -107,12 +110,12 @@ public class GestureOverlay extends View { } }; - public GestureOverlay(Context context) { + public GestureOverlayView(Context context) { super(context); init(); } - public GestureOverlay(Context context, AttributeSet attrs) { + public GestureOverlayView(Context context, AttributeSet attrs) { super(context, attrs); init(); } @@ -130,7 +133,7 @@ public class GestureOverlay extends View { * * @param color */ - public void setGestureColor(int color) { + public void setGestureDrawingColor(int color) { mGesturePaint.setColor(color); if (mCurrentGesture != null) { mBitmap.eraseColor(TRANSPARENT_BACKGROUND); @@ -138,6 +141,22 @@ public class GestureOverlay extends View { } } + public void setGestureColor(int color) { + mCertainGestureColor = color; + } + + public void setUncertainGestureColor(int color) { + mUncertainGestureColor = color; + } + + public int getUncertainGestureColor() { + return mUncertainGestureColor; + } + + public int getGestureColor() { + return mCertainGestureColor; + } + /** * Set the gesture to be shown in the view * @@ -199,12 +218,12 @@ public class GestureOverlay extends View { } } - public void addGestureListener(GestureListener listener) { - mGestureListeners.add(listener); + public void addOnGestureListener(OnGestureListener listener) { + mOnGestureListeners.add(listener); } - public void removeGestureListener(GestureListener listener) { - mGestureListeners.remove(listener); + public void removeOnGestureListener(OnGestureListener listener) { + mOnGestureListeners.remove(listener); } @Override @@ -281,11 +300,11 @@ public class GestureOverlay extends View { private Rect touchStart(MotionEvent event) { // pass the event to handlers - final ArrayList listeners = mGestureListeners; + final ArrayList listeners = mOnGestureListeners; final int count = listeners.size(); for (int i = 0; i < count; i++) { - GestureListener listener = listeners.get(i); - listener.onStartGesture(this, event); + OnGestureListener listener = listeners.get(i); + listener.onGestureStarted(this, event); } // if there is fading out going on, stop it. @@ -358,7 +377,7 @@ public class GestureOverlay extends View { mPointBuffer.add(new GesturePoint(x, y, event.getEventTime())); // pass the event to handlers - final ArrayList listeners = mGestureListeners; + final ArrayList listeners = mOnGestureListeners; final int count = listeners.size(); for (int i = 0; i < count; i++) { listeners.get(i).onGesture(this, event); @@ -377,14 +396,24 @@ public class GestureOverlay extends View { mGesturePaint.setMaskFilter(null); // pass the event to handlers - final ArrayList listeners = mGestureListeners; + final ArrayList listeners = mOnGestureListeners; final int count = listeners.size(); for (int i = 0; i < count; i++) { - listeners.get(i).onFinishGesture(this, event); + listeners.get(i).onGestureEnded(this, event); } mPath = null; mPointBuffer = null; } + /** + * An interface for processing gesture events + */ + public static interface OnGestureListener { + public void onGestureStarted(GestureOverlayView overlay, MotionEvent event); + + public void onGesture(GestureOverlayView overlay, MotionEvent event); + + public void onGestureEnded(GestureOverlayView overlay, MotionEvent event); + } } diff --git a/tests/sketch/src/com/android/gesture/GesturePoint.java b/core/java/android/gesture/GesturePoint.java similarity index 97% rename from tests/sketch/src/com/android/gesture/GesturePoint.java rename to core/java/android/gesture/GesturePoint.java index 560f893cf0521..3698011fc7fcd 100644 --- a/tests/sketch/src/com/android/gesture/GesturePoint.java +++ b/core/java/android/gesture/GesturePoint.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.gesture; +package android.gesture; import java.io.DataInputStream; import java.io.IOException; diff --git a/tests/sketch/src/com/android/gesture/GestureStroke.java b/core/java/android/gesture/GestureStroke.java similarity index 85% rename from tests/sketch/src/com/android/gesture/GestureStroke.java rename to core/java/android/gesture/GestureStroke.java index 79b42fe9e786a..5160a76df7d19 100644 --- a/tests/sketch/src/com/android/gesture/GestureStroke.java +++ b/core/java/android/gesture/GestureStroke.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.gesture; +package android.gesture; import android.graphics.Canvas; import android.graphics.Matrix; @@ -126,16 +126,16 @@ public class GestureStroke { * @param width the width of the bounding box of the target path * @param height the height of the bounding box of the target path * @param numSample the number of points needed + * * @return the path */ public Path toPath(float width, float height, int numSample) { final float[] pts = GestureUtilities.temporalSampling(this, numSample); final RectF rect = boundingBox; - final float scale = height / rect.height(); final Matrix matrix = new Matrix(); matrix.setTranslate(-rect.left, -rect.top); - matrix.postScale(scale, scale); + matrix.postScale(width / rect.width(), height / rect.height()); matrix.mapPoints(pts); float mX = 0; @@ -156,7 +156,8 @@ public class GestureStroke { } else { float dx = Math.abs(x - mX); float dy = Math.abs(y - mY); - if (dx >= GestureOverlay.TOUCH_TOLERANCE || dy >= GestureOverlay.TOUCH_TOLERANCE) { + if (dx >= GestureOverlayView.TOUCH_TOLERANCE || + dy >= GestureOverlayView.TOUCH_TOLERANCE) { path.quadTo(mX, mY, (x + mX) / 2, (y + mY) / 2); mX = x; mY = y; @@ -198,29 +199,10 @@ public class GestureStroke { } /** - * Convert the stroke to string + * Invalidate the cached path that is used to render the stroke */ - @Override - public String toString() { - final StringBuilder str = new StringBuilder(GestureConstants.STROKE_STRING_BUFFER_SIZE); - final float[] pts = points; - final long[] times = timestamps; - final int count = points.length; - - for (int i = 0; i < count; i += 2) { - str.append(pts[i]).append(GestureConstants.STRING_STROKE_DELIIMITER); - str.append(pts[i + 1]).append(GestureConstants.STRING_STROKE_DELIIMITER); - str.append(times[i / 2]).append(GestureConstants.STRING_STROKE_DELIIMITER); - } - - return str.toString(); - } - - /** - * Invalidate the cached path that is used for rendering the stroke - */ - public void invalidate() { - mCachedPath = null; + public void clearPath() { + if (mCachedPath != null) mCachedPath.rewind(); } /** diff --git a/tests/sketch/src/com/android/gesture/GestureUtilities.java b/core/java/android/gesture/GestureUtilities.java similarity index 99% rename from tests/sketch/src/com/android/gesture/GestureUtilities.java rename to core/java/android/gesture/GestureUtilities.java index 6d73c2db7841f..e47856c1a8610 100755 --- a/tests/sketch/src/com/android/gesture/GestureUtilities.java +++ b/core/java/android/gesture/GestureUtilities.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.gesture; +package android.gesture; import android.graphics.RectF; import android.graphics.Matrix; @@ -25,7 +25,7 @@ import java.util.Arrays; import java.io.Closeable; import java.io.IOException; -import static com.android.gesture.GestureConstants.*; +import static android.gesture.GestureConstants.*; final class GestureUtilities { private static final int TEMPORAL_SAMPLING_RATE = 16; diff --git a/tests/sketch/src/com/android/gesture/Instance.java b/core/java/android/gesture/Instance.java similarity index 99% rename from tests/sketch/src/com/android/gesture/Instance.java rename to core/java/android/gesture/Instance.java index 502a0fa4ff01c..7922faba3f981 100755 --- a/tests/sketch/src/com/android/gesture/Instance.java +++ b/core/java/android/gesture/Instance.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.gesture; +package android.gesture; import android.graphics.Matrix; diff --git a/tests/sketch/src/com/android/gesture/InstanceLearner.java b/core/java/android/gesture/InstanceLearner.java similarity index 78% rename from tests/sketch/src/com/android/gesture/InstanceLearner.java rename to core/java/android/gesture/InstanceLearner.java index 4495256eb80ba..1739cdcbe915a 100644 --- a/tests/sketch/src/com/android/gesture/InstanceLearner.java +++ b/core/java/android/gesture/InstanceLearner.java @@ -14,10 +14,11 @@ * limitations under the License. */ -package com.android.gesture; +package android.gesture; import android.util.Config; import android.util.Log; +import static android.gesture.GestureConstants.*; import java.util.ArrayList; import java.util.Collections; @@ -30,9 +31,6 @@ import java.util.TreeMap; */ class InstanceLearner extends Learner { - - private static final String LOGTAG = "InstanceLearner"; - @Override ArrayList classify(int gestureType, float[] vector) { ArrayList predictions = new ArrayList(); @@ -63,19 +61,15 @@ class InstanceLearner extends Learner { } double sum = 0; - Iterator lableIterator = label2score.keySet().iterator(); - while (lableIterator.hasNext()) { - String name = lableIterator.next(); + for (String name : label2score.keySet()) { double score = label2score.get(name); sum += score; predictions.add(new Prediction(name, score)); } // normalize - Iterator predictionIterator = predictions.iterator(); - while (predictionIterator.hasNext()) { - Prediction name = predictionIterator.next(); - name.score /= sum; + for (Prediction prediction : predictions) { + prediction.score /= sum; } Collections.sort(predictions, new Comparator() { @@ -92,14 +86,6 @@ class InstanceLearner extends Learner { } }); - if (Config.DEBUG) { - predictionIterator = predictions.iterator(); - while (predictionIterator.hasNext()) { - Prediction name = predictionIterator.next(); - Log.v(LOGTAG, "prediction [" + name.name + " = " + name.score + "]"); - } - } - return predictions; } } diff --git a/tests/sketch/src/com/android/gesture/Learner.java b/core/java/android/gesture/Learner.java similarity index 98% rename from tests/sketch/src/com/android/gesture/Learner.java rename to core/java/android/gesture/Learner.java index 15b20536feaba..feacde5f97365 100755 --- a/tests/sketch/src/com/android/gesture/Learner.java +++ b/core/java/android/gesture/Learner.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.gesture; +package android.gesture; import java.util.ArrayList; diff --git a/tests/sketch/src/com/android/gesture/LetterRecognizer.java b/core/java/android/gesture/LetterRecognizer.java similarity index 55% rename from tests/sketch/src/com/android/gesture/LetterRecognizer.java rename to core/java/android/gesture/LetterRecognizer.java index 07a5f313c9315..44767469bfb19 100644 --- a/tests/sketch/src/com/android/gesture/LetterRecognizer.java +++ b/core/java/android/gesture/LetterRecognizer.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.gesture; +package android.gesture; import android.content.Context; import android.content.res.Resources; @@ -28,10 +28,13 @@ import java.util.Collections; import java.util.Comparator; import java.util.HashMap; -import static com.android.gesture.GestureConstants.LOG_TAG; +import static android.gesture.GestureConstants.LOG_TAG; public class LetterRecognizer { - public final static int LATIN_LOWERCASE = 0; + public final static int RECOGNIZER_LATIN_LOWERCASE = 0; + static final String GESTURE_FILE_NAME = "letters.gestures"; + + private final static int ADJUST_RANGE = 3; private SigmoidUnit[] mHiddenLayer; private SigmoidUnit[] mOutputLayer; @@ -40,59 +43,57 @@ public class LetterRecognizer { private final int mPatchSize; - static final String GESTURE_FILE_NAME = "letters.gestures"; + private GestureLibrary mGestureLibrary; - private GestureLibrary mGestureLibrary; - private final static int ADJUST_RANGE = 3; - private static class SigmoidUnit { final float[] mWeights; + private boolean mComputed; + private float mResult; + SigmoidUnit(float[] weights) { mWeights = weights; } private float compute(float[] inputs) { - float sum = 0; + if (!mComputed) { + float sum = 0; - final int count = inputs.length; - final float[] weights = mWeights; + final int count = inputs.length; + final float[] weights = mWeights; - for (int i = 0; i < count; i++) { - sum += inputs[i] * weights[i]; + for (int i = 0; i < count; i++) { + sum += inputs[i] * weights[i]; + } + sum += weights[weights.length - 1]; + + mResult = 1.0f / (float) (1 + Math.exp(-sum)); + mComputed = true; } - sum += weights[weights.length - 1]; - - return 1.0f / (float) (1 + Math.exp(-sum)); + return mResult; } } - private LetterRecognizer(int numOfInput, int numOfHidden, String[] classes) { - mPatchSize = (int)Math.sqrt(numOfInput); - mHiddenLayer = new SigmoidUnit[numOfHidden]; - mClasses = classes; - mOutputLayer = new SigmoidUnit[classes.length]; - } - - public void save() { - mGestureLibrary.save(); - } - public static LetterRecognizer getLetterRecognizer(Context context, int type) { switch (type) { - case LATIN_LOWERCASE: { + case RECOGNIZER_LATIN_LOWERCASE: { return createFromResource(context, com.android.internal.R.raw.latin_lowercase); } } return null; } + private LetterRecognizer(int numOfInput, int numOfHidden, String[] classes) { + mPatchSize = (int) Math.sqrt(numOfInput); + mHiddenLayer = new SigmoidUnit[numOfHidden]; + mClasses = classes; + mOutputLayer = new SigmoidUnit[classes.length]; + } + public ArrayList recognize(Gesture gesture) { float[] query = GestureUtilities.spatialSampling(gesture, mPatchSize); ArrayList predictions = classify(query); - if (mGestureLibrary != null) { - adjustPrediction(gesture, predictions); - } + adjustPrediction(gesture, predictions); return predictions; } @@ -153,38 +154,14 @@ public class LetterRecognizer { in = new DataInputStream(new BufferedInputStream(resources.openRawResource(resourceID), GestureConstants.IO_BUFFER_SIZE)); - final int iCount = in.readInt(); - final int hCount = in.readInt(); - final int oCount = in.readInt(); + final int version = in.readShort(); - final String[] classes = new String[oCount]; - for (int i = 0; i < classes.length; i++) { - classes[i] = in.readUTF(); + switch (version) { + case 1: + classifier = readV1(in); + break; } - classifier = new LetterRecognizer(iCount, hCount, classes); - SigmoidUnit[] hiddenLayer = new SigmoidUnit[hCount]; - SigmoidUnit[] outputLayer = new SigmoidUnit[oCount]; - - for (int i = 0; i < hCount; i++) { - float[] weights = new float[iCount + 1]; - for (int j = 0; j <= iCount; j++) { - weights[j] = in.readFloat(); - } - hiddenLayer[i] = new SigmoidUnit(weights); - } - - for (int i = 0; i < oCount; i++) { - float[] weights = new float[hCount + 1]; - for (int j = 0; j <= hCount; j++) { - weights[j] = in.readFloat(); - } - outputLayer[i] = new SigmoidUnit(weights); - } - - classifier.mHiddenLayer = hiddenLayer; - classifier.mOutputLayer = outputLayer; - } catch (IOException e) { Log.d(LOG_TAG, "Failed to load handwriting data:", e); } finally { @@ -193,9 +170,65 @@ public class LetterRecognizer { return classifier; } - - public void enablePersonalization(boolean enable) { - if (enable) { + + private static LetterRecognizer readV1(DataInputStream in) throws IOException { + + final int iCount = in.readInt(); + final int hCount = in.readInt(); + final int oCount = in.readInt(); + + final String[] classes = new String[oCount]; + for (int i = 0; i < classes.length; i++) { + classes[i] = in.readUTF(); + } + + final LetterRecognizer classifier = new LetterRecognizer(iCount, hCount, classes); + final SigmoidUnit[] hiddenLayer = new SigmoidUnit[hCount]; + final SigmoidUnit[] outputLayer = new SigmoidUnit[oCount]; + + for (int i = 0; i < hCount; i++) { + final float[] weights = new float[iCount + 1]; + for (int j = 0; j <= iCount; j++) { + weights[j] = in.readFloat(); + } + hiddenLayer[i] = new SigmoidUnit(weights); + } + + for (int i = 0; i < oCount; i++) { + final float[] weights = new float[hCount + 1]; + for (int j = 0; j <= hCount; j++) { + weights[j] = in.readFloat(); + } + outputLayer[i] = new SigmoidUnit(weights); + } + + classifier.mHiddenLayer = hiddenLayer; + classifier.mOutputLayer = outputLayer; + + return classifier; + } + + /** + * TODO: Publish this API once we figure out where we should save the personzlied + * gestures, and how to do so across all apps + * + * @hide + */ + public boolean save() { + if (mGestureLibrary != null) { + return mGestureLibrary.save(); + } + return false; + } + + /** + * TODO: Publish this API once we figure out where we should save the personzlied + * gestures, and how to do so across all apps + * + * @hide + */ + public void setPersonalizationEnabled(boolean enabled) { + if (enabled) { mGestureLibrary = new GestureLibrary(GESTURE_FILE_NAME); mGestureLibrary.setSequenceType(GestureLibrary.SEQUENCE_INVARIANT); mGestureLibrary.load(); @@ -204,24 +237,36 @@ public class LetterRecognizer { } } + /** + * TODO: Publish this API once we figure out where we should save the personzlied + * gestures, and how to do so across all apps + * + * @hide + */ public void addExample(String letter, Gesture example) { - mGestureLibrary.addGesture(letter, example); + if (mGestureLibrary != null) { + mGestureLibrary.addGesture(letter, example); + } } private void adjustPrediction(Gesture query, ArrayList predictions) { - ArrayList results = mGestureLibrary.recognize(query); - HashMap topNList = new HashMap(); - for (int j = 0; j < ADJUST_RANGE; j++) { - Prediction prediction = predictions.remove(0); - topNList.put(prediction.name, prediction); - } - int count = results.size(); - for (int j = count - 1; j >= 0 && !topNList.isEmpty(); j--) { - Prediction item = results.get(j); - Prediction original = topNList.get(item.name); - if (original != null) { - predictions.add(0, original); - topNList.remove(item.name); + if (mGestureLibrary != null) { + final ArrayList results = mGestureLibrary.recognize(query); + final HashMap topNList = new HashMap(); + + for (int j = 0; j < ADJUST_RANGE; j++) { + Prediction prediction = predictions.remove(0); + topNList.put(prediction.name, prediction); + } + + final int count = results.size(); + for (int j = count - 1; j >= 0 && !topNList.isEmpty(); j--) { + final Prediction item = results.get(j); + final Prediction original = topNList.get(item.name); + if (original != null) { + predictions.add(0, original); + topNList.remove(item.name); + } } } } diff --git a/tests/sketch/src/com/android/gesture/OrientedBoundingBox.java b/core/java/android/gesture/OrientedBoundingBox.java similarity index 95% rename from tests/sketch/src/com/android/gesture/OrientedBoundingBox.java rename to core/java/android/gesture/OrientedBoundingBox.java index a07d125d52559..f1335ee122322 100644 --- a/tests/sketch/src/com/android/gesture/OrientedBoundingBox.java +++ b/core/java/android/gesture/OrientedBoundingBox.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.gesture; +package android.gesture; import android.graphics.Matrix; import android.graphics.Path; @@ -47,6 +47,11 @@ public class OrientedBoundingBox { } } + /** + * Currently used for debugging purpose only. + * + * @hide + */ public Path toPath() { Path path = new Path(); float[] point = new float[2]; diff --git a/tests/sketch/src/com/android/gesture/Prediction.java b/core/java/android/gesture/Prediction.java similarity index 96% rename from tests/sketch/src/com/android/gesture/Prediction.java rename to core/java/android/gesture/Prediction.java index 92d3ba4af604a..ce6ad5745df6c 100755 --- a/tests/sketch/src/com/android/gesture/Prediction.java +++ b/core/java/android/gesture/Prediction.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.gesture; +package android.gesture; public class Prediction { public final String name; diff --git a/tests/sketch/src/com/android/gesture/TouchThroughGesturing.java b/core/java/android/gesture/TouchThroughGestureListener.java similarity index 64% rename from tests/sketch/src/com/android/gesture/TouchThroughGesturing.java rename to core/java/android/gesture/TouchThroughGestureListener.java index fc878c8fd221e..7621ddf2781f2 100644 --- a/tests/sketch/src/com/android/gesture/TouchThroughGesturing.java +++ b/core/java/android/gesture/TouchThroughGestureListener.java @@ -14,13 +14,13 @@ * limitations under the License. */ -package com.android.gesture; +package android.gesture; -import android.graphics.Color; import android.view.MotionEvent; import android.view.View; import java.util.ArrayList; +import java.lang.ref.WeakReference; /** * TouchThroughGesturing implements the interaction behavior that allows a user @@ -28,19 +28,15 @@ import java.util.ArrayList; * still allows a user to perform basic interactions (clicking, scrolling and panning) * with the underlying widget. */ - -public class TouchThroughGesturing implements GestureListener { +public class TouchThroughGestureListener implements GestureOverlayView.OnGestureListener { public static final int SINGLE_STROKE = 0; public static final int MULTIPLE_STROKE = 1; + // TODO: Add properties for all these private static final float STROKE_LENGTH_THRESHOLD = 30; private static final float SQUARENESS_THRESHOLD = 0.275f; private static final float ANGLE_THRESHOLD = 40; - private static final boolean STEAL_EVENTS = false; - - public static final int DEFAULT_UNCERTAIN_GESTURE_COLOR = Color.argb(60, 255, 255, 0); - private boolean mIsGesturing = false; private float mTotalLength; @@ -48,18 +44,23 @@ public class TouchThroughGesturing implements GestureListener { private float mX; private float mY; - // TODO: Use WeakReference? - private View mModel; + private WeakReference mModel; private int mGestureType = SINGLE_STROKE; - private int mUncertainGestureColor = DEFAULT_UNCERTAIN_GESTURE_COLOR; // TODO: Use WeakReferences - private final ArrayList mActionListeners = - new ArrayList(); + private final ArrayList mPerformedListeners = + new ArrayList(); - public TouchThroughGesturing(View model) { - mModel = model; + private boolean mStealEvents = false; + + public TouchThroughGestureListener(View model) { + this(model, false); + } + + public TouchThroughGestureListener(View model, boolean stealEvents) { + mModel = new WeakReference(model); + mStealEvents = stealEvents; } /** @@ -70,11 +71,7 @@ public class TouchThroughGesturing implements GestureListener { mGestureType = type; } - public void setUncertainGestureColor(int color) { - mUncertainGestureColor = color; - } - - public void onStartGesture(GestureOverlay overlay, MotionEvent event) { + public void onGestureStarted(GestureOverlayView overlay, MotionEvent event) { if (mGestureType == MULTIPLE_STROKE) { overlay.cancelFadingOut(); } @@ -86,16 +83,21 @@ public class TouchThroughGesturing implements GestureListener { if (mGestureType == SINGLE_STROKE || overlay.getCurrentGesture() == null || overlay.getCurrentGesture().getStrokesCount() == 0) { - overlay.setGestureColor(mUncertainGestureColor); + overlay.setGestureDrawingColor(overlay.getUncertainGestureColor()); } - mModel.dispatchTouchEvent(event); + dispatchEventToModel(event); } - public void onGesture(GestureOverlay overlay, MotionEvent event) { + private void dispatchEventToModel(MotionEvent event) { + View v = mModel.get(); + if (v != null) v.dispatchTouchEvent(event); + } + + public void onGesture(GestureOverlayView overlay, MotionEvent event) { //noinspection PointlessBooleanExpression - if (!STEAL_EVENTS) { - mModel.dispatchTouchEvent(event); + if (!mStealEvents) { + dispatchEventToModel(event); } if (mIsGesturing) { @@ -107,7 +109,7 @@ public class TouchThroughGesturing implements GestureListener { final float dx = x - mX; final float dy = y - mY; - mTotalLength += (float)Math.sqrt(dx * dx + dy * dy); + mTotalLength += (float) Math.sqrt(dx * dx + dy * dy); mX = x; mY = y; @@ -120,8 +122,8 @@ public class TouchThroughGesturing implements GestureListener { } if (box.squareness > SQUARENESS_THRESHOLD || angle < ANGLE_THRESHOLD) { mIsGesturing = true; - overlay.setGestureColor(GestureOverlay.DEFAULT_GESTURE_COLOR); - if (STEAL_EVENTS) { + overlay.setGestureDrawingColor(overlay.getGestureColor()); + if (mStealEvents) { event = MotionEvent.obtain(event.getDownTime(), System.currentTimeMillis(), MotionEvent.ACTION_UP, x, y, event.getPressure(), event.getSize(), event.getMetaState(), event.getXPrecision(), event.getYPrecision(), @@ -130,36 +132,40 @@ public class TouchThroughGesturing implements GestureListener { } } - if (STEAL_EVENTS) { - mModel.dispatchTouchEvent(event); + if (mStealEvents) { + dispatchEventToModel(event); } } - public void onFinishGesture(GestureOverlay overlay, MotionEvent event) { + public void onGestureEnded(GestureOverlayView overlay, MotionEvent event) { if (mIsGesturing) { overlay.clear(true); - final ArrayList listeners = mActionListeners; + final ArrayList listeners = mPerformedListeners; final int count = listeners.size(); for (int i = 0; i < count; i++) { listeners.get(i).onGesturePerformed(overlay, overlay.getCurrentGesture()); } } else { - mModel.dispatchTouchEvent(event); + dispatchEventToModel(event); overlay.clear(false); } } - public void addGestureActionListener(GestureActionListener listener) { - mActionListeners.add(listener); + public void addOnGestureActionListener(OnGesturePerformedListener listener) { + mPerformedListeners.add(listener); } - public void removeGestureActionListener(GestureActionListener listener) { - mActionListeners.remove(listener); + public void removeOnGestureActionListener(OnGesturePerformedListener listener) { + mPerformedListeners.remove(listener); } public boolean isGesturing() { return mIsGesturing; } + + public static interface OnGesturePerformedListener { + public void onGesturePerformed(GestureOverlayView overlay, Gesture gesture); + } } diff --git a/core/res/res/raw/latin_lowercase b/core/res/res/raw/latin_lowercase index 9c747d69facb1..5c38b911a58fa 100644 Binary files a/core/res/res/raw/latin_lowercase and b/core/res/res/raw/latin_lowercase differ diff --git a/tests/sketch/AndroidManifest.xml b/tests/sketch/AndroidManifest.xml index 78df234efb299..fbf3a09bd224f 100755 --- a/tests/sketch/AndroidManifest.xml +++ b/tests/sketch/AndroidManifest.xml @@ -14,9 +14,7 @@ limitations under the License. --> + package="com.android.gesture.example"> 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 c9c523299f414..0000000000000 --- a/tests/sketch/src/com/android/gesture/GestureActionListener.java +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright (C) 2008-2009 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.gesture; - -public interface GestureActionListener { - public void onGesturePerformed(GestureOverlay overlay, Gesture gesture); -} diff --git a/tests/sketch/src/com/android/gesture/GestureListener.java b/tests/sketch/src/com/android/gesture/GestureListener.java deleted file mode 100755 index 9b5071401fd0a..0000000000000 --- a/tests/sketch/src/com/android/gesture/GestureListener.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (C) 2008-2009 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.gesture; - -import android.view.MotionEvent; - -/** - * An interface for processing gesture events - */ -public interface GestureListener { - public void onStartGesture(GestureOverlay overlay, MotionEvent event); - - public void onGesture(GestureOverlay overlay, MotionEvent event); - - public void onFinishGesture(GestureOverlay overlay, MotionEvent event); -} diff --git a/tests/sketch/src/com/android/gesture/example/ContactListGestureOverlay.java b/tests/sketch/src/com/android/gesture/example/ContactListGestureOverlay.java index 6eb2f2309cb49..eda42248ce452 100644 --- a/tests/sketch/src/com/android/gesture/example/ContactListGestureOverlay.java +++ b/tests/sketch/src/com/android/gesture/example/ContactListGestureOverlay.java @@ -30,12 +30,11 @@ import android.view.Window; import android.widget.AdapterView; import android.widget.ListView; -import com.android.gesture.Gesture; -import com.android.gesture.GestureActionListener; -import com.android.gesture.GestureOverlay; -import com.android.gesture.LetterRecognizer; -import com.android.gesture.Prediction; -import com.android.gesture.TouchThroughGesturing; +import android.gesture.Gesture; +import android.gesture.GestureOverlayView; +import android.gesture.LetterRecognizer; +import android.gesture.Prediction; +import android.gesture.TouchThroughGestureListener; import java.util.ArrayList; @@ -52,7 +51,7 @@ public class ContactListGestureOverlay extends Activity { private ContactAdapter mContactAdapter; - private TouchThroughGesturing mGestureProcessor; + private TouchThroughGestureListener mGestureProcessor; private LetterRecognizer mRecognizer; @@ -67,7 +66,7 @@ public class ContactListGestureOverlay extends Activity { setProgressBarIndeterminateVisibility(true); // create a letter recognizer - mRecognizer = LetterRecognizer.getLetterRecognizer(this, LetterRecognizer.LATIN_LOWERCASE); + mRecognizer = LetterRecognizer.getLetterRecognizer(this, LetterRecognizer.RECOGNIZER_LATIN_LOWERCASE); // load the contact list mContactList = (ListView) findViewById(R.id.list); @@ -95,11 +94,11 @@ public class ContactListGestureOverlay extends Activity { setProgressBarIndeterminateVisibility(false); // add a gesture overlay on top of the ListView - GestureOverlay overlay = new GestureOverlay(this); - mGestureProcessor = new TouchThroughGesturing(mContactList); - mGestureProcessor.setGestureType(TouchThroughGesturing.MULTIPLE_STROKE); - mGestureProcessor.addGestureActionListener(new GestureActionListener() { - public void onGesturePerformed(GestureOverlay overlay, Gesture gesture) { + GestureOverlayView overlay = new GestureOverlayView(this); + mGestureProcessor = new TouchThroughGestureListener(mContactList); + mGestureProcessor.setGestureType(TouchThroughGestureListener.MULTIPLE_STROKE); + mGestureProcessor.addOnGestureActionListener(new TouchThroughGestureListener.OnGesturePerformedListener() { + public void onGesturePerformed(GestureOverlayView overlay, Gesture gesture) { ArrayList predictions = mRecognizer.recognize(gesture); if (!predictions.isEmpty()) { Log.v(LOGTAG, "1st Prediction : " + predictions.get(0).name); @@ -112,7 +111,7 @@ public class ContactListGestureOverlay extends Activity { } } }); - overlay.addGestureListener(mGestureProcessor); + overlay.addOnGestureListener(mGestureProcessor); ViewGroup.LayoutParams params = new ViewGroup.LayoutParams( ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.FILL_PARENT); this.addContentView(overlay, params); diff --git a/tests/sketch/src/com/android/gesture/example/GestureEntry.java b/tests/sketch/src/com/android/gesture/example/GestureEntry.java index 53ba481bb77d3..200f89f037867 100644 --- a/tests/sketch/src/com/android/gesture/example/GestureEntry.java +++ b/tests/sketch/src/com/android/gesture/example/GestureEntry.java @@ -34,12 +34,11 @@ import android.widget.ArrayAdapter; import android.widget.EditText; import android.widget.Spinner; import android.widget.AdapterView.OnItemSelectedListener; +import android.gesture.Gesture; -import com.android.gesture.Gesture; -import com.android.gesture.GestureLibrary; -import com.android.gesture.GestureListener; -import com.android.gesture.GestureOverlay; -import com.android.gesture.Prediction; +import android.gesture.GestureLibrary; +import android.gesture.GestureOverlayView; +import android.gesture.Prediction; import java.io.File; import java.util.ArrayList; @@ -57,7 +56,7 @@ public class GestureEntry extends Activity { private static final int VIEW_ID = Menu.FIRST + 1; - private GestureOverlay mGesturePad; + private GestureOverlayView mGesturePad; private Spinner mRecognitionResult; @@ -96,17 +95,17 @@ public class GestureEntry extends Activity { }); // create the area for drawing a gesture - mGesturePad = (GestureOverlay) findViewById(R.id.drawingpad); + mGesturePad = (GestureOverlayView) findViewById(R.id.drawingpad); mGesturePad.setBackgroundColor(Color.BLACK); - mGesturePad.addGestureListener(new GestureListener() { - public void onFinishGesture(GestureOverlay overlay, MotionEvent event) { + mGesturePad.addOnGestureListener(new GestureOverlayView.OnGestureListener() { + public void onGestureEnded(GestureOverlayView overlay, MotionEvent event) { recognize(overlay.getCurrentGesture()); } - public void onGesture(GestureOverlay overlay, MotionEvent event) { + public void onGesture(GestureOverlayView overlay, MotionEvent event) { } - public void onStartGesture(GestureOverlay overlay, MotionEvent event) { + public void onGestureStarted(GestureOverlayView overlay, MotionEvent event) { overlay.clear(false); } }); diff --git a/tests/sketch/src/com/android/gesture/example/GestureLibViewer.java b/tests/sketch/src/com/android/gesture/example/GestureLibViewer.java index ca541105e6033..aa07e7b972f93 100755 --- a/tests/sketch/src/com/android/gesture/example/GestureLibViewer.java +++ b/tests/sketch/src/com/android/gesture/example/GestureLibViewer.java @@ -26,10 +26,10 @@ import android.widget.ArrayAdapter; import android.widget.Button; import android.widget.Spinner; import android.widget.AdapterView.OnItemSelectedListener; +import android.gesture.Gesture; -import com.android.gesture.Gesture; -import com.android.gesture.GestureLibrary; -import com.android.gesture.GestureOverlay; +import android.gesture.GestureLibrary; +import android.gesture.GestureOverlayView; import java.util.ArrayList; import java.util.Collections; @@ -41,7 +41,7 @@ import java.util.Collections; public class GestureLibViewer extends Activity { - private GestureOverlay mGesturePad; + private GestureOverlayView mGesturePad; private Spinner mGestureCategory; @@ -90,7 +90,7 @@ public class GestureLibViewer extends Activity { setContentView(R.layout.gestureviewer); // create the area for drawing a gesture - mGesturePad = (GestureOverlay) findViewById(R.id.drawingpad); + mGesturePad = (GestureOverlayView) findViewById(R.id.drawingpad); mGesturePad.setEnabled(false); // init the gesture library diff --git a/tests/sketch/tools/Converter.java b/tests/sketch/tools/Converter.java index b4654f8c24dc9..c0391d8612175 100644 --- a/tests/sketch/tools/Converter.java +++ b/tests/sketch/tools/Converter.java @@ -15,6 +15,7 @@ import java.io.BufferedInputStream; */ public class Converter { private final File mFile; + private static final short VERSION_NUMBER = 1; Converter(File file) { mFile = file; @@ -63,10 +64,10 @@ public class Converter { iWeights = new float[hCount][]; for (int i = 0; i < hCount; i++) { - iWeights[i] = new float[iCount]; + iWeights[i] = new float[iCount + 1]; line = reader.readLine(); startIndex = 0; - for (int j = 0; j < iCount; j++) { + for (int j = 0; j <= iCount; j++) { endIndex = line.indexOf(" ", startIndex); iWeights[i][j] = Float.parseFloat(line.substring(startIndex, endIndex)); startIndex = endIndex + 1; @@ -75,10 +76,10 @@ public class Converter { oWeights = new float[oCount][]; for (int i = 0; i < oCount; i++) { - oWeights[i] = new float[hCount]; + oWeights[i] = new float[hCount + 1]; line = reader.readLine(); startIndex = 0; - for (int j = 0; j < hCount; j++) { + for (int j = 0; j <= hCount; j++) { endIndex = line.indexOf(" ", startIndex); oWeights[i][j] = Float.parseFloat(line.substring(startIndex, endIndex)); startIndex = endIndex + 1; @@ -105,6 +106,7 @@ public class Converter { try { out = new DataOutputStream(new FileOutputStream(mFile)); + out.writeShort(VERSION_NUMBER); out.writeInt(iCount); out.writeInt(hCount); out.writeInt(oCount);