Recovered the code of the gesture library
diff --git a/tests/sketch/src/com/android/gesture/GestureLibrary.java b/tests/sketch/src/com/android/gesture/GestureLibrary.java
new file mode 100644
index 0000000..c89aa16
--- /dev/null
+++ b/tests/sketch/src/com/android/gesture/GestureLibrary.java
@@ -0,0 +1,337 @@
+/*
+ * Copyright (C) 2008-2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.gesture;
+
+import android.util.Config;
+import android.util.Log;
+import android.util.Xml;
+import android.util.Xml.Encoding;
+
+import org.xml.sax.Attributes;
+import org.xml.sax.ContentHandler;
+import org.xml.sax.Locator;
+import org.xml.sax.SAXException;
+import org.xmlpull.v1.XmlSerializer;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Set;
+
+/**
+ * GestureLibrary maintains gesture examples and makes predictions on a new
+ * gesture
+ */
+public class GestureLibrary {
+
+ public static final int SEQUENCE_INVARIANT = 1;
+
+ // when SEQUENCE_SENSITIVE is used, only single stroke gestures are allowed
+ public static final int SEQUENCE_SENSITIVE = 2;
+
+ private int mSequenceType = SEQUENCE_SENSITIVE;
+
+ public static final int ORIENTATION_INVARIANT = 1;
+
+ // ORIENTATION_SENSITIVE is only available for single stroke gestures
+ public static final int ORIENTATION_SENSITIVE = 2;
+
+ private int mOrientationStyle = ORIENTATION_SENSITIVE;
+
+ private static final String LOGTAG = "GestureLibrary";
+
+ private static final String NAMESPACE = "";
+
+ private final String mGestureFileName;
+
+ private HashMap<String, ArrayList<Gesture>> mEntryName2gestures = new HashMap<String, ArrayList<Gesture>>();
+
+ private Learner mClassifier;
+
+ private boolean mChanged = false;
+
+ /**
+ * @param path where gesture data is stored
+ */
+ public GestureLibrary(String path) {
+ mGestureFileName = path;
+ mClassifier = new InstanceLearner();
+ }
+
+ /**
+ * Specify whether the gesture library will handle orientation sensitive
+ * gestures. Use ORIENTATION_INVARIANT or ORIENTATION_SENSITIVE
+ *
+ * @param style
+ */
+ public void setOrientationStyle(int style) {
+ mOrientationStyle = style;
+ }
+
+ public int getOrientationStyle() {
+ return mOrientationStyle;
+ }
+
+ public void setGestureType(int type) {
+ mSequenceType = type;
+ }
+
+ public int getGestureType() {
+ return mSequenceType;
+ }
+
+ /**
+ * Get all the gesture entry names in the library
+ *
+ * @return a set of strings
+ */
+ public Set<String> getGestureEntries() {
+ return mEntryName2gestures.keySet();
+ }
+
+ /**
+ * Recognize a gesture
+ *
+ * @param gesture the query
+ * @return a list of predictions of possible entries for a given gesture
+ */
+ public ArrayList<Prediction> recognize(Gesture gesture) {
+ Instance instance = Instance.createInstance(this, gesture, null);
+ return mClassifier.classify(this, instance);
+ }
+
+ /**
+ * Add a gesture for the entry
+ *
+ * @param entryName entry name
+ * @param gesture
+ */
+ public void addGesture(String entryName, Gesture gesture) {
+ if (Config.DEBUG) {
+ Log.v(LOGTAG, "Add an example for gesture: " + entryName);
+ }
+ if (entryName == null || entryName.length() == 0) {
+ return;
+ }
+ ArrayList<Gesture> gestures = mEntryName2gestures.get(entryName);
+ if (gestures == null) {
+ gestures = new ArrayList<Gesture>();
+ mEntryName2gestures.put(entryName, gestures);
+ }
+ gestures.add(gesture);
+ mClassifier.addInstance(Instance.createInstance(this, gesture, entryName));
+ mChanged = true;
+ }
+
+ /**
+ * Remove a gesture from the library. If there are no more gestures for the
+ * given entry, the gesture entry will be removed.
+ *
+ * @param entryName entry name
+ * @param gesture
+ */
+ public void removeGesture(String entryName, Gesture gesture) {
+ ArrayList<Gesture> gestures = mEntryName2gestures.get(entryName);
+ if (gestures == null) {
+ return;
+ }
+
+ gestures.remove(gesture);
+
+ // if there are no more samples, remove the entry automatically
+ if (gestures.isEmpty()) {
+ mEntryName2gestures.remove(entryName);
+ }
+
+ mClassifier.removeInstance(gesture.getID());
+
+ mChanged = true;
+ }
+
+ /**
+ * Remove a entry of gestures
+ *
+ * @param entryName the entry name
+ */
+ public void removeEntireEntry(String entryName) {
+ mEntryName2gestures.remove(entryName);
+ mClassifier.removeInstances(entryName);
+ mChanged = true;
+ }
+
+ /**
+ * Get all the gestures of an entry
+ *
+ * @param entryName
+ * @return the list of gestures that is under this name
+ */
+ @SuppressWarnings("unchecked")
+ public ArrayList<Gesture> getGestures(String entryName) {
+ ArrayList<Gesture> gestures = mEntryName2gestures.get(entryName);
+ if (gestures != null) {
+ return (ArrayList<Gesture>)gestures.clone();
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Save the gesture library
+ */
+ public void save() {
+ if (!mChanged)
+ return;
+
+ try {
+ File file = new File(mGestureFileName);
+ if (!file.getParentFile().exists()) {
+ file.getParentFile().mkdirs();
+ }
+ if (Config.DEBUG) {
+ Log.v(LOGTAG, "Save to " + mGestureFileName);
+ }
+ BufferedOutputStream outputStream = new BufferedOutputStream(new FileOutputStream(
+ mGestureFileName), GestureConstants.IO_BUFFER_SIZE);
+
+ PrintWriter writer = new PrintWriter(outputStream);
+ XmlSerializer serializer = Xml.newSerializer();
+ serializer.setOutput(writer);
+ serializer.startDocument(Encoding.ISO_8859_1.name(), null);
+ serializer.startTag(NAMESPACE, GestureConstants.XML_TAG_LIBRARY);
+ HashMap<String, ArrayList<Gesture>> maps = mEntryName2gestures;
+ Iterator<String> it = maps.keySet().iterator();
+ while (it.hasNext()) {
+ String key = it.next();
+ ArrayList<Gesture> examples = maps.get(key);
+ // save an entry
+ serializer.startTag(NAMESPACE, GestureConstants.XML_TAG_ENTRY);
+ serializer.attribute(NAMESPACE, GestureConstants.XML_TAG_NAME, key);
+ int count = examples.size();
+ for (int i = 0; i < count; i++) {
+ Gesture gesture = examples.get(i);
+ // save each gesture in the entry
+ gesture.toXML(NAMESPACE, serializer);
+ }
+ serializer.endTag(NAMESPACE, GestureConstants.XML_TAG_ENTRY);
+ }
+ serializer.endTag(NAMESPACE, GestureConstants.XML_TAG_LIBRARY);
+ serializer.endDocument();
+ serializer.flush();
+ writer.close();
+ outputStream.close();
+ mChanged = false;
+ } catch (IOException ex) {
+ Log.d(LOGTAG, "Failed to save gestures:", ex);
+ }
+ }
+
+ /**
+ * Load the gesture library
+ */
+ public void load() {
+ File file = new File(mGestureFileName);
+ if (file.exists()) {
+ try {
+ if (Config.DEBUG) {
+ Log.v(LOGTAG, "Load from " + mGestureFileName);
+ }
+ BufferedInputStream in = new BufferedInputStream(new FileInputStream(
+ mGestureFileName), GestureConstants.IO_BUFFER_SIZE);
+ Xml.parse(in, Encoding.ISO_8859_1, new CompactInkHandler());
+ in.close();
+ } catch (SAXException ex) {
+ Log.d(LOGTAG, "Failed to load gestures:", ex);
+ } catch (IOException ex) {
+ Log.d(LOGTAG, "Failed to load gestures:", ex);
+ }
+ }
+ }
+
+ private class CompactInkHandler implements ContentHandler {
+ Gesture currentGesture = null;
+
+ StringBuilder buffer = new StringBuilder(GestureConstants.STROKE_STRING_BUFFER_SIZE);
+
+ String entryName;
+
+ ArrayList<Gesture> gestures;
+
+ CompactInkHandler() {
+ }
+
+ public void characters(char[] ch, int start, int length) {
+ buffer.append(ch, start, length);
+ }
+
+ public void endDocument() {
+ }
+
+ public void endElement(String uri, String localName, String qName) {
+ if (localName.equals(GestureConstants.XML_TAG_ENTRY)) {
+ mEntryName2gestures.put(entryName, gestures);
+ gestures = null;
+ } else if (localName.equals(GestureConstants.XML_TAG_GESTURE)) {
+ gestures.add(currentGesture);
+ mClassifier.addInstance(Instance.createInstance(GestureLibrary.this,
+ currentGesture, entryName));
+ currentGesture = null;
+ } else if (localName.equals(GestureConstants.XML_TAG_STROKE)) {
+ currentGesture.addStroke(GestureStroke.createFromString(buffer.toString()));
+ buffer.setLength(0);
+ }
+ }
+
+ public void endPrefixMapping(String prefix) {
+ }
+
+ public void ignorableWhitespace(char[] ch, int start, int length) {
+ }
+
+ public void processingInstruction(String target, String data) {
+ }
+
+ public void setDocumentLocator(Locator locator) {
+ }
+
+ public void skippedEntity(String name) {
+ }
+
+ public void startDocument() {
+ }
+
+ public void startElement(String uri, String localName, String qName, Attributes attributes) {
+ if (localName.equals(GestureConstants.XML_TAG_ENTRY)) {
+ gestures = new ArrayList<Gesture>();
+ entryName = attributes.getValue(NAMESPACE, GestureConstants.XML_TAG_NAME);
+ } else if (localName.equals(GestureConstants.XML_TAG_GESTURE)) {
+ currentGesture = new Gesture();
+ currentGesture.setID(Long.parseLong(attributes.getValue(NAMESPACE,
+ GestureConstants.XML_TAG_ID)));
+ }
+ }
+
+ public void startPrefixMapping(String prefix, String uri) {
+ }
+ }
+}