Merge change 2285 into donut
* changes: Move the Gestures API to the framework in android.gesture.
This commit is contained in:
1091
api/current.xml
1091
api/current.xml
File diff suppressed because it is too large
Load Diff
@@ -14,7 +14,7 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.android.gesture;
|
package android.gesture;
|
||||||
|
|
||||||
import android.graphics.Bitmap;
|
import android.graphics.Bitmap;
|
||||||
import android.graphics.Canvas;
|
import android.graphics.Canvas;
|
||||||
@@ -32,8 +32,6 @@ import java.io.ByteArrayOutputStream;
|
|||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
|
||||||
import static com.android.gesture.GestureConstants.LOG_TAG;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A gesture can have a single or multiple strokes
|
* A gesture can have a single or multiple strokes
|
||||||
*/
|
*/
|
||||||
@@ -242,26 +240,6 @@ public class Gesture implements Parcelable {
|
|||||||
return gesture;
|
return gesture;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Convert the gesture to string
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
final StringBuilder str = new StringBuilder();
|
|
||||||
str.append(mGestureID);
|
|
||||||
|
|
||||||
final ArrayList<GestureStroke> strokes = mStrokes;
|
|
||||||
final int count = strokes.size();
|
|
||||||
|
|
||||||
for (int i = 0; i < count; i++) {
|
|
||||||
final GestureStroke stroke = strokes.get(i);
|
|
||||||
str.append(GestureConstants.STRING_GESTURE_DELIIMITER);
|
|
||||||
str.append(stroke.toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
return str.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static final Parcelable.Creator<Gesture> CREATOR = new Parcelable.Creator<Gesture>() {
|
public static final Parcelable.Creator<Gesture> CREATOR = new Parcelable.Creator<Gesture>() {
|
||||||
public Gesture createFromParcel(Parcel in) {
|
public Gesture createFromParcel(Parcel in) {
|
||||||
Gesture gesture = null;
|
Gesture gesture = null;
|
||||||
@@ -273,7 +251,7 @@ public class Gesture implements Parcelable {
|
|||||||
try {
|
try {
|
||||||
gesture = deserialize(inStream);
|
gesture = deserialize(inStream);
|
||||||
} catch (IOException e) {
|
} 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 {
|
} finally {
|
||||||
GestureUtilities.closeStream(inStream);
|
GestureUtilities.closeStream(inStream);
|
||||||
}
|
}
|
||||||
@@ -302,7 +280,7 @@ public class Gesture implements Parcelable {
|
|||||||
serialize(outStream);
|
serialize(outStream);
|
||||||
result = true;
|
result = true;
|
||||||
} catch (IOException e) {
|
} 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 {
|
} finally {
|
||||||
GestureUtilities.closeStream(outStream);
|
GestureUtilities.closeStream(outStream);
|
||||||
GestureUtilities.closeStream(byteStream);
|
GestureUtilities.closeStream(byteStream);
|
||||||
@@ -14,12 +14,9 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.android.gesture;
|
package android.gesture;
|
||||||
|
|
||||||
interface GestureConstants {
|
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_STRING_BUFFER_SIZE = 1024;
|
||||||
static final int STROKE_POINT_BUFFER_SIZE = 100; // number of points
|
static final int STROKE_POINT_BUFFER_SIZE = 100; // number of points
|
||||||
|
|
||||||
@@ -14,7 +14,7 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.android.gesture;
|
package android.gesture;
|
||||||
|
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.os.SystemClock;
|
import android.os.SystemClock;
|
||||||
@@ -32,7 +32,7 @@ import java.util.HashMap;
|
|||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.Map;
|
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
|
* GestureLibrary maintains gesture examples and makes predictions on a new
|
||||||
@@ -190,7 +190,7 @@ public class GestureLibrary {
|
|||||||
*
|
*
|
||||||
* @param entryName the entry name
|
* @param entryName the entry name
|
||||||
*/
|
*/
|
||||||
public void removeEntireEntry(String entryName) {
|
public void removeEntry(String entryName) {
|
||||||
mNamedGestures.remove(entryName);
|
mNamedGestures.remove(entryName);
|
||||||
mClassifier.removeInstances(entryName);
|
mClassifier.removeInstances(entryName);
|
||||||
mChanged = true;
|
mChanged = true;
|
||||||
@@ -14,7 +14,7 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.android.gesture;
|
package android.gesture;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.graphics.Bitmap;
|
import android.graphics.Bitmap;
|
||||||
@@ -23,6 +23,7 @@ import android.graphics.Canvas;
|
|||||||
import android.graphics.Paint;
|
import android.graphics.Paint;
|
||||||
import android.graphics.Path;
|
import android.graphics.Path;
|
||||||
import android.graphics.Rect;
|
import android.graphics.Rect;
|
||||||
|
import android.graphics.Color;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.util.AttributeSet;
|
import android.util.AttributeSet;
|
||||||
import android.view.MotionEvent;
|
import android.view.MotionEvent;
|
||||||
@@ -35,7 +36,7 @@ import java.util.ArrayList;
|
|||||||
* widgets. The view can also be opaque.
|
* widgets. The view can also be opaque.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public class GestureOverlay extends View {
|
public class GestureOverlayView extends View {
|
||||||
static final float TOUCH_TOLERANCE = 3;
|
static final float TOUCH_TOLERANCE = 3;
|
||||||
|
|
||||||
// TODO: Move all these values into XML attributes
|
// TODO: Move all these values into XML attributes
|
||||||
@@ -52,20 +53,22 @@ public class GestureOverlay extends View {
|
|||||||
private static final boolean DITHER_FLAG = true;
|
private static final boolean DITHER_FLAG = true;
|
||||||
|
|
||||||
public static final int DEFAULT_GESTURE_COLOR = 0xFFFFFF00;
|
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 int REFRESH_RANGE = 10;
|
||||||
|
|
||||||
private static final BlurMaskFilter BLUR_MASK_FILTER =
|
private static final BlurMaskFilter BLUR_MASK_FILTER =
|
||||||
new BlurMaskFilter(1, BlurMaskFilter.Blur.NORMAL);
|
new BlurMaskFilter(1, BlurMaskFilter.Blur.NORMAL);
|
||||||
|
|
||||||
|
|
||||||
// double buffering
|
|
||||||
private Paint mGesturePaint;
|
private Paint mGesturePaint;
|
||||||
|
|
||||||
private final Paint mBitmapPaint = new Paint(Paint.DITHER_FLAG);
|
private final Paint mBitmapPaint = new Paint(Paint.DITHER_FLAG);
|
||||||
private Bitmap mBitmap; // with transparent background
|
private Bitmap mBitmap; // with transparent background
|
||||||
private Canvas mBitmapCanvas;
|
private Canvas mBitmapCanvas;
|
||||||
|
|
||||||
|
private int mCertainGestureColor = DEFAULT_GESTURE_COLOR;
|
||||||
|
private int mUncertainGestureColor = DEFAULT_UNCERTAIN_GESTURE_COLOR;
|
||||||
|
|
||||||
// for rendering immediate ink feedback
|
// for rendering immediate ink feedback
|
||||||
private Rect mInvalidRect = new Rect();
|
private Rect mInvalidRect = new Rect();
|
||||||
|
|
||||||
@@ -81,7 +84,7 @@ public class GestureOverlay extends View {
|
|||||||
private Gesture mCurrentGesture = null;
|
private Gesture mCurrentGesture = null;
|
||||||
|
|
||||||
// TODO: Make this a list of WeakReferences
|
// TODO: Make this a list of WeakReferences
|
||||||
private final ArrayList<GestureListener> mGestureListeners = new ArrayList<GestureListener>();
|
private final ArrayList<OnGestureListener> mOnGestureListeners = new ArrayList<OnGestureListener>();
|
||||||
private ArrayList<GesturePoint> mPointBuffer = null;
|
private ArrayList<GesturePoint> mPointBuffer = null;
|
||||||
|
|
||||||
// fading out effect
|
// fading out effect
|
||||||
@@ -107,12 +110,12 @@ public class GestureOverlay extends View {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
public GestureOverlay(Context context) {
|
public GestureOverlayView(Context context) {
|
||||||
super(context);
|
super(context);
|
||||||
init();
|
init();
|
||||||
}
|
}
|
||||||
|
|
||||||
public GestureOverlay(Context context, AttributeSet attrs) {
|
public GestureOverlayView(Context context, AttributeSet attrs) {
|
||||||
super(context, attrs);
|
super(context, attrs);
|
||||||
init();
|
init();
|
||||||
}
|
}
|
||||||
@@ -130,7 +133,7 @@ public class GestureOverlay extends View {
|
|||||||
*
|
*
|
||||||
* @param color
|
* @param color
|
||||||
*/
|
*/
|
||||||
public void setGestureColor(int color) {
|
public void setGestureDrawingColor(int color) {
|
||||||
mGesturePaint.setColor(color);
|
mGesturePaint.setColor(color);
|
||||||
if (mCurrentGesture != null) {
|
if (mCurrentGesture != null) {
|
||||||
mBitmap.eraseColor(TRANSPARENT_BACKGROUND);
|
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
|
* Set the gesture to be shown in the view
|
||||||
*
|
*
|
||||||
@@ -199,12 +218,12 @@ public class GestureOverlay extends View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addGestureListener(GestureListener listener) {
|
public void addOnGestureListener(OnGestureListener listener) {
|
||||||
mGestureListeners.add(listener);
|
mOnGestureListeners.add(listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void removeGestureListener(GestureListener listener) {
|
public void removeOnGestureListener(OnGestureListener listener) {
|
||||||
mGestureListeners.remove(listener);
|
mOnGestureListeners.remove(listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -281,11 +300,11 @@ public class GestureOverlay extends View {
|
|||||||
|
|
||||||
private Rect touchStart(MotionEvent event) {
|
private Rect touchStart(MotionEvent event) {
|
||||||
// pass the event to handlers
|
// pass the event to handlers
|
||||||
final ArrayList<GestureListener> listeners = mGestureListeners;
|
final ArrayList<OnGestureListener> listeners = mOnGestureListeners;
|
||||||
final int count = listeners.size();
|
final int count = listeners.size();
|
||||||
for (int i = 0; i < count; i++) {
|
for (int i = 0; i < count; i++) {
|
||||||
GestureListener listener = listeners.get(i);
|
OnGestureListener listener = listeners.get(i);
|
||||||
listener.onStartGesture(this, event);
|
listener.onGestureStarted(this, event);
|
||||||
}
|
}
|
||||||
|
|
||||||
// if there is fading out going on, stop it.
|
// 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()));
|
mPointBuffer.add(new GesturePoint(x, y, event.getEventTime()));
|
||||||
|
|
||||||
// pass the event to handlers
|
// pass the event to handlers
|
||||||
final ArrayList<GestureListener> listeners = mGestureListeners;
|
final ArrayList<OnGestureListener> listeners = mOnGestureListeners;
|
||||||
final int count = listeners.size();
|
final int count = listeners.size();
|
||||||
for (int i = 0; i < count; i++) {
|
for (int i = 0; i < count; i++) {
|
||||||
listeners.get(i).onGesture(this, event);
|
listeners.get(i).onGesture(this, event);
|
||||||
@@ -377,14 +396,24 @@ public class GestureOverlay extends View {
|
|||||||
mGesturePaint.setMaskFilter(null);
|
mGesturePaint.setMaskFilter(null);
|
||||||
|
|
||||||
// pass the event to handlers
|
// pass the event to handlers
|
||||||
final ArrayList<GestureListener> listeners = mGestureListeners;
|
final ArrayList<OnGestureListener> listeners = mOnGestureListeners;
|
||||||
final int count = listeners.size();
|
final int count = listeners.size();
|
||||||
for (int i = 0; i < count; i++) {
|
for (int i = 0; i < count; i++) {
|
||||||
listeners.get(i).onFinishGesture(this, event);
|
listeners.get(i).onGestureEnded(this, event);
|
||||||
}
|
}
|
||||||
|
|
||||||
mPath = null;
|
mPath = null;
|
||||||
mPointBuffer = 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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -14,7 +14,7 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.android.gesture;
|
package android.gesture;
|
||||||
|
|
||||||
import java.io.DataInputStream;
|
import java.io.DataInputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@@ -14,7 +14,7 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.android.gesture;
|
package android.gesture;
|
||||||
|
|
||||||
import android.graphics.Canvas;
|
import android.graphics.Canvas;
|
||||||
import android.graphics.Matrix;
|
import android.graphics.Matrix;
|
||||||
@@ -126,16 +126,16 @@ public class GestureStroke {
|
|||||||
* @param width the width of the bounding box of the target 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 height the height of the bounding box of the target path
|
||||||
* @param numSample the number of points needed
|
* @param numSample the number of points needed
|
||||||
|
*
|
||||||
* @return the path
|
* @return the path
|
||||||
*/
|
*/
|
||||||
public Path toPath(float width, float height, int numSample) {
|
public Path toPath(float width, float height, int numSample) {
|
||||||
final float[] pts = GestureUtilities.temporalSampling(this, numSample);
|
final float[] pts = GestureUtilities.temporalSampling(this, numSample);
|
||||||
final RectF rect = boundingBox;
|
final RectF rect = boundingBox;
|
||||||
final float scale = height / rect.height();
|
|
||||||
|
|
||||||
final Matrix matrix = new Matrix();
|
final Matrix matrix = new Matrix();
|
||||||
matrix.setTranslate(-rect.left, -rect.top);
|
matrix.setTranslate(-rect.left, -rect.top);
|
||||||
matrix.postScale(scale, scale);
|
matrix.postScale(width / rect.width(), height / rect.height());
|
||||||
matrix.mapPoints(pts);
|
matrix.mapPoints(pts);
|
||||||
|
|
||||||
float mX = 0;
|
float mX = 0;
|
||||||
@@ -156,7 +156,8 @@ public class GestureStroke {
|
|||||||
} else {
|
} else {
|
||||||
float dx = Math.abs(x - mX);
|
float dx = Math.abs(x - mX);
|
||||||
float dy = Math.abs(y - mY);
|
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);
|
path.quadTo(mX, mY, (x + mX) / 2, (y + mY) / 2);
|
||||||
mX = x;
|
mX = x;
|
||||||
mY = y;
|
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 void clearPath() {
|
||||||
public String toString() {
|
if (mCachedPath != null) mCachedPath.rewind();
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -14,7 +14,7 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.android.gesture;
|
package android.gesture;
|
||||||
|
|
||||||
import android.graphics.RectF;
|
import android.graphics.RectF;
|
||||||
import android.graphics.Matrix;
|
import android.graphics.Matrix;
|
||||||
@@ -25,7 +25,7 @@ import java.util.Arrays;
|
|||||||
import java.io.Closeable;
|
import java.io.Closeable;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
import static com.android.gesture.GestureConstants.*;
|
import static android.gesture.GestureConstants.*;
|
||||||
|
|
||||||
final class GestureUtilities {
|
final class GestureUtilities {
|
||||||
private static final int TEMPORAL_SAMPLING_RATE = 16;
|
private static final int TEMPORAL_SAMPLING_RATE = 16;
|
||||||
@@ -14,7 +14,7 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.android.gesture;
|
package android.gesture;
|
||||||
|
|
||||||
import android.graphics.Matrix;
|
import android.graphics.Matrix;
|
||||||
|
|
||||||
@@ -14,10 +14,11 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.android.gesture;
|
package android.gesture;
|
||||||
|
|
||||||
import android.util.Config;
|
import android.util.Config;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
import static android.gesture.GestureConstants.*;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
@@ -30,9 +31,6 @@ import java.util.TreeMap;
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
class InstanceLearner extends Learner {
|
class InstanceLearner extends Learner {
|
||||||
|
|
||||||
private static final String LOGTAG = "InstanceLearner";
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
ArrayList<Prediction> classify(int gestureType, float[] vector) {
|
ArrayList<Prediction> classify(int gestureType, float[] vector) {
|
||||||
ArrayList<Prediction> predictions = new ArrayList<Prediction>();
|
ArrayList<Prediction> predictions = new ArrayList<Prediction>();
|
||||||
@@ -63,19 +61,15 @@ class InstanceLearner extends Learner {
|
|||||||
}
|
}
|
||||||
|
|
||||||
double sum = 0;
|
double sum = 0;
|
||||||
Iterator<String> lableIterator = label2score.keySet().iterator();
|
for (String name : label2score.keySet()) {
|
||||||
while (lableIterator.hasNext()) {
|
|
||||||
String name = lableIterator.next();
|
|
||||||
double score = label2score.get(name);
|
double score = label2score.get(name);
|
||||||
sum += score;
|
sum += score;
|
||||||
predictions.add(new Prediction(name, score));
|
predictions.add(new Prediction(name, score));
|
||||||
}
|
}
|
||||||
|
|
||||||
// normalize
|
// normalize
|
||||||
Iterator<Prediction> predictionIterator = predictions.iterator();
|
for (Prediction prediction : predictions) {
|
||||||
while (predictionIterator.hasNext()) {
|
prediction.score /= sum;
|
||||||
Prediction name = predictionIterator.next();
|
|
||||||
name.score /= sum;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Collections.sort(predictions, new Comparator<Prediction>() {
|
Collections.sort(predictions, new Comparator<Prediction>() {
|
||||||
@@ -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;
|
return predictions;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -14,7 +14,7 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.android.gesture;
|
package android.gesture;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
|
||||||
@@ -14,7 +14,7 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.android.gesture;
|
package android.gesture;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.res.Resources;
|
import android.content.res.Resources;
|
||||||
@@ -28,10 +28,13 @@ import java.util.Collections;
|
|||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
|
||||||
import static com.android.gesture.GestureConstants.LOG_TAG;
|
import static android.gesture.GestureConstants.LOG_TAG;
|
||||||
|
|
||||||
public class LetterRecognizer {
|
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[] mHiddenLayer;
|
||||||
private SigmoidUnit[] mOutputLayer;
|
private SigmoidUnit[] mOutputLayer;
|
||||||
@@ -40,19 +43,20 @@ public class LetterRecognizer {
|
|||||||
|
|
||||||
private final int mPatchSize;
|
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 {
|
private static class SigmoidUnit {
|
||||||
final float[] mWeights;
|
final float[] mWeights;
|
||||||
|
|
||||||
|
private boolean mComputed;
|
||||||
|
private float mResult;
|
||||||
|
|
||||||
SigmoidUnit(float[] weights) {
|
SigmoidUnit(float[] weights) {
|
||||||
mWeights = weights;
|
mWeights = weights;
|
||||||
}
|
}
|
||||||
|
|
||||||
private float compute(float[] inputs) {
|
private float compute(float[] inputs) {
|
||||||
|
if (!mComputed) {
|
||||||
float sum = 0;
|
float sum = 0;
|
||||||
|
|
||||||
final int count = inputs.length;
|
final int count = inputs.length;
|
||||||
@@ -63,8 +67,20 @@ public class LetterRecognizer {
|
|||||||
}
|
}
|
||||||
sum += weights[weights.length - 1];
|
sum += weights[weights.length - 1];
|
||||||
|
|
||||||
return 1.0f / (float) (1 + Math.exp(-sum));
|
mResult = 1.0f / (float) (1 + Math.exp(-sum));
|
||||||
|
mComputed = true;
|
||||||
}
|
}
|
||||||
|
return mResult;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static LetterRecognizer getLetterRecognizer(Context context, int type) {
|
||||||
|
switch (type) {
|
||||||
|
case RECOGNIZER_LATIN_LOWERCASE: {
|
||||||
|
return createFromResource(context, com.android.internal.R.raw.latin_lowercase);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private LetterRecognizer(int numOfInput, int numOfHidden, String[] classes) {
|
private LetterRecognizer(int numOfInput, int numOfHidden, String[] classes) {
|
||||||
@@ -74,25 +90,10 @@ public class LetterRecognizer {
|
|||||||
mOutputLayer = new SigmoidUnit[classes.length];
|
mOutputLayer = new SigmoidUnit[classes.length];
|
||||||
}
|
}
|
||||||
|
|
||||||
public void save() {
|
|
||||||
mGestureLibrary.save();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static LetterRecognizer getLetterRecognizer(Context context, int type) {
|
|
||||||
switch (type) {
|
|
||||||
case LATIN_LOWERCASE: {
|
|
||||||
return createFromResource(context, com.android.internal.R.raw.latin_lowercase);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ArrayList<Prediction> recognize(Gesture gesture) {
|
public ArrayList<Prediction> recognize(Gesture gesture) {
|
||||||
float[] query = GestureUtilities.spatialSampling(gesture, mPatchSize);
|
float[] query = GestureUtilities.spatialSampling(gesture, mPatchSize);
|
||||||
ArrayList<Prediction> predictions = classify(query);
|
ArrayList<Prediction> predictions = classify(query);
|
||||||
if (mGestureLibrary != null) {
|
|
||||||
adjustPrediction(gesture, predictions);
|
adjustPrediction(gesture, predictions);
|
||||||
}
|
|
||||||
return predictions;
|
return predictions;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -153,38 +154,14 @@ public class LetterRecognizer {
|
|||||||
in = new DataInputStream(new BufferedInputStream(resources.openRawResource(resourceID),
|
in = new DataInputStream(new BufferedInputStream(resources.openRawResource(resourceID),
|
||||||
GestureConstants.IO_BUFFER_SIZE));
|
GestureConstants.IO_BUFFER_SIZE));
|
||||||
|
|
||||||
final int iCount = in.readInt();
|
final int version = in.readShort();
|
||||||
final int hCount = in.readInt();
|
|
||||||
final int oCount = in.readInt();
|
|
||||||
|
|
||||||
final String[] classes = new String[oCount];
|
switch (version) {
|
||||||
for (int i = 0; i < classes.length; i++) {
|
case 1:
|
||||||
classes[i] = in.readUTF();
|
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) {
|
} catch (IOException e) {
|
||||||
Log.d(LOG_TAG, "Failed to load handwriting data:", e);
|
Log.d(LOG_TAG, "Failed to load handwriting data:", e);
|
||||||
} finally {
|
} finally {
|
||||||
@@ -194,8 +171,64 @@ public class LetterRecognizer {
|
|||||||
return classifier;
|
return classifier;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void enablePersonalization(boolean enable) {
|
private static LetterRecognizer readV1(DataInputStream in) throws IOException {
|
||||||
if (enable) {
|
|
||||||
|
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 = new GestureLibrary(GESTURE_FILE_NAME);
|
||||||
mGestureLibrary.setSequenceType(GestureLibrary.SEQUENCE_INVARIANT);
|
mGestureLibrary.setSequenceType(GestureLibrary.SEQUENCE_INVARIANT);
|
||||||
mGestureLibrary.load();
|
mGestureLibrary.load();
|
||||||
@@ -204,21 +237,32 @@ 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) {
|
public void addExample(String letter, Gesture example) {
|
||||||
|
if (mGestureLibrary != null) {
|
||||||
mGestureLibrary.addGesture(letter, example);
|
mGestureLibrary.addGesture(letter, example);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void adjustPrediction(Gesture query, ArrayList<Prediction> predictions) {
|
private void adjustPrediction(Gesture query, ArrayList<Prediction> predictions) {
|
||||||
ArrayList<Prediction> results = mGestureLibrary.recognize(query);
|
if (mGestureLibrary != null) {
|
||||||
HashMap<String, Prediction> topNList = new HashMap<String, Prediction>();
|
final ArrayList<Prediction> results = mGestureLibrary.recognize(query);
|
||||||
|
final HashMap<String, Prediction> topNList = new HashMap<String, Prediction>();
|
||||||
|
|
||||||
for (int j = 0; j < ADJUST_RANGE; j++) {
|
for (int j = 0; j < ADJUST_RANGE; j++) {
|
||||||
Prediction prediction = predictions.remove(0);
|
Prediction prediction = predictions.remove(0);
|
||||||
topNList.put(prediction.name, prediction);
|
topNList.put(prediction.name, prediction);
|
||||||
}
|
}
|
||||||
int count = results.size();
|
|
||||||
|
final int count = results.size();
|
||||||
for (int j = count - 1; j >= 0 && !topNList.isEmpty(); j--) {
|
for (int j = count - 1; j >= 0 && !topNList.isEmpty(); j--) {
|
||||||
Prediction item = results.get(j);
|
final Prediction item = results.get(j);
|
||||||
Prediction original = topNList.get(item.name);
|
final Prediction original = topNList.get(item.name);
|
||||||
if (original != null) {
|
if (original != null) {
|
||||||
predictions.add(0, original);
|
predictions.add(0, original);
|
||||||
topNList.remove(item.name);
|
topNList.remove(item.name);
|
||||||
@@ -226,3 +270,4 @@ public class LetterRecognizer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
@@ -14,7 +14,7 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.android.gesture;
|
package android.gesture;
|
||||||
|
|
||||||
import android.graphics.Matrix;
|
import android.graphics.Matrix;
|
||||||
import android.graphics.Path;
|
import android.graphics.Path;
|
||||||
@@ -47,6 +47,11 @@ public class OrientedBoundingBox {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Currently used for debugging purpose only.
|
||||||
|
*
|
||||||
|
* @hide
|
||||||
|
*/
|
||||||
public Path toPath() {
|
public Path toPath() {
|
||||||
Path path = new Path();
|
Path path = new Path();
|
||||||
float[] point = new float[2];
|
float[] point = new float[2];
|
||||||
@@ -14,7 +14,7 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.android.gesture;
|
package android.gesture;
|
||||||
|
|
||||||
public class Prediction {
|
public class Prediction {
|
||||||
public final String name;
|
public final String name;
|
||||||
@@ -14,13 +14,13 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.android.gesture;
|
package android.gesture;
|
||||||
|
|
||||||
import android.graphics.Color;
|
|
||||||
import android.view.MotionEvent;
|
import android.view.MotionEvent;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.lang.ref.WeakReference;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TouchThroughGesturing implements the interaction behavior that allows a user
|
* 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)
|
* still allows a user to perform basic interactions (clicking, scrolling and panning)
|
||||||
* with the underlying widget.
|
* with the underlying widget.
|
||||||
*/
|
*/
|
||||||
|
public class TouchThroughGestureListener implements GestureOverlayView.OnGestureListener {
|
||||||
public class TouchThroughGesturing implements GestureListener {
|
|
||||||
public static final int SINGLE_STROKE = 0;
|
public static final int SINGLE_STROKE = 0;
|
||||||
public static final int MULTIPLE_STROKE = 1;
|
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 STROKE_LENGTH_THRESHOLD = 30;
|
||||||
private static final float SQUARENESS_THRESHOLD = 0.275f;
|
private static final float SQUARENESS_THRESHOLD = 0.275f;
|
||||||
private static final float ANGLE_THRESHOLD = 40;
|
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 boolean mIsGesturing = false;
|
||||||
|
|
||||||
private float mTotalLength;
|
private float mTotalLength;
|
||||||
@@ -48,18 +44,23 @@ public class TouchThroughGesturing implements GestureListener {
|
|||||||
private float mX;
|
private float mX;
|
||||||
private float mY;
|
private float mY;
|
||||||
|
|
||||||
// TODO: Use WeakReference?
|
private WeakReference<View> mModel;
|
||||||
private View mModel;
|
|
||||||
|
|
||||||
private int mGestureType = SINGLE_STROKE;
|
private int mGestureType = SINGLE_STROKE;
|
||||||
private int mUncertainGestureColor = DEFAULT_UNCERTAIN_GESTURE_COLOR;
|
|
||||||
|
|
||||||
// TODO: Use WeakReferences
|
// TODO: Use WeakReferences
|
||||||
private final ArrayList<GestureActionListener> mActionListeners =
|
private final ArrayList<OnGesturePerformedListener> mPerformedListeners =
|
||||||
new ArrayList<GestureActionListener>();
|
new ArrayList<OnGesturePerformedListener>();
|
||||||
|
|
||||||
public TouchThroughGesturing(View model) {
|
private boolean mStealEvents = false;
|
||||||
mModel = model;
|
|
||||||
|
public TouchThroughGestureListener(View model) {
|
||||||
|
this(model, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public TouchThroughGestureListener(View model, boolean stealEvents) {
|
||||||
|
mModel = new WeakReference<View>(model);
|
||||||
|
mStealEvents = stealEvents;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -70,11 +71,7 @@ public class TouchThroughGesturing implements GestureListener {
|
|||||||
mGestureType = type;
|
mGestureType = type;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setUncertainGestureColor(int color) {
|
public void onGestureStarted(GestureOverlayView overlay, MotionEvent event) {
|
||||||
mUncertainGestureColor = color;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void onStartGesture(GestureOverlay overlay, MotionEvent event) {
|
|
||||||
if (mGestureType == MULTIPLE_STROKE) {
|
if (mGestureType == MULTIPLE_STROKE) {
|
||||||
overlay.cancelFadingOut();
|
overlay.cancelFadingOut();
|
||||||
}
|
}
|
||||||
@@ -86,16 +83,21 @@ public class TouchThroughGesturing implements GestureListener {
|
|||||||
|
|
||||||
if (mGestureType == SINGLE_STROKE || overlay.getCurrentGesture() == null
|
if (mGestureType == SINGLE_STROKE || overlay.getCurrentGesture() == null
|
||||||
|| overlay.getCurrentGesture().getStrokesCount() == 0) {
|
|| 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
|
//noinspection PointlessBooleanExpression
|
||||||
if (!STEAL_EVENTS) {
|
if (!mStealEvents) {
|
||||||
mModel.dispatchTouchEvent(event);
|
dispatchEventToModel(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mIsGesturing) {
|
if (mIsGesturing) {
|
||||||
@@ -120,8 +122,8 @@ public class TouchThroughGesturing implements GestureListener {
|
|||||||
}
|
}
|
||||||
if (box.squareness > SQUARENESS_THRESHOLD || angle < ANGLE_THRESHOLD) {
|
if (box.squareness > SQUARENESS_THRESHOLD || angle < ANGLE_THRESHOLD) {
|
||||||
mIsGesturing = true;
|
mIsGesturing = true;
|
||||||
overlay.setGestureColor(GestureOverlay.DEFAULT_GESTURE_COLOR);
|
overlay.setGestureDrawingColor(overlay.getGestureColor());
|
||||||
if (STEAL_EVENTS) {
|
if (mStealEvents) {
|
||||||
event = MotionEvent.obtain(event.getDownTime(), System.currentTimeMillis(),
|
event = MotionEvent.obtain(event.getDownTime(), System.currentTimeMillis(),
|
||||||
MotionEvent.ACTION_UP, x, y, event.getPressure(), event.getSize(),
|
MotionEvent.ACTION_UP, x, y, event.getPressure(), event.getSize(),
|
||||||
event.getMetaState(), event.getXPrecision(), event.getYPrecision(),
|
event.getMetaState(), event.getXPrecision(), event.getYPrecision(),
|
||||||
@@ -130,36 +132,40 @@ public class TouchThroughGesturing implements GestureListener {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (STEAL_EVENTS) {
|
if (mStealEvents) {
|
||||||
mModel.dispatchTouchEvent(event);
|
dispatchEventToModel(event);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onFinishGesture(GestureOverlay overlay, MotionEvent event) {
|
public void onGestureEnded(GestureOverlayView overlay, MotionEvent event) {
|
||||||
if (mIsGesturing) {
|
if (mIsGesturing) {
|
||||||
overlay.clear(true);
|
overlay.clear(true);
|
||||||
|
|
||||||
final ArrayList<GestureActionListener> listeners = mActionListeners;
|
final ArrayList<OnGesturePerformedListener> listeners = mPerformedListeners;
|
||||||
final int count = listeners.size();
|
final int count = listeners.size();
|
||||||
|
|
||||||
for (int i = 0; i < count; i++) {
|
for (int i = 0; i < count; i++) {
|
||||||
listeners.get(i).onGesturePerformed(overlay, overlay.getCurrentGesture());
|
listeners.get(i).onGesturePerformed(overlay, overlay.getCurrentGesture());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
mModel.dispatchTouchEvent(event);
|
dispatchEventToModel(event);
|
||||||
overlay.clear(false);
|
overlay.clear(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addGestureActionListener(GestureActionListener listener) {
|
public void addOnGestureActionListener(OnGesturePerformedListener listener) {
|
||||||
mActionListeners.add(listener);
|
mPerformedListeners.add(listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void removeGestureActionListener(GestureActionListener listener) {
|
public void removeOnGestureActionListener(OnGesturePerformedListener listener) {
|
||||||
mActionListeners.remove(listener);
|
mPerformedListeners.remove(listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isGesturing() {
|
public boolean isGesturing() {
|
||||||
return mIsGesturing;
|
return mIsGesturing;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static interface OnGesturePerformedListener {
|
||||||
|
public void onGesturePerformed(GestureOverlayView overlay, Gesture gesture);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Binary file not shown.
|
Before Width: | Height: | Size: 35 KiB After Width: | Height: | Size: 28 KiB |
@@ -14,9 +14,7 @@
|
|||||||
limitations under the License.
|
limitations under the License.
|
||||||
-->
|
-->
|
||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
package="com.android.gesture.example"
|
package="com.android.gesture.example">
|
||||||
android:versionCode="1"
|
|
||||||
android:versionName="1.0.0">
|
|
||||||
|
|
||||||
<uses-permission android:name="android.permission.READ_CONTACTS" />
|
<uses-permission android:name="android.permission.READ_CONTACTS" />
|
||||||
<uses-permission android:name="android.permission.WRITE_SDCARD" />
|
<uses-permission android:name="android.permission.WRITE_SDCARD" />
|
||||||
|
|||||||
@@ -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);
|
|
||||||
}
|
|
||||||
@@ -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);
|
|
||||||
}
|
|
||||||
@@ -30,12 +30,11 @@ import android.view.Window;
|
|||||||
import android.widget.AdapterView;
|
import android.widget.AdapterView;
|
||||||
import android.widget.ListView;
|
import android.widget.ListView;
|
||||||
|
|
||||||
import com.android.gesture.Gesture;
|
import android.gesture.Gesture;
|
||||||
import com.android.gesture.GestureActionListener;
|
import android.gesture.GestureOverlayView;
|
||||||
import com.android.gesture.GestureOverlay;
|
import android.gesture.LetterRecognizer;
|
||||||
import com.android.gesture.LetterRecognizer;
|
import android.gesture.Prediction;
|
||||||
import com.android.gesture.Prediction;
|
import android.gesture.TouchThroughGestureListener;
|
||||||
import com.android.gesture.TouchThroughGesturing;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
|
||||||
@@ -52,7 +51,7 @@ public class ContactListGestureOverlay extends Activity {
|
|||||||
|
|
||||||
private ContactAdapter mContactAdapter;
|
private ContactAdapter mContactAdapter;
|
||||||
|
|
||||||
private TouchThroughGesturing mGestureProcessor;
|
private TouchThroughGestureListener mGestureProcessor;
|
||||||
|
|
||||||
private LetterRecognizer mRecognizer;
|
private LetterRecognizer mRecognizer;
|
||||||
|
|
||||||
@@ -67,7 +66,7 @@ public class ContactListGestureOverlay extends Activity {
|
|||||||
setProgressBarIndeterminateVisibility(true);
|
setProgressBarIndeterminateVisibility(true);
|
||||||
|
|
||||||
// create a letter recognizer
|
// create a letter recognizer
|
||||||
mRecognizer = LetterRecognizer.getLetterRecognizer(this, LetterRecognizer.LATIN_LOWERCASE);
|
mRecognizer = LetterRecognizer.getLetterRecognizer(this, LetterRecognizer.RECOGNIZER_LATIN_LOWERCASE);
|
||||||
|
|
||||||
// load the contact list
|
// load the contact list
|
||||||
mContactList = (ListView) findViewById(R.id.list);
|
mContactList = (ListView) findViewById(R.id.list);
|
||||||
@@ -95,11 +94,11 @@ public class ContactListGestureOverlay extends Activity {
|
|||||||
setProgressBarIndeterminateVisibility(false);
|
setProgressBarIndeterminateVisibility(false);
|
||||||
|
|
||||||
// add a gesture overlay on top of the ListView
|
// add a gesture overlay on top of the ListView
|
||||||
GestureOverlay overlay = new GestureOverlay(this);
|
GestureOverlayView overlay = new GestureOverlayView(this);
|
||||||
mGestureProcessor = new TouchThroughGesturing(mContactList);
|
mGestureProcessor = new TouchThroughGestureListener(mContactList);
|
||||||
mGestureProcessor.setGestureType(TouchThroughGesturing.MULTIPLE_STROKE);
|
mGestureProcessor.setGestureType(TouchThroughGestureListener.MULTIPLE_STROKE);
|
||||||
mGestureProcessor.addGestureActionListener(new GestureActionListener() {
|
mGestureProcessor.addOnGestureActionListener(new TouchThroughGestureListener.OnGesturePerformedListener() {
|
||||||
public void onGesturePerformed(GestureOverlay overlay, Gesture gesture) {
|
public void onGesturePerformed(GestureOverlayView overlay, Gesture gesture) {
|
||||||
ArrayList<Prediction> predictions = mRecognizer.recognize(gesture);
|
ArrayList<Prediction> predictions = mRecognizer.recognize(gesture);
|
||||||
if (!predictions.isEmpty()) {
|
if (!predictions.isEmpty()) {
|
||||||
Log.v(LOGTAG, "1st Prediction : " + predictions.get(0).name);
|
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 params = new ViewGroup.LayoutParams(
|
||||||
ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.FILL_PARENT);
|
ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.FILL_PARENT);
|
||||||
this.addContentView(overlay, params);
|
this.addContentView(overlay, params);
|
||||||
|
|||||||
@@ -34,12 +34,11 @@ import android.widget.ArrayAdapter;
|
|||||||
import android.widget.EditText;
|
import android.widget.EditText;
|
||||||
import android.widget.Spinner;
|
import android.widget.Spinner;
|
||||||
import android.widget.AdapterView.OnItemSelectedListener;
|
import android.widget.AdapterView.OnItemSelectedListener;
|
||||||
|
import android.gesture.Gesture;
|
||||||
|
|
||||||
import com.android.gesture.Gesture;
|
import android.gesture.GestureLibrary;
|
||||||
import com.android.gesture.GestureLibrary;
|
import android.gesture.GestureOverlayView;
|
||||||
import com.android.gesture.GestureListener;
|
import android.gesture.Prediction;
|
||||||
import com.android.gesture.GestureOverlay;
|
|
||||||
import com.android.gesture.Prediction;
|
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@@ -57,7 +56,7 @@ public class GestureEntry extends Activity {
|
|||||||
|
|
||||||
private static final int VIEW_ID = Menu.FIRST + 1;
|
private static final int VIEW_ID = Menu.FIRST + 1;
|
||||||
|
|
||||||
private GestureOverlay mGesturePad;
|
private GestureOverlayView mGesturePad;
|
||||||
|
|
||||||
private Spinner mRecognitionResult;
|
private Spinner mRecognitionResult;
|
||||||
|
|
||||||
@@ -96,17 +95,17 @@ public class GestureEntry extends Activity {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// create the area for drawing a gesture
|
// create the area for drawing a gesture
|
||||||
mGesturePad = (GestureOverlay) findViewById(R.id.drawingpad);
|
mGesturePad = (GestureOverlayView) findViewById(R.id.drawingpad);
|
||||||
mGesturePad.setBackgroundColor(Color.BLACK);
|
mGesturePad.setBackgroundColor(Color.BLACK);
|
||||||
mGesturePad.addGestureListener(new GestureListener() {
|
mGesturePad.addOnGestureListener(new GestureOverlayView.OnGestureListener() {
|
||||||
public void onFinishGesture(GestureOverlay overlay, MotionEvent event) {
|
public void onGestureEnded(GestureOverlayView overlay, MotionEvent event) {
|
||||||
recognize(overlay.getCurrentGesture());
|
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);
|
overlay.clear(false);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -26,10 +26,10 @@ import android.widget.ArrayAdapter;
|
|||||||
import android.widget.Button;
|
import android.widget.Button;
|
||||||
import android.widget.Spinner;
|
import android.widget.Spinner;
|
||||||
import android.widget.AdapterView.OnItemSelectedListener;
|
import android.widget.AdapterView.OnItemSelectedListener;
|
||||||
|
import android.gesture.Gesture;
|
||||||
|
|
||||||
import com.android.gesture.Gesture;
|
import android.gesture.GestureLibrary;
|
||||||
import com.android.gesture.GestureLibrary;
|
import android.gesture.GestureOverlayView;
|
||||||
import com.android.gesture.GestureOverlay;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
@@ -41,7 +41,7 @@ import java.util.Collections;
|
|||||||
|
|
||||||
public class GestureLibViewer extends Activity {
|
public class GestureLibViewer extends Activity {
|
||||||
|
|
||||||
private GestureOverlay mGesturePad;
|
private GestureOverlayView mGesturePad;
|
||||||
|
|
||||||
private Spinner mGestureCategory;
|
private Spinner mGestureCategory;
|
||||||
|
|
||||||
@@ -90,7 +90,7 @@ public class GestureLibViewer extends Activity {
|
|||||||
setContentView(R.layout.gestureviewer);
|
setContentView(R.layout.gestureviewer);
|
||||||
|
|
||||||
// create the area for drawing a gesture
|
// create the area for drawing a gesture
|
||||||
mGesturePad = (GestureOverlay) findViewById(R.id.drawingpad);
|
mGesturePad = (GestureOverlayView) findViewById(R.id.drawingpad);
|
||||||
mGesturePad.setEnabled(false);
|
mGesturePad.setEnabled(false);
|
||||||
|
|
||||||
// init the gesture library
|
// init the gesture library
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import java.io.BufferedInputStream;
|
|||||||
*/
|
*/
|
||||||
public class Converter {
|
public class Converter {
|
||||||
private final File mFile;
|
private final File mFile;
|
||||||
|
private static final short VERSION_NUMBER = 1;
|
||||||
|
|
||||||
Converter(File file) {
|
Converter(File file) {
|
||||||
mFile = file;
|
mFile = file;
|
||||||
@@ -63,10 +64,10 @@ public class Converter {
|
|||||||
|
|
||||||
iWeights = new float[hCount][];
|
iWeights = new float[hCount][];
|
||||||
for (int i = 0; i < hCount; i++) {
|
for (int i = 0; i < hCount; i++) {
|
||||||
iWeights[i] = new float[iCount];
|
iWeights[i] = new float[iCount + 1];
|
||||||
line = reader.readLine();
|
line = reader.readLine();
|
||||||
startIndex = 0;
|
startIndex = 0;
|
||||||
for (int j = 0; j < iCount; j++) {
|
for (int j = 0; j <= iCount; j++) {
|
||||||
endIndex = line.indexOf(" ", startIndex);
|
endIndex = line.indexOf(" ", startIndex);
|
||||||
iWeights[i][j] = Float.parseFloat(line.substring(startIndex, endIndex));
|
iWeights[i][j] = Float.parseFloat(line.substring(startIndex, endIndex));
|
||||||
startIndex = endIndex + 1;
|
startIndex = endIndex + 1;
|
||||||
@@ -75,10 +76,10 @@ public class Converter {
|
|||||||
|
|
||||||
oWeights = new float[oCount][];
|
oWeights = new float[oCount][];
|
||||||
for (int i = 0; i < oCount; i++) {
|
for (int i = 0; i < oCount; i++) {
|
||||||
oWeights[i] = new float[hCount];
|
oWeights[i] = new float[hCount + 1];
|
||||||
line = reader.readLine();
|
line = reader.readLine();
|
||||||
startIndex = 0;
|
startIndex = 0;
|
||||||
for (int j = 0; j < hCount; j++) {
|
for (int j = 0; j <= hCount; j++) {
|
||||||
endIndex = line.indexOf(" ", startIndex);
|
endIndex = line.indexOf(" ", startIndex);
|
||||||
oWeights[i][j] = Float.parseFloat(line.substring(startIndex, endIndex));
|
oWeights[i][j] = Float.parseFloat(line.substring(startIndex, endIndex));
|
||||||
startIndex = endIndex + 1;
|
startIndex = endIndex + 1;
|
||||||
@@ -105,6 +106,7 @@ public class Converter {
|
|||||||
try {
|
try {
|
||||||
out = new DataOutputStream(new FileOutputStream(mFile));
|
out = new DataOutputStream(new FileOutputStream(mFile));
|
||||||
|
|
||||||
|
out.writeShort(VERSION_NUMBER);
|
||||||
out.writeInt(iCount);
|
out.writeInt(iCount);
|
||||||
out.writeInt(hCount);
|
out.writeInt(hCount);
|
||||||
out.writeInt(oCount);
|
out.writeInt(oCount);
|
||||||
|
|||||||
Reference in New Issue
Block a user