Merge change 2746 into donut

* changes:
  Modify the base gestures API to use streams instead of files. Adds new wrappers to easily load/save gestures from files, resources, etc. Do the same for the letters recognizer.
This commit is contained in:
Android (Google) Code Review
2009-05-29 14:46:02 -07:00
11 changed files with 660 additions and 396 deletions

View File

@@ -0,0 +1,139 @@
/*
* Copyright (C) 2009 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.gesture;
import android.util.Log;
import static android.gesture.GestureConstants.*;
import android.content.Context;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.FileInputStream;
import java.io.InputStream;
import java.lang.ref.WeakReference;
public final class GestureLibraries {
private GestureLibraries() {
}
public static GestureLibrary fromFile(String path) {
return fromFile(new File(path));
}
public static GestureLibrary fromFile(File path) {
return new FileGestureLibrary(path);
}
public static GestureLibrary fromPrivateFile(Context context, String name) {
return fromFile(context.getFileStreamPath(name));
}
public static GestureLibrary fromRawResource(Context context, int resourceId) {
return new ResourceGestureLibrary(context, resourceId);
}
private static class FileGestureLibrary extends GestureLibrary {
private final File mPath;
public FileGestureLibrary(File path) {
mPath = path;
}
@Override
public boolean isReadOnly() {
return !mPath.canWrite();
}
public boolean save() {
final File file = mPath;
if (!file.canWrite()) return false;
if (!file.getParentFile().exists()) {
if (!file.getParentFile().mkdirs()) {
return false;
}
}
boolean result = false;
try {
mStore.save(new FileOutputStream(file), true);
result = true;
} catch (FileNotFoundException e) {
Log.d(LOG_TAG, "Could not save the gesture library in " + mPath, e);
} catch (IOException e) {
Log.d(LOG_TAG, "Could not save the gesture library in " + mPath, e);
}
return result;
}
public boolean load() {
boolean result = false;
final File file = mPath;
if (file.exists() && file.canRead()) {
try {
mStore.load(new FileInputStream(file), true);
result = true;
} catch (FileNotFoundException e) {
Log.d(LOG_TAG, "Could not load the gesture library from " + mPath, e);
} catch (IOException e) {
Log.d(LOG_TAG, "Could not load the gesture library from " + mPath, e);
}
}
return result;
}
}
private static class ResourceGestureLibrary extends GestureLibrary {
private final WeakReference<Context> mContext;
private final int mResourceId;
public ResourceGestureLibrary(Context context, int resourceId) {
mContext = new WeakReference<Context>(context);
mResourceId = resourceId;
}
@Override
public boolean isReadOnly() {
return true;
}
public boolean save() {
return false;
}
public boolean load() {
boolean result = false;
final Context context = mContext.get();
if (context != null) {
final InputStream in = context.getResources().openRawResource(mResourceId);
try {
mStore.load(in, true);
result = true;
} catch (IOException e) {
Log.d(LOG_TAG, "Could not load the gesture library from raw resource " +
context.getResources().getResourceName(mResourceId), e);
}
}
return result;
}
}
}

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2008-2009 The Android Open Source Project * Copyright (C) 2009 The Android Open Source Project
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -14,337 +14,68 @@
* limitations under the License. * limitations under the License.
*/ */
package android.gesture; package android.gesture;
import android.util.Log;
import android.os.SystemClock;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.DataOutputStream;
import java.io.DataInputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Set; import java.util.Set;
import java.util.Map; import java.util.ArrayList;
import static android.gesture.GestureConstants.LOG_TAG; public abstract class GestureLibrary {
protected final GestureStore mStore;
/** protected GestureLibrary() {
* GestureLibrary maintains gesture examples and makes predictions on a new mStore = new GestureStore();
* gesture }
*/
// public abstract boolean save();
// File format for GestureLibrary:
// public abstract boolean load();
// Nb. bytes Java type Description
// ----------------------------------- public boolean isReadOnly() {
// Header return false;
// 2 bytes short File format version number }
// 4 bytes int Number of entries
// Entry public Learner getLearner() {
// X bytes UTF String Entry name return mStore.getLearner();
// 4 bytes int Number of gestures
// Gesture
// 8 bytes long Gesture ID
// 4 bytes int Number of strokes
// Stroke
// 4 bytes int Number of points
// Point
// 4 bytes float X coordinate of the point
// 4 bytes float Y coordinate of the point
// 8 bytes long Time stamp
//
public class GestureLibrary {
public static final int SEQUENCE_INVARIANT = 1;
// when SEQUENCE_SENSITIVE is used, only single stroke gestures are currently allowed
public static final int SEQUENCE_SENSITIVE = 2;
// ORIENTATION_SENSITIVE and ORIENTATION_INVARIANT are only for SEQUENCE_SENSITIVE gestures
public static final int ORIENTATION_INVARIANT = 1;
public static final int ORIENTATION_SENSITIVE = 2;
private static final short FILE_FORMAT_VERSION = 1;
private static final boolean PROFILE_LOADING_SAVING = false;
private int mSequenceType = SEQUENCE_SENSITIVE;
private int mOrientationStyle = ORIENTATION_SENSITIVE;
private final String mGestureFileName;
private final HashMap<String, ArrayList<Gesture>> mNamedGestures =
new HashMap<String, ArrayList<Gesture>>();
private Learner mClassifier;
private boolean mChanged = false;
/**
* @param path where gesture data is stored
*/
public GestureLibrary(String path) {
mGestureFileName = path;
mClassifier = new InstanceLearner();
} }
/**
* Specify how the gesture library will handle orientation.
* Use ORIENTATION_INVARIANT or ORIENTATION_SENSITIVE
*
* @param style
*/
public void setOrientationStyle(int style) { public void setOrientationStyle(int style) {
mOrientationStyle = style; mStore.setOrientationStyle(style);
} }
public int getOrientationStyle() { public int getOrientationStyle() {
return mOrientationStyle; return mStore.getOrientationStyle();
} }
/**
* @param type SEQUENCE_INVARIANT or SEQUENCE_SENSITIVE
*/
public void setSequenceType(int type) { public void setSequenceType(int type) {
mSequenceType = type; mStore.setSequenceType(type);
} }
/**
* @return SEQUENCE_INVARIANT or SEQUENCE_SENSITIVE
*/
public int getSequenceType() { public int getSequenceType() {
return mSequenceType; return mStore.getSequenceType();
} }
/**
* Get all the gesture entry names in the library
*
* @return a set of strings
*/
public Set<String> getGestureEntries() { public Set<String> getGestureEntries() {
return mNamedGestures.keySet(); return mStore.getGestureEntries();
} }
/**
* Recognize a gesture
*
* @param gesture the query
* @return a list of predictions of possible entries for a given gesture
*/
public ArrayList<Prediction> recognize(Gesture gesture) { public ArrayList<Prediction> recognize(Gesture gesture) {
Instance instance = Instance.createInstance(mSequenceType, mOrientationStyle, gesture, null); return mStore.recognize(gesture);
return mClassifier.classify(mSequenceType, instance.vector);
} }
/**
* Add a gesture for the entry
*
* @param entryName entry name
* @param gesture
*/
public void addGesture(String entryName, Gesture gesture) { public void addGesture(String entryName, Gesture gesture) {
if (entryName == null || entryName.length() == 0) { mStore.addGesture(entryName, gesture);
return;
}
ArrayList<Gesture> gestures = mNamedGestures.get(entryName);
if (gestures == null) {
gestures = new ArrayList<Gesture>();
mNamedGestures.put(entryName, gestures);
}
gestures.add(gesture);
mClassifier.addInstance(Instance.createInstance(mSequenceType, mOrientationStyle, gesture, entryName));
mChanged = true;
} }
/**
* Remove a gesture from the library. If there are no more gestures for the
* given entry, the gesture entry will be removed.
*
* @param entryName entry name
* @param gesture
*/
public void removeGesture(String entryName, Gesture gesture) { public void removeGesture(String entryName, Gesture gesture) {
ArrayList<Gesture> gestures = mNamedGestures.get(entryName); mStore.removeGesture(entryName, gesture);
if (gestures == null) {
return;
}
gestures.remove(gesture);
// if there are no more samples, remove the entry automatically
if (gestures.isEmpty()) {
mNamedGestures.remove(entryName);
}
mClassifier.removeInstance(gesture.getID());
mChanged = true;
} }
/**
* Remove a entry of gestures
*
* @param entryName the entry name
*/
public void removeEntry(String entryName) { public void removeEntry(String entryName) {
mNamedGestures.remove(entryName); mStore.removeEntry(entryName);
mClassifier.removeInstances(entryName);
mChanged = true;
} }
/**
* Get all the gestures of an entry
*
* @param entryName
* @return the list of gestures that is under this name
*/
public ArrayList<Gesture> getGestures(String entryName) { public ArrayList<Gesture> getGestures(String entryName) {
ArrayList<Gesture> gestures = mNamedGestures.get(entryName); return mStore.getGestures(entryName);
if (gestures != null) {
return new ArrayList<Gesture>(gestures);
} else {
return null;
}
}
/**
* Save the gesture library
*/
public boolean save() {
if (!mChanged) {
return true;
}
boolean result = false;
DataOutputStream out = null;
try {
File file = new File(mGestureFileName);
if (!file.getParentFile().exists()) {
if (!file.getParentFile().mkdirs()) {
return false;
}
}
long start;
if (PROFILE_LOADING_SAVING) {
start = SystemClock.elapsedRealtime();
}
final HashMap<String, ArrayList<Gesture>> maps = mNamedGestures;
out = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(file),
GestureConstants.IO_BUFFER_SIZE));
// Write version number
out.writeShort(FILE_FORMAT_VERSION);
// Write number of entries
out.writeInt(maps.size());
for (Map.Entry<String, ArrayList<Gesture>> entry : maps.entrySet()) {
final String key = entry.getKey();
final ArrayList<Gesture> examples = entry.getValue();
final int count = examples.size();
// Write entry name
out.writeUTF(key);
// Write number of examples for this entry
out.writeInt(count);
for (int i = 0; i < count; i++) {
examples.get(i).serialize(out);
}
}
out.flush();
if (PROFILE_LOADING_SAVING) {
long end = SystemClock.elapsedRealtime();
Log.d(LOG_TAG, "Saving gestures library = " + (end - start) + " ms");
}
mChanged = false;
result = true;
} catch (IOException ex) {
Log.d(LOG_TAG, "Failed to save gestures:", ex);
} finally {
GestureUtilities.closeStream(out);
}
return result;
}
/**
* Load the gesture library
*/
public boolean load() {
boolean result = false;
final File file = new File(mGestureFileName);
if (file.exists()) {
DataInputStream in = null;
try {
in = new DataInputStream(new BufferedInputStream(
new FileInputStream(mGestureFileName), GestureConstants.IO_BUFFER_SIZE));
long start;
if (PROFILE_LOADING_SAVING) {
start = SystemClock.elapsedRealtime();
}
// Read file format version number
final short versionNumber = in.readShort();
switch (versionNumber) {
case 1:
readFormatV1(in);
break;
}
if (PROFILE_LOADING_SAVING) {
long end = SystemClock.elapsedRealtime();
Log.d(LOG_TAG, "Loading gestures library = " + (end - start) + " ms");
}
result = true;
} catch (IOException ex) {
Log.d(LOG_TAG, "Failed to load gestures:", ex);
} finally {
GestureUtilities.closeStream(in);
}
}
return result;
}
private void readFormatV1(DataInputStream in) throws IOException {
final Learner classifier = mClassifier;
final HashMap<String, ArrayList<Gesture>> namedGestures = mNamedGestures;
namedGestures.clear();
// Number of entries in the library
final int entriesCount = in.readInt();
for (int i = 0; i < entriesCount; i++) {
// Entry name
final String name = in.readUTF();
// Number of gestures
final int gestureCount = in.readInt();
final ArrayList<Gesture> gestures = new ArrayList<Gesture>(gestureCount);
for (int j = 0; j < gestureCount; j++) {
final Gesture gesture = Gesture.deserialize(in);
gestures.add(gesture);
classifier.addInstance(Instance.createInstance(mSequenceType, mOrientationStyle, gesture, name));
}
namedGestures.put(name, gestures);
}
}
Learner getLearner() {
return mClassifier;
} }
} }

View File

@@ -0,0 +1,330 @@
/*
* 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 android.gesture;
import android.util.Log;
import android.os.SystemClock;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.IOException;
import java.io.DataOutputStream;
import java.io.DataInputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Set;
import java.util.Map;
import static android.gesture.GestureConstants.LOG_TAG;
/**
* GestureLibrary maintains gesture examples and makes predictions on a new
* gesture
*/
//
// File format for GestureStore:
//
// Nb. bytes Java type Description
// -----------------------------------
// Header
// 2 bytes short File format version number
// 4 bytes int Number of entries
// Entry
// X bytes UTF String Entry name
// 4 bytes int Number of gestures
// Gesture
// 8 bytes long Gesture ID
// 4 bytes int Number of strokes
// Stroke
// 4 bytes int Number of points
// Point
// 4 bytes float X coordinate of the point
// 4 bytes float Y coordinate of the point
// 8 bytes long Time stamp
//
public class GestureStore {
public static final int SEQUENCE_INVARIANT = 1;
// when SEQUENCE_SENSITIVE is used, only single stroke gestures are currently allowed
public static final int SEQUENCE_SENSITIVE = 2;
// ORIENTATION_SENSITIVE and ORIENTATION_INVARIANT are only for SEQUENCE_SENSITIVE gestures
public static final int ORIENTATION_INVARIANT = 1;
public static final int ORIENTATION_SENSITIVE = 2;
private static final short FILE_FORMAT_VERSION = 1;
private static final boolean PROFILE_LOADING_SAVING = false;
private int mSequenceType = SEQUENCE_SENSITIVE;
private int mOrientationStyle = ORIENTATION_SENSITIVE;
private final HashMap<String, ArrayList<Gesture>> mNamedGestures =
new HashMap<String, ArrayList<Gesture>>();
private Learner mClassifier;
private boolean mChanged = false;
public GestureStore() {
mClassifier = new InstanceLearner();
}
/**
* Specify how the gesture library will handle orientation.
* Use ORIENTATION_INVARIANT or ORIENTATION_SENSITIVE
*
* @param style
*/
public void setOrientationStyle(int style) {
mOrientationStyle = style;
}
public int getOrientationStyle() {
return mOrientationStyle;
}
/**
* @param type SEQUENCE_INVARIANT or SEQUENCE_SENSITIVE
*/
public void setSequenceType(int type) {
mSequenceType = type;
}
/**
* @return SEQUENCE_INVARIANT or SEQUENCE_SENSITIVE
*/
public int getSequenceType() {
return mSequenceType;
}
/**
* Get all the gesture entry names in the library
*
* @return a set of strings
*/
public Set<String> getGestureEntries() {
return mNamedGestures.keySet();
}
/**
* Recognize a gesture
*
* @param gesture the query
* @return a list of predictions of possible entries for a given gesture
*/
public ArrayList<Prediction> recognize(Gesture gesture) {
Instance instance = Instance.createInstance(mSequenceType,
mOrientationStyle, gesture, null);
return mClassifier.classify(mSequenceType, instance.vector);
}
/**
* Add a gesture for the entry
*
* @param entryName entry name
* @param gesture
*/
public void addGesture(String entryName, Gesture gesture) {
if (entryName == null || entryName.length() == 0) {
return;
}
ArrayList<Gesture> gestures = mNamedGestures.get(entryName);
if (gestures == null) {
gestures = new ArrayList<Gesture>();
mNamedGestures.put(entryName, gestures);
}
gestures.add(gesture);
mClassifier.addInstance(
Instance.createInstance(mSequenceType, mOrientationStyle, gesture, entryName));
mChanged = true;
}
/**
* Remove a gesture from the library. If there are no more gestures for the
* given entry, the gesture entry will be removed.
*
* @param entryName entry name
* @param gesture
*/
public void removeGesture(String entryName, Gesture gesture) {
ArrayList<Gesture> gestures = mNamedGestures.get(entryName);
if (gestures == null) {
return;
}
gestures.remove(gesture);
// if there are no more samples, remove the entry automatically
if (gestures.isEmpty()) {
mNamedGestures.remove(entryName);
}
mClassifier.removeInstance(gesture.getID());
mChanged = true;
}
/**
* Remove a entry of gestures
*
* @param entryName the entry name
*/
public void removeEntry(String entryName) {
mNamedGestures.remove(entryName);
mClassifier.removeInstances(entryName);
mChanged = true;
}
/**
* Get all the gestures of an entry
*
* @param entryName
* @return the list of gestures that is under this name
*/
public ArrayList<Gesture> getGestures(String entryName) {
ArrayList<Gesture> gestures = mNamedGestures.get(entryName);
if (gestures != null) {
return new ArrayList<Gesture>(gestures);
} else {
return null;
}
}
/**
* Save the gesture library
*/
public void save(OutputStream stream) throws IOException {
save(stream, false);
}
public void save(OutputStream stream, boolean closeStream) throws IOException {
if (!mChanged) {
return;
}
DataOutputStream out = null;
try {
long start;
if (PROFILE_LOADING_SAVING) {
start = SystemClock.elapsedRealtime();
}
final HashMap<String, ArrayList<Gesture>> maps = mNamedGestures;
out = new DataOutputStream((stream instanceof BufferedOutputStream) ? out :
new BufferedOutputStream(out, GestureConstants.IO_BUFFER_SIZE));
// Write version number
out.writeShort(FILE_FORMAT_VERSION);
// Write number of entries
out.writeInt(maps.size());
for (Map.Entry<String, ArrayList<Gesture>> entry : maps.entrySet()) {
final String key = entry.getKey();
final ArrayList<Gesture> examples = entry.getValue();
final int count = examples.size();
// Write entry name
out.writeUTF(key);
// Write number of examples for this entry
out.writeInt(count);
for (int i = 0; i < count; i++) {
examples.get(i).serialize(out);
}
}
out.flush();
if (PROFILE_LOADING_SAVING) {
long end = SystemClock.elapsedRealtime();
Log.d(LOG_TAG, "Saving gestures library = " + (end - start) + " ms");
}
mChanged = false;
} finally {
if (closeStream) GestureUtilities.closeStream(out);
}
}
/**
* Load the gesture library
*/
public void load(InputStream stream) throws IOException {
load(stream, false);
}
public void load(InputStream stream, boolean closeStream) throws IOException {
DataInputStream in = null;
try {
in = new DataInputStream((stream instanceof BufferedInputStream) ? stream :
new BufferedInputStream(stream, GestureConstants.IO_BUFFER_SIZE));
long start;
if (PROFILE_LOADING_SAVING) {
start = SystemClock.elapsedRealtime();
}
// Read file format version number
final short versionNumber = in.readShort();
switch (versionNumber) {
case 1:
readFormatV1(in);
break;
}
if (PROFILE_LOADING_SAVING) {
long end = SystemClock.elapsedRealtime();
Log.d(LOG_TAG, "Loading gestures library = " + (end - start) + " ms");
}
} finally {
if (closeStream) GestureUtilities.closeStream(in);
}
}
private void readFormatV1(DataInputStream in) throws IOException {
final Learner classifier = mClassifier;
final HashMap<String, ArrayList<Gesture>> namedGestures = mNamedGestures;
namedGestures.clear();
// Number of entries in the library
final int entriesCount = in.readInt();
for (int i = 0; i < entriesCount; i++) {
// Entry name
final String name = in.readUTF();
// Number of gestures
final int gestureCount = in.readInt();
final ArrayList<Gesture> gestures = new ArrayList<Gesture>(gestureCount);
for (int j = 0; j < gestureCount; j++) {
final Gesture gesture = Gesture.deserialize(in);
gestures.add(gesture);
classifier.addInstance(
Instance.createInstance(mSequenceType, mOrientationStyle, gesture, name));
}
namedGestures.put(name, gestures);
}
}
Learner getLearner() {
return mClassifier;
}
}

View File

@@ -72,7 +72,7 @@ class Instance {
static Instance createInstance(int sequenceType, int orientationType, Gesture gesture, String label) { static Instance createInstance(int sequenceType, int orientationType, Gesture gesture, String label) {
float[] pts; float[] pts;
Instance instance; Instance instance;
if (sequenceType == GestureLibrary.SEQUENCE_SENSITIVE) { if (sequenceType == GestureStore.SEQUENCE_SENSITIVE) {
pts = temporalSampler(orientationType, gesture); pts = temporalSampler(orientationType, gesture);
instance = new Instance(gesture.getID(), pts, label); instance = new Instance(gesture.getID(), pts, label);
instance.normalize(); instance.normalize();
@@ -94,7 +94,7 @@ class Instance {
float orientation = (float)Math.atan2(pts[1] - center[1], pts[0] - center[0]); float orientation = (float)Math.atan2(pts[1] - center[1], pts[0] - center[0]);
float adjustment = -orientation; float adjustment = -orientation;
if (orientationType == GestureLibrary.ORIENTATION_SENSITIVE) { if (orientationType == GestureStore.ORIENTATION_SENSITIVE) {
int count = ORIENTATIONS.length; int count = ORIENTATIONS.length;
for (int i = 0; i < count; i++) { for (int i = 0; i < count; i++) {
float delta = ORIENTATIONS[i] - orientation; float delta = ORIENTATIONS[i] - orientation;

View File

@@ -38,7 +38,7 @@ class InstanceLearner extends Learner {
continue; continue;
} }
double distance; double distance;
if (sequenceType == GestureLibrary.SEQUENCE_SENSITIVE) { if (sequenceType == GestureStore.SEQUENCE_SENSITIVE) {
distance = GestureUtilities.cosineDistance(sample.vector, vector); distance = GestureUtilities.cosineDistance(sample.vector, vector);
} else { } else {
distance = GestureUtilities.squaredEuclideanDistance(sample.vector, vector); distance = GestureUtilities.squaredEuclideanDistance(sample.vector, vector);

View File

@@ -23,6 +23,7 @@ import android.util.Log;
import java.io.BufferedInputStream; import java.io.BufferedInputStream;
import java.io.DataInputStream; import java.io.DataInputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.Comparator; import java.util.Comparator;
@@ -31,10 +32,9 @@ import java.util.HashMap;
import static android.gesture.GestureConstants.LOG_TAG; import static android.gesture.GestureConstants.LOG_TAG;
public class LetterRecognizer { public class LetterRecognizer {
public final static int RECOGNIZER_LATIN_LOWERCASE = 0;
static final String GESTURE_FILE_NAME = "letters.gestures"; static final String GESTURE_FILE_NAME = "letters.gestures";
private final static int ADJUST_RANGE = 3; private final static int ADJUST_RANGE = 3;
private SigmoidUnit[] mHiddenLayer; private SigmoidUnit[] mHiddenLayer;
private SigmoidUnit[] mOutputLayer; private SigmoidUnit[] mOutputLayer;
@@ -42,8 +42,8 @@ public class LetterRecognizer {
private final String[] mClasses; private final String[] mClasses;
private final int mPatchSize; private final int mPatchSize;
private GestureLibrary mGestureLibrary; private GestureLibrary mGestureStore;
private final Comparator<Prediction> mComparator = new PredictionComparator(); private final Comparator<Prediction> mComparator = new PredictionComparator();
@@ -69,15 +69,6 @@ public class LetterRecognizer {
} }
} }
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) {
mPatchSize = (int) Math.sqrt(numOfInput); mPatchSize = (int) Math.sqrt(numOfInput);
mHiddenLayer = new SigmoidUnit[numOfHidden]; mHiddenLayer = new SigmoidUnit[numOfHidden];
@@ -137,14 +128,18 @@ public class LetterRecognizer {
return output; return output;
} }
private static LetterRecognizer createFromResource(Context context, int resourceID) { static LetterRecognizer createFromResource(Context context, int resourceID) {
final Resources resources = context.getResources(); final Resources resources = context.getResources();
final InputStream stream = resources.openRawResource(resourceID);
return createFromStream(stream);
}
static LetterRecognizer createFromStream(InputStream stream) {
DataInputStream in = null; DataInputStream in = null;
LetterRecognizer classifier = null; LetterRecognizer classifier = null;
try { try {
in = new DataInputStream(new BufferedInputStream(resources.openRawResource(resourceID), in = new DataInputStream(new BufferedInputStream(stream,
GestureConstants.IO_BUFFER_SIZE)); GestureConstants.IO_BUFFER_SIZE));
final int version = in.readShort(); final int version = in.readShort();
@@ -206,49 +201,49 @@ public class LetterRecognizer {
} }
/** /**
* TODO: Publish this API once we figure out where we should save the personzlied * TODO: Publish this API once we figure out where we should save the personalized
* gestures, and how to do so across all apps * gestures, and how to do so across all apps
* *
* @hide * @hide
*/ */
public boolean save() { public boolean save() {
if (mGestureLibrary != null) { if (mGestureStore != null) {
return mGestureLibrary.save(); return mGestureStore.save();
} }
return false; return false;
} }
/** /**
* TODO: Publish this API once we figure out where we should save the personzlied * TODO: Publish this API once we figure out where we should save the personalized
* gestures, and how to do so across all apps * gestures, and how to do so across all apps
* *
* @hide * @hide
*/ */
public void setPersonalizationEnabled(boolean enabled) { public void setPersonalizationEnabled(boolean enabled) {
if (enabled) { if (enabled) {
mGestureLibrary = new GestureLibrary(GESTURE_FILE_NAME); mGestureStore = GestureLibraries.fromFile(GESTURE_FILE_NAME);
mGestureLibrary.setSequenceType(GestureLibrary.SEQUENCE_INVARIANT); mGestureStore.setSequenceType(GestureStore.SEQUENCE_INVARIANT);
mGestureLibrary.load(); mGestureStore.load();
} else { } else {
mGestureLibrary = null; mGestureStore = null;
} }
} }
/** /**
* TODO: Publish this API once we figure out where we should save the personzlied * TODO: Publish this API once we figure out where we should save the personalized
* gestures, and how to do so across all apps * gestures, and how to do so across all apps
* *
* @hide * @hide
*/ */
public void addExample(String letter, Gesture example) { public void addExample(String letter, Gesture example) {
if (mGestureLibrary != null) { if (mGestureStore != null) {
mGestureLibrary.addGesture(letter, example); mGestureStore.addGesture(letter, example);
} }
} }
private void adjustPrediction(Gesture query, ArrayList<Prediction> predictions) { private void adjustPrediction(Gesture query, ArrayList<Prediction> predictions) {
if (mGestureLibrary != null) { if (mGestureStore != null) {
final ArrayList<Prediction> results = mGestureLibrary.recognize(query); final ArrayList<Prediction> results = mGestureStore.recognize(query);
final HashMap<String, Prediction> topNList = new HashMap<String, Prediction>(); 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++) {

View File

@@ -0,0 +1,65 @@
/*
* Copyright (C) 2009 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.gesture;
import android.content.Context;
import android.util.Log;
import static android.gesture.GestureConstants.LOG_TAG;
import static android.gesture.LetterRecognizer.*;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
public final class LetterRecognizers {
public final static int RECOGNIZER_LATIN_LOWERCASE = 0;
private LetterRecognizers() {
}
public static LetterRecognizer fromType(Context context, int type) {
switch (type) {
case RECOGNIZER_LATIN_LOWERCASE: {
return createFromResource(context, com.android.internal.R.raw.latin_lowercase);
}
}
return null;
}
public static LetterRecognizer fromResource(Context context, int resourceId) {
return createFromResource(context, resourceId);
}
public static LetterRecognizer fromFile(String path) {
return fromFile(new File(path));
}
public static LetterRecognizer fromFile(File file) {
try {
return createFromStream(new FileInputStream(file));
} catch (FileNotFoundException e) {
Log.d(LOG_TAG, "Failed to load handwriting data from file " + file, e);
}
return null;
}
public static LetterRecognizer fromStream(InputStream stream) {
return createFromStream(stream);
}
}

View File

@@ -52,6 +52,7 @@ import android.gesture.GestureOverlayView;
import android.gesture.Gesture; import android.gesture.Gesture;
import android.gesture.LetterRecognizer; import android.gesture.LetterRecognizer;
import android.gesture.Prediction; import android.gesture.Prediction;
import android.gesture.LetterRecognizers;
import com.android.internal.R; import com.android.internal.R;
@@ -94,7 +95,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
public static final int TRANSCRIPT_MODE_NORMAL = 1; public static final int TRANSCRIPT_MODE_NORMAL = 1;
/** /**
* The list will automatically scroll to the bottom, no matter what items * The list will automatically scroll to the bottom, no matter what items
* are currently visible. * are currently visible.
* *
* @see #setTranscriptMode(int) * @see #setTranscriptMode(int)
*/ */
@@ -156,7 +157,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
* Indicates the view is in the process of being flung * Indicates the view is in the process of being flung
*/ */
static final int TOUCH_MODE_FLING = 4; static final int TOUCH_MODE_FLING = 4;
/** /**
* Indicates that the user is currently dragging the fast scroll thumb * Indicates that the user is currently dragging the fast scroll thumb
*/ */
@@ -349,7 +350,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
* bitmap cache after scrolling. * bitmap cache after scrolling.
*/ */
boolean mScrollingCacheEnabled; boolean mScrollingCacheEnabled;
/** /**
* Whether or not to enable the fast scroll feature on this list * Whether or not to enable the fast scroll feature on this list
*/ */
@@ -422,7 +423,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
* The last CheckForTap runnable we posted, if any * The last CheckForTap runnable we posted, if any
*/ */
private Runnable mPendingCheckForTap; private Runnable mPendingCheckForTap;
/** /**
* The last CheckForKeyLongPress runnable we posted, if any * The last CheckForKeyLongPress runnable we posted, if any
*/ */
@@ -576,7 +577,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
int color = a.getColor(R.styleable.AbsListView_cacheColorHint, 0); int color = a.getColor(R.styleable.AbsListView_cacheColorHint, 0);
setCacheColorHint(color); setCacheColorHint(color);
boolean enableFastScroll = a.getBoolean(R.styleable.AbsListView_fastScrollEnabled, false); boolean enableFastScroll = a.getBoolean(R.styleable.AbsListView_fastScrollEnabled, false);
setFastScrollEnabled(enableFastScroll); setFastScrollEnabled(enableFastScroll);
@@ -605,7 +606,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
mTouchSlop = ViewConfiguration.get(mContext).getScaledTouchSlop(); mTouchSlop = ViewConfiguration.get(mContext).getScaledTouchSlop();
mDensityScale = getContext().getResources().getDisplayMetrics().density; mDensityScale = getContext().getResources().getDisplayMetrics().density;
} }
/** /**
* <p>Sets the type of gestures to use with this list. When gestures are enabled, * <p>Sets the type of gestures to use with this list. When gestures are enabled,
* that is if the <code>gestures</code> parameter is not {@link #GESTURES_NONE}, * that is if the <code>gestures</code> parameter is not {@link #GESTURES_NONE},
@@ -663,7 +664,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
* @see #GESTURES_NONE * @see #GESTURES_NONE
* @see #GESTURES_JUMP * @see #GESTURES_JUMP
* @see #GESTURES_FILTER * @see #GESTURES_FILTER
* @see #setGestures(int) * @see #setGestures(int)
*/ */
@ViewDebug.ExportedProperty(mapping = { @ViewDebug.ExportedProperty(mapping = {
@ViewDebug.IntToString(from = GESTURES_NONE, to = "NONE"), @ViewDebug.IntToString(from = GESTURES_NONE, to = "NONE"),
@@ -737,7 +738,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
mGesturesOverlay.setGestureStrokeType(GestureOverlayView.GESTURE_STROKE_TYPE_MULTIPLE); mGesturesOverlay.setGestureStrokeType(GestureOverlayView.GESTURE_STROKE_TYPE_MULTIPLE);
mGesturesOverlay.addOnGesturePerformedListener(new GesturesProcessor()); mGesturesOverlay.addOnGesturePerformedListener(new GesturesProcessor());
mPreviousGesturing = false; mPreviousGesturing = false;
} }
} }
@@ -778,10 +779,10 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
} }
/** /**
* Enables fast scrolling by letting the user quickly scroll through lists by * Enables fast scrolling by letting the user quickly scroll through lists by
* dragging the fast scroll thumb. The adapter attached to the list may want * dragging the fast scroll thumb. The adapter attached to the list may want
* to implement {@link SectionIndexer} if it wishes to display alphabet preview and * to implement {@link SectionIndexer} if it wishes to display alphabet preview and
* jump between sections of the list. * jump between sections of the list.
* @see SectionIndexer * @see SectionIndexer
* @see #isFastScrollEnabled() * @see #isFastScrollEnabled()
* @param enabled whether or not to enable fast scrolling * @param enabled whether or not to enable fast scrolling
@@ -799,7 +800,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
} }
} }
} }
/** /**
* Returns the current state of the fast scroll feature. * Returns the current state of the fast scroll feature.
* @see #setFastScrollEnabled(boolean) * @see #setFastScrollEnabled(boolean)
@@ -809,10 +810,10 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
public boolean isFastScrollEnabled() { public boolean isFastScrollEnabled() {
return mFastScrollEnabled; return mFastScrollEnabled;
} }
/** /**
* If fast scroll is visible, then don't draw the vertical scrollbar. * If fast scroll is visible, then don't draw the vertical scrollbar.
* @hide * @hide
*/ */
@Override @Override
protected boolean isVerticalScrollBarHidden() { protected boolean isVerticalScrollBarHidden() {
@@ -830,11 +831,11 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
* When smooth scrollbar is disabled, the position and size of the scrollbar thumb * When smooth scrollbar is disabled, the position and size of the scrollbar thumb
* is based solely on the number of items in the adapter and the position of the * is based solely on the number of items in the adapter and the position of the
* visible items inside the adapter. This provides a stable scrollbar as the user * visible items inside the adapter. This provides a stable scrollbar as the user
* navigates through a list of items with varying heights. * navigates through a list of items with varying heights.
* *
* @param enabled Whether or not to enable smooth scrollbar. * @param enabled Whether or not to enable smooth scrollbar.
* *
* @see #setSmoothScrollbarEnabled(boolean) * @see #setSmoothScrollbarEnabled(boolean)
* @attr ref android.R.styleable#AbsListView_smoothScrollbar * @attr ref android.R.styleable#AbsListView_smoothScrollbar
*/ */
public void setSmoothScrollbarEnabled(boolean enabled) { public void setSmoothScrollbarEnabled(boolean enabled) {
@@ -1142,7 +1143,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
/** /**
* Sets the initial value for the text filter. * Sets the initial value for the text filter.
* @param filterText The text to use for the filter. * @param filterText The text to use for the filter.
* *
* @see #setTextFilterEnabled * @see #setTextFilterEnabled
*/ */
public void setFilterText(String filterText) { public void setFilterText(String filterText) {
@@ -1168,7 +1169,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
} }
/** /**
* Returns the list's text filter, if available. * Returns the list's text filter, if available.
* @return the list's text filter or null if filtering isn't enabled * @return the list's text filter or null if filtering isn't enabled
*/ */
public CharSequence getTextFilter() { public CharSequence getTextFilter() {
@@ -1177,7 +1178,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
} }
return null; return null;
} }
@Override @Override
protected void onFocusChanged(boolean gainFocus, int direction, Rect previouslyFocusedRect) { protected void onFocusChanged(boolean gainFocus, int direction, Rect previouslyFocusedRect) {
super.onFocusChanged(gainFocus, direction, previouslyFocusedRect); super.onFocusChanged(gainFocus, direction, previouslyFocusedRect);
@@ -1740,7 +1741,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
System.arraycopy(state, enabledPos + 1, state, enabledPos, System.arraycopy(state, enabledPos + 1, state, enabledPos,
state.length - enabledPos - 1); state.length - enabledPos - 1);
} }
return state; return state;
} }
@@ -1851,16 +1852,16 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
*/ */
private class WindowRunnnable { private class WindowRunnnable {
private int mOriginalAttachCount; private int mOriginalAttachCount;
public void rememberWindowAttachCount() { public void rememberWindowAttachCount() {
mOriginalAttachCount = getWindowAttachCount(); mOriginalAttachCount = getWindowAttachCount();
} }
public boolean sameWindow() { public boolean sameWindow() {
return hasWindowFocus() && getWindowAttachCount() == mOriginalAttachCount; return hasWindowFocus() && getWindowAttachCount() == mOriginalAttachCount;
} }
} }
private class PerformClick extends WindowRunnnable implements Runnable { private class PerformClick extends WindowRunnnable implements Runnable {
View mChild; View mChild;
int mClickMotionPosition; int mClickMotionPosition;
@@ -1887,7 +1888,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
final long longPressId = mAdapter.getItemId(mMotionPosition); final long longPressId = mAdapter.getItemId(mMotionPosition);
boolean handled = false; boolean handled = false;
if (sameWindow() && !mDataChanged) { if (sameWindow() && !mDataChanged) {
handled = performLongPress(child, longPressPosition, longPressId); handled = performLongPress(child, longPressPosition, longPressId);
} }
if (handled) { if (handled) {
@@ -1901,7 +1902,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
} }
} }
} }
private class CheckForKeyLongPress extends WindowRunnnable implements Runnable { private class CheckForKeyLongPress extends WindowRunnnable implements Runnable {
public void run() { public void run() {
if (isPressed() && mSelectedPosition >= 0) { if (isPressed() && mSelectedPosition >= 0) {
@@ -1930,7 +1931,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
boolean handled = false; boolean handled = false;
dismissGesturesPopup(); dismissGesturesPopup();
if (mOnItemLongClickListener != null) { if (mOnItemLongClickListener != null) {
handled = mOnItemLongClickListener.onItemLongClick(AbsListView.this, child, handled = mOnItemLongClickListener.onItemLongClick(AbsListView.this, child,
longPressPosition, longPressId); longPressPosition, longPressId);
@@ -2079,7 +2080,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
mTouchMode = TOUCH_MODE_DONE_WAITING; mTouchMode = TOUCH_MODE_DONE_WAITING;
} }
} else { } else {
mTouchMode = TOUCH_MODE_DONE_WAITING; mTouchMode = TOUCH_MODE_DONE_WAITING;
} }
} }
} }
@@ -2138,7 +2139,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
boolean intercepted = mFastScroller.onTouchEvent(ev); boolean intercepted = mFastScroller.onTouchEvent(ev);
if (intercepted) { if (intercepted) {
return true; return true;
} }
} }
final int action = ev.getAction(); final int action = ev.getAction();
@@ -2326,10 +2327,10 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
} }
setPressed(false); setPressed(false);
// Need to redraw since we probably aren't drawing the selector anymore // Need to redraw since we probably aren't drawing the selector anymore
invalidate(); invalidate();
final Handler handler = getHandler(); final Handler handler = getHandler();
if (handler != null) { if (handler != null) {
handler.removeCallbacks(mPendingCheckForLongPress); handler.removeCallbacks(mPendingCheckForLongPress);
@@ -2373,7 +2374,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
return true; return true;
} }
@Override @Override
public void draw(Canvas canvas) { public void draw(Canvas canvas) {
super.draw(canvas); super.draw(canvas);
@@ -2388,14 +2389,14 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
int x = (int) ev.getX(); int x = (int) ev.getX();
int y = (int) ev.getY(); int y = (int) ev.getY();
View v; View v;
if (mFastScroller != null) { if (mFastScroller != null) {
boolean intercepted = mFastScroller.onInterceptTouchEvent(ev); boolean intercepted = mFastScroller.onInterceptTouchEvent(ev);
if (intercepted) { if (intercepted) {
return true; return true;
} }
} }
switch (action) { switch (action) {
case MotionEvent.ACTION_DOWN: { case MotionEvent.ACTION_DOWN: {
int motionPosition = findMotionRow(y); int motionPosition = findMotionRow(y);
@@ -3245,7 +3246,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
} }
return null; return null;
} }
/** /**
* For filtering we proxy an input connection to an internal text editor, * For filtering we proxy an input connection to an internal text editor,
* and this allows the proxying to happen. * and this allows the proxying to happen.
@@ -3254,7 +3255,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
public boolean checkInputConnectionProxy(View view) { public boolean checkInputConnectionProxy(View view) {
return view == mTextFilter; return view == mTextFilter;
} }
/** /**
* Creates the window for the text filter and populates it with an EditText field; * Creates the window for the text filter and populates it with an EditText field;
* *
@@ -3647,7 +3648,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
mCurrentScrap = scrapViews[0]; mCurrentScrap = scrapViews[0];
mScrapViews = scrapViews; mScrapViews = scrapViews;
} }
public boolean shouldRecycleViewType(int viewType) { public boolean shouldRecycleViewType(int viewType) {
return viewType >= 0; return viewType >= 0;
} }
@@ -3862,8 +3863,8 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
private final char[] mHolder; private final char[] mHolder;
GesturesProcessor() { GesturesProcessor() {
mRecognizer = LetterRecognizer.getLetterRecognizer(getContext(), mRecognizer = LetterRecognizers.fromType(getContext(),
LetterRecognizer.RECOGNIZER_LATIN_LOWERCASE); LetterRecognizers.RECOGNIZER_LATIN_LOWERCASE);
if (mRecognizer == null) { if (mRecognizer == null) {
setGestures(GESTURES_NONE); setGestures(GESTURES_NONE);
} }

View File

@@ -33,6 +33,7 @@ import android.gesture.Gesture;
import android.gesture.GestureOverlayView; import android.gesture.GestureOverlayView;
import android.gesture.LetterRecognizer; import android.gesture.LetterRecognizer;
import android.gesture.Prediction; import android.gesture.Prediction;
import android.gesture.LetterRecognizers;
import java.util.ArrayList; import java.util.ArrayList;
@@ -57,8 +58,8 @@ public class ContactListGestureOverlay extends Activity {
setContentView(R.layout.overlaydemo); setContentView(R.layout.overlaydemo);
// create a letter recognizer // create a letter recognizer
mRecognizer = LetterRecognizer.getLetterRecognizer(this, mRecognizer = LetterRecognizers.fromType(this,
LetterRecognizer.RECOGNIZER_LATIN_LOWERCASE); LetterRecognizers.RECOGNIZER_LATIN_LOWERCASE);
mOverlay = (GestureOverlayView) findViewById(R.id.overlay); mOverlay = (GestureOverlayView) findViewById(R.id.overlay);
// load the contact list // load the contact list

View File

@@ -36,9 +36,10 @@ import android.widget.Spinner;
import android.widget.AdapterView.OnItemSelectedListener; import android.widget.AdapterView.OnItemSelectedListener;
import android.gesture.Gesture; import android.gesture.Gesture;
import android.gesture.GestureLibrary;
import android.gesture.GestureOverlayView; import android.gesture.GestureOverlayView;
import android.gesture.Prediction; import android.gesture.Prediction;
import android.gesture.GestureLibraries;
import android.gesture.GestureLibrary;
import java.io.File; import java.io.File;
import java.util.ArrayList; import java.util.ArrayList;
@@ -61,7 +62,7 @@ public class GestureEntry extends Activity {
private Spinner mRecognitionResult; private Spinner mRecognitionResult;
private GestureLibrary mGestureLibrary; private GestureLibrary mGestureStore;
private boolean mChangedByRecognizer = false; private boolean mChangedByRecognizer = false;
@@ -71,8 +72,8 @@ public class GestureEntry extends Activity {
setContentView(R.layout.demo); setContentView(R.layout.demo);
// init the gesture library // init the gesture library
mGestureLibrary = new GestureLibrary(GESTURE_FILE_NAME); mGestureStore = GestureLibraries.fromFile(GESTURE_FILE_NAME);
mGestureLibrary.load(); mGestureStore.load();
// create the spinner for showing the recognition results // create the spinner for showing the recognition results
// the spinner also allows a user to correct a prediction // the spinner also allows a user to correct a prediction
@@ -82,7 +83,7 @@ public class GestureEntry extends Activity {
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) { public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
// correct the recognition result by adding the new example // correct the recognition result by adding the new example
if (!mChangedByRecognizer) { if (!mChangedByRecognizer) {
mGestureLibrary.addGesture(parent.getSelectedItem().toString(), mGesturePad mGestureStore.addGesture(parent.getSelectedItem().toString(), mGesturePad
.getGesture()); .getGesture());
} else { } else {
mChangedByRecognizer = false; mChangedByRecognizer = false;
@@ -109,7 +110,7 @@ public class GestureEntry extends Activity {
public void onGestureStarted(GestureOverlayView overlay, MotionEvent event) { public void onGestureStarted(GestureOverlayView overlay, MotionEvent event) {
overlay.clear(false); overlay.clear(false);
} }
public void onGestureCancelled(GestureOverlayView overlay, MotionEvent event) { public void onGestureCancelled(GestureOverlayView overlay, MotionEvent event) {
} }
}); });
@@ -134,7 +135,7 @@ public class GestureEntry extends Activity {
.findViewById(R.id.gesturename_edit); .findViewById(R.id.gesturename_edit);
String text = edittext.getText().toString().trim(); String text = edittext.getText().toString().trim();
if (text.length() > 0) { if (text.length() > 0) {
mGestureLibrary.addGesture(text, mGesturePad.getGesture()); mGestureStore.addGesture(text, mGesturePad.getGesture());
} }
} }
}).setNegativeButton(R.string.newgesture_dialog_cancel, }).setNegativeButton(R.string.newgesture_dialog_cancel,
@@ -173,14 +174,14 @@ public class GestureEntry extends Activity {
@Override @Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) { protected void onActivityResult(int requestCode, int resultCode, Intent data) {
mGestureLibrary.load(); mGestureStore.load();
mGesturePad.clear(false); mGesturePad.clear(false);
} }
@Override @Override
protected void onPause() { protected void onPause() {
super.onPause(); super.onPause();
mGestureLibrary.save(); mGestureStore.save();
} }
@Override @Override
@@ -195,12 +196,12 @@ public class GestureEntry extends Activity {
if (gesture != null) { if (gesture != null) {
outState.putParcelable(PARCEL_KEY, gesture); outState.putParcelable(PARCEL_KEY, gesture);
} }
mGestureLibrary.save(); mGestureStore.save();
} }
private void recognize(Gesture gesture) { private void recognize(Gesture gesture) {
mChangedByRecognizer = true; mChangedByRecognizer = true;
ArrayList<Prediction> predictions = mGestureLibrary.recognize(gesture); ArrayList<Prediction> predictions = mGestureStore.recognize(gesture);
ArrayAdapter<Prediction> adapter = new ArrayAdapter<Prediction>(this, ArrayAdapter<Prediction> adapter = new ArrayAdapter<Prediction>(this,
android.R.layout.simple_spinner_item, predictions); android.R.layout.simple_spinner_item, predictions);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);

View File

@@ -28,8 +28,9 @@ import android.widget.Spinner;
import android.widget.AdapterView.OnItemSelectedListener; import android.widget.AdapterView.OnItemSelectedListener;
import android.gesture.Gesture; import android.gesture.Gesture;
import android.gesture.GestureLibrary;
import android.gesture.GestureOverlayView; import android.gesture.GestureOverlayView;
import android.gesture.GestureLibraries;
import android.gesture.GestureLibrary;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
@@ -45,7 +46,7 @@ public class GestureLibViewer extends Activity {
private Spinner mGestureCategory; private Spinner mGestureCategory;
private GestureLibrary mGesureLibrary; private GestureLibrary mGesureStore;
private ArrayList<Gesture> mGestures; private ArrayList<Gesture> mGestures;
@@ -59,15 +60,15 @@ public class GestureLibViewer extends Activity {
String name = (String) mGestureCategory.getSelectedItem(); String name = (String) mGestureCategory.getSelectedItem();
Gesture gesture = mGestures.get(mCurrentGestureIndex); Gesture gesture = mGestures.get(mCurrentGestureIndex);
mGesureLibrary.removeGesture(name, gesture); mGesureStore.removeGesture(name, gesture);
mGestures = mGesureLibrary.getGestures(name); mGestures = mGesureStore.getGestures(name);
if (mGestures == null) { if (mGestures == null) {
// delete the entire entry // delete the entire entry
mCurrentGestureIndex = 0; mCurrentGestureIndex = 0;
ArrayList<String> list = new ArrayList<String>(); ArrayList<String> list = new ArrayList<String>();
list.addAll(mGesureLibrary.getGestureEntries()); list.addAll(mGesureStore.getGestureEntries());
Collections.sort(list); Collections.sort(list);
ArrayAdapter<String> adapter = new ArrayAdapter<String>(GestureLibViewer.this, ArrayAdapter<String> adapter = new ArrayAdapter<String>(GestureLibViewer.this,
android.R.layout.simple_spinner_item, list); android.R.layout.simple_spinner_item, list);
@@ -83,7 +84,7 @@ public class GestureLibViewer extends Activity {
} }
} }
} }
@Override @Override
public void onCreate(Bundle savedInstanceState) { public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
@@ -94,19 +95,19 @@ public class GestureLibViewer extends Activity {
mGesturePad.setEnabled(false); mGesturePad.setEnabled(false);
// init the gesture library // init the gesture library
mGesureLibrary = new GestureLibrary(GestureEntry.GESTURE_FILE_NAME); mGesureStore = GestureLibraries.fromFile(GestureEntry.GESTURE_FILE_NAME);
mGesureLibrary.load(); mGesureStore.load();
mGestureCategory = (Spinner) findViewById(R.id.spinner); mGestureCategory = (Spinner) findViewById(R.id.spinner);
ArrayList<String> list = new ArrayList<String>(); ArrayList<String> list = new ArrayList<String>();
if (!mGesureLibrary.getGestureEntries().isEmpty()) { if (!mGesureStore.getGestureEntries().isEmpty()) {
list.addAll(mGesureLibrary.getGestureEntries()); list.addAll(mGesureStore.getGestureEntries());
Collections.sort(list); Collections.sort(list);
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,
android.R.layout.simple_spinner_item, list); android.R.layout.simple_spinner_item, list);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
mGestureCategory.setAdapter(adapter); mGestureCategory.setAdapter(adapter);
mGestures = mGesureLibrary.getGestures(list.get(0)); mGestures = mGesureStore.getGestures(list.get(0));
mCurrentGestureIndex = 0; mCurrentGestureIndex = 0;
Gesture gesture = mGestures.get(mCurrentGestureIndex); Gesture gesture = mGestures.get(mCurrentGestureIndex);
mGesturePad.setGesture(gesture); mGesturePad.setGesture(gesture);
@@ -114,7 +115,7 @@ public class GestureLibViewer extends Activity {
mGestureCategory.setOnItemSelectedListener(new OnItemSelectedListener() { mGestureCategory.setOnItemSelectedListener(new OnItemSelectedListener() {
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) { public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
mGestures = mGesureLibrary.getGestures((String) mGestureCategory.getSelectedItem()); mGestures = mGesureStore.getGestures((String) mGestureCategory.getSelectedItem());
if (!mGestures.isEmpty()) { if (!mGestures.isEmpty()) {
mCurrentGestureIndex = 0; mCurrentGestureIndex = 0;
Gesture gesture = mGestures.get(mCurrentGestureIndex); Gesture gesture = mGestures.get(mCurrentGestureIndex);
@@ -160,7 +161,7 @@ public class GestureLibViewer extends Activity {
@Override @Override
public boolean onKeyUp(int keyCode, KeyEvent event) { public boolean onKeyUp(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK) { if (keyCode == KeyEvent.KEYCODE_BACK) {
mGesureLibrary.save(); mGesureStore.save();
setResult(RESULT_OK); setResult(RESULT_OK);
finish(); finish();
return true; return true;
@@ -172,12 +173,12 @@ public class GestureLibViewer extends Activity {
@Override @Override
protected void onPause() { protected void onPause() {
super.onPause(); super.onPause();
mGesureLibrary.save(); mGesureStore.save();
} }
@Override @Override
protected void onSaveInstanceState(Bundle outState) { protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState); super.onSaveInstanceState(outState);
mGesureLibrary.save(); mGesureStore.save();
} }
} }