diff options
author | Romain Guy <romainguy@android.com> | 2009-05-29 14:43:54 -0700 |
---|---|---|
committer | Romain Guy <romainguy@android.com> | 2009-05-29 14:43:54 -0700 |
commit | 0a63716ed0e44f7cd32b81a444429318d42d8f08 (patch) | |
tree | 76387f19e8f6a5ff28b2429396928cb9e2bb98b1 /core/java/android/gesture | |
parent | 7a8c437723a50b171d0cd97cb17886b28dffce92 (diff) | |
download | frameworks_base-0a63716ed0e44f7cd32b81a444429318d42d8f08.zip frameworks_base-0a63716ed0e44f7cd32b81a444429318d42d8f08.tar.gz frameworks_base-0a63716ed0e44f7cd32b81a444429318d42d8f08.tar.bz2 |
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.
Diffstat (limited to 'core/java/android/gesture')
-rw-r--r-- | core/java/android/gesture/GestureLibraries.java | 139 | ||||
-rw-r--r-- | core/java/android/gesture/GestureLibrary.java | 319 | ||||
-rw-r--r-- | core/java/android/gesture/GestureStore.java | 330 | ||||
-rwxr-xr-x | core/java/android/gesture/Instance.java | 4 | ||||
-rw-r--r-- | core/java/android/gesture/InstanceLearner.java | 2 | ||||
-rw-r--r-- | core/java/android/gesture/LetterRecognizer.java | 53 | ||||
-rw-r--r-- | core/java/android/gesture/LetterRecognizers.java | 65 |
7 files changed, 586 insertions, 326 deletions
diff --git a/core/java/android/gesture/GestureLibraries.java b/core/java/android/gesture/GestureLibraries.java new file mode 100644 index 0000000..2ce7a8e --- /dev/null +++ b/core/java/android/gesture/GestureLibraries.java @@ -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; + } + } +} diff --git a/core/java/android/gesture/GestureLibrary.java b/core/java/android/gesture/GestureLibrary.java index 9020d2b..a29c2c8 100644 --- a/core/java/android/gesture/GestureLibrary.java +++ b/core/java/android/gesture/GestureLibrary.java @@ -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"); * you may not use this file except in compliance with the License. @@ -14,337 +14,68 @@ * limitations under the License. */ -package android.gesture; -import android.util.Log; -import android.os.SystemClock; +package android.gesture; -import java.io.BufferedInputStream; -import java.io.BufferedOutputStream; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.DataOutputStream; -import java.io.DataInputStream; -import java.util.ArrayList; -import java.util.HashMap; import java.util.Set; -import java.util.Map; - -import static android.gesture.GestureConstants.LOG_TAG; - -/** - * GestureLibrary maintains gesture examples and makes predictions on a new - * gesture - */ -// -// File format for GestureLibrary: -// -// Nb. bytes Java type Description -// ----------------------------------- -// Header -// 2 bytes short File format version number -// 4 bytes int Number of entries -// Entry -// X bytes UTF String Entry name -// 4 bytes int Number of gestures -// Gesture -// 8 bytes long Gesture ID -// 4 bytes int Number of strokes -// Stroke -// 4 bytes int Number of points -// Point -// 4 bytes float X coordinate of the point -// 4 bytes float Y coordinate of the point -// 8 bytes long Time stamp -// -public class GestureLibrary { - public static final int SEQUENCE_INVARIANT = 1; - // when SEQUENCE_SENSITIVE is used, only single stroke gestures are currently allowed - public static final int SEQUENCE_SENSITIVE = 2; - - // ORIENTATION_SENSITIVE and ORIENTATION_INVARIANT are only for SEQUENCE_SENSITIVE gestures - public static final int ORIENTATION_INVARIANT = 1; - public static final int ORIENTATION_SENSITIVE = 2; - - private static final short FILE_FORMAT_VERSION = 1; - - private static final boolean PROFILE_LOADING_SAVING = false; +import java.util.ArrayList; - private int mSequenceType = SEQUENCE_SENSITIVE; - private int mOrientationStyle = ORIENTATION_SENSITIVE; +public abstract class GestureLibrary { + protected final GestureStore mStore; - private final String mGestureFileName; + protected GestureLibrary() { + mStore = new GestureStore(); + } - private final HashMap<String, ArrayList<Gesture>> mNamedGestures = - new HashMap<String, ArrayList<Gesture>>(); + public abstract boolean save(); - private Learner mClassifier; + public abstract boolean load(); - private boolean mChanged = false; + public boolean isReadOnly() { + return false; + } - /** - * @param path where gesture data is stored - */ - public GestureLibrary(String path) { - mGestureFileName = path; - mClassifier = new InstanceLearner(); + public Learner getLearner() { + return mStore.getLearner(); } - /** - * Specify how the gesture library will handle orientation. - * Use ORIENTATION_INVARIANT or ORIENTATION_SENSITIVE - * - * @param style - */ public void setOrientationStyle(int style) { - mOrientationStyle = style; + mStore.setOrientationStyle(style); } public int getOrientationStyle() { - return mOrientationStyle; + return mStore.getOrientationStyle(); } - /** - * @param type SEQUENCE_INVARIANT or SEQUENCE_SENSITIVE - */ public void setSequenceType(int type) { - mSequenceType = type; + mStore.setSequenceType(type); } - /** - * @return SEQUENCE_INVARIANT or SEQUENCE_SENSITIVE - */ 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() { - 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) { - Instance instance = Instance.createInstance(mSequenceType, mOrientationStyle, gesture, null); - return mClassifier.classify(mSequenceType, instance.vector); + return mStore.recognize(gesture); } - /** - * 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; + mStore.addGesture(entryName, gesture); } - /** - * 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; + mStore.removeGesture(entryName, gesture); } - /** - * Remove a entry of gestures - * - * @param entryName the entry name - */ public void removeEntry(String entryName) { - mNamedGestures.remove(entryName); - mClassifier.removeInstances(entryName); - mChanged = true; + mStore.removeEntry(entryName); } - /** - * Get all the gestures of an entry - * - * @param entryName - * @return the list of gestures that is under this name - */ public ArrayList<Gesture> getGestures(String entryName) { - ArrayList<Gesture> gestures = mNamedGestures.get(entryName); - if (gestures != null) { - return new ArrayList<Gesture>(gestures); - } else { - return null; - } - } - - /** - * Save the gesture library - */ - public boolean save() { - if (!mChanged) { - return true; - } - - boolean result = false; - DataOutputStream out = null; - - try { - File file = new File(mGestureFileName); - if (!file.getParentFile().exists()) { - if (!file.getParentFile().mkdirs()) { - return false; - } - } - - long start; - if (PROFILE_LOADING_SAVING) { - start = SystemClock.elapsedRealtime(); - } - - final HashMap<String, ArrayList<Gesture>> maps = mNamedGestures; - - out = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(file), - GestureConstants.IO_BUFFER_SIZE)); - // Write version number - out.writeShort(FILE_FORMAT_VERSION); - // Write number of entries - out.writeInt(maps.size()); - - for (Map.Entry<String, ArrayList<Gesture>> entry : maps.entrySet()) { - final String key = entry.getKey(); - final ArrayList<Gesture> examples = entry.getValue(); - final int count = examples.size(); - - // Write entry name - out.writeUTF(key); - // Write number of examples for this entry - out.writeInt(count); - - for (int i = 0; i < count; i++) { - examples.get(i).serialize(out); - } - } - - out.flush(); - - if (PROFILE_LOADING_SAVING) { - long end = SystemClock.elapsedRealtime(); - Log.d(LOG_TAG, "Saving gestures library = " + (end - start) + " ms"); - } - - mChanged = false; - result = true; - } catch (IOException ex) { - Log.d(LOG_TAG, "Failed to save gestures:", ex); - } finally { - GestureUtilities.closeStream(out); - } - - return result; - } - - /** - * Load the gesture library - */ - public boolean load() { - boolean result = false; - - final File file = new File(mGestureFileName); - if (file.exists()) { - DataInputStream in = null; - try { - in = new DataInputStream(new BufferedInputStream( - new FileInputStream(mGestureFileName), GestureConstants.IO_BUFFER_SIZE)); - - long start; - if (PROFILE_LOADING_SAVING) { - start = SystemClock.elapsedRealtime(); - } - - // Read file format version number - final short versionNumber = in.readShort(); - switch (versionNumber) { - case 1: - readFormatV1(in); - break; - } - - if (PROFILE_LOADING_SAVING) { - long end = SystemClock.elapsedRealtime(); - Log.d(LOG_TAG, "Loading gestures library = " + (end - start) + " ms"); - } - - result = true; - } catch (IOException ex) { - Log.d(LOG_TAG, "Failed to load gestures:", ex); - } finally { - GestureUtilities.closeStream(in); - } - } - - return result; - } - - private void readFormatV1(DataInputStream in) throws IOException { - final Learner classifier = mClassifier; - final HashMap<String, ArrayList<Gesture>> namedGestures = mNamedGestures; - namedGestures.clear(); - - // Number of entries in the library - final int entriesCount = in.readInt(); - - for (int i = 0; i < entriesCount; i++) { - // Entry name - final String name = in.readUTF(); - // Number of gestures - final int gestureCount = in.readInt(); - - final ArrayList<Gesture> gestures = new ArrayList<Gesture>(gestureCount); - for (int j = 0; j < gestureCount; j++) { - final Gesture gesture = Gesture.deserialize(in); - gestures.add(gesture); - classifier.addInstance(Instance.createInstance(mSequenceType, mOrientationStyle, gesture, name)); - } - - namedGestures.put(name, gestures); - } - } - - Learner getLearner() { - return mClassifier; + return mStore.getGestures(entryName); } } diff --git a/core/java/android/gesture/GestureStore.java b/core/java/android/gesture/GestureStore.java new file mode 100644 index 0000000..ddf1c83 --- /dev/null +++ b/core/java/android/gesture/GestureStore.java @@ -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; + } +} diff --git a/core/java/android/gesture/Instance.java b/core/java/android/gesture/Instance.java index 9ac0a96..ef208ac 100755 --- a/core/java/android/gesture/Instance.java +++ b/core/java/android/gesture/Instance.java @@ -72,7 +72,7 @@ class Instance { static Instance createInstance(int sequenceType, int orientationType, Gesture gesture, String label) { float[] pts; Instance instance; - if (sequenceType == GestureLibrary.SEQUENCE_SENSITIVE) { + if (sequenceType == GestureStore.SEQUENCE_SENSITIVE) { pts = temporalSampler(orientationType, gesture); instance = new Instance(gesture.getID(), pts, label); instance.normalize(); @@ -94,7 +94,7 @@ class Instance { float orientation = (float)Math.atan2(pts[1] - center[1], pts[0] - center[0]); float adjustment = -orientation; - if (orientationType == GestureLibrary.ORIENTATION_SENSITIVE) { + if (orientationType == GestureStore.ORIENTATION_SENSITIVE) { int count = ORIENTATIONS.length; for (int i = 0; i < count; i++) { float delta = ORIENTATIONS[i] - orientation; diff --git a/core/java/android/gesture/InstanceLearner.java b/core/java/android/gesture/InstanceLearner.java index b6feb64..00cdadc 100644 --- a/core/java/android/gesture/InstanceLearner.java +++ b/core/java/android/gesture/InstanceLearner.java @@ -38,7 +38,7 @@ class InstanceLearner extends Learner { continue; } double distance; - if (sequenceType == GestureLibrary.SEQUENCE_SENSITIVE) { + if (sequenceType == GestureStore.SEQUENCE_SENSITIVE) { distance = GestureUtilities.cosineDistance(sample.vector, vector); } else { distance = GestureUtilities.squaredEuclideanDistance(sample.vector, vector); diff --git a/core/java/android/gesture/LetterRecognizer.java b/core/java/android/gesture/LetterRecognizer.java index 9e801ed..580fc26 100644 --- a/core/java/android/gesture/LetterRecognizer.java +++ b/core/java/android/gesture/LetterRecognizer.java @@ -23,6 +23,7 @@ import android.util.Log; import java.io.BufferedInputStream; import java.io.DataInputStream; import java.io.IOException; +import java.io.InputStream; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; @@ -31,10 +32,9 @@ import java.util.HashMap; import static android.gesture.GestureConstants.LOG_TAG; public class LetterRecognizer { - public final static int RECOGNIZER_LATIN_LOWERCASE = 0; 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[] mOutputLayer; @@ -42,8 +42,8 @@ public class LetterRecognizer { private final String[] mClasses; private final int mPatchSize; - - private GestureLibrary mGestureLibrary; + + private GestureLibrary mGestureStore; 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) { mPatchSize = (int) Math.sqrt(numOfInput); mHiddenLayer = new SigmoidUnit[numOfHidden]; @@ -137,14 +128,18 @@ public class LetterRecognizer { return output; } - private static LetterRecognizer createFromResource(Context context, int resourceID) { + static LetterRecognizer createFromResource(Context context, int resourceID) { final Resources resources = context.getResources(); + final InputStream stream = resources.openRawResource(resourceID); + return createFromStream(stream); + } + static LetterRecognizer createFromStream(InputStream stream) { DataInputStream in = null; LetterRecognizer classifier = null; try { - in = new DataInputStream(new BufferedInputStream(resources.openRawResource(resourceID), + in = new DataInputStream(new BufferedInputStream(stream, GestureConstants.IO_BUFFER_SIZE)); 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 * * @hide */ public boolean save() { - if (mGestureLibrary != null) { - return mGestureLibrary.save(); + if (mGestureStore != null) { + return mGestureStore.save(); } 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 * * @hide */ public void setPersonalizationEnabled(boolean enabled) { if (enabled) { - mGestureLibrary = new GestureLibrary(GESTURE_FILE_NAME); - mGestureLibrary.setSequenceType(GestureLibrary.SEQUENCE_INVARIANT); - mGestureLibrary.load(); + mGestureStore = GestureLibraries.fromFile(GESTURE_FILE_NAME); + mGestureStore.setSequenceType(GestureStore.SEQUENCE_INVARIANT); + mGestureStore.load(); } 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 * * @hide */ public void addExample(String letter, Gesture example) { - if (mGestureLibrary != null) { - mGestureLibrary.addGesture(letter, example); + if (mGestureStore != null) { + mGestureStore.addGesture(letter, example); } } - + private void adjustPrediction(Gesture query, ArrayList<Prediction> predictions) { - if (mGestureLibrary != null) { - final ArrayList<Prediction> results = mGestureLibrary.recognize(query); + if (mGestureStore != null) { + final ArrayList<Prediction> results = mGestureStore.recognize(query); final HashMap<String, Prediction> topNList = new HashMap<String, Prediction>(); for (int j = 0; j < ADJUST_RANGE; j++) { diff --git a/core/java/android/gesture/LetterRecognizers.java b/core/java/android/gesture/LetterRecognizers.java new file mode 100644 index 0000000..e3f45a0 --- /dev/null +++ b/core/java/android/gesture/LetterRecognizers.java @@ -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); + } +} |