10a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy/* 20a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy * Copyright (C) 2008-2009 The Android Open Source Project 30a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy * 40a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy * Licensed under the Apache License, Version 2.0 (the "License"); 50a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy * you may not use this file except in compliance with the License. 60a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy * You may obtain a copy of the License at 70a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy * 80a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy * http://www.apache.org/licenses/LICENSE-2.0 90a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy * 100a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy * Unless required by applicable law or agreed to in writing, software 110a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy * distributed under the License is distributed on an "AS IS" BASIS, 120a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 130a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy * See the License for the specific language governing permissions and 140a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy * limitations under the License. 150a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy */ 160a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy 170a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guypackage android.gesture; 180a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy 190a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guyimport android.util.Log; 200a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guyimport android.os.SystemClock; 210a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy 220a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guyimport java.io.BufferedInputStream; 230a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guyimport java.io.BufferedOutputStream; 240a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guyimport java.io.IOException; 250a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guyimport java.io.DataOutputStream; 260a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guyimport java.io.DataInputStream; 270a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guyimport java.io.InputStream; 280a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guyimport java.io.OutputStream; 290a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guyimport java.util.ArrayList; 300a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guyimport java.util.HashMap; 310a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guyimport java.util.Set; 320a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guyimport java.util.Map; 330a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy 340a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guyimport static android.gesture.GestureConstants.LOG_TAG; 350a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy 360a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy/** 370a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy * GestureLibrary maintains gesture examples and makes predictions on a new 380a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy * gesture 390a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy */ 400a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy// 410a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy// File format for GestureStore: 420a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy// 430a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy// Nb. bytes Java type Description 440a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy// ----------------------------------- 450a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy// Header 460a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy// 2 bytes short File format version number 470a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy// 4 bytes int Number of entries 480a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy// Entry 490a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy// X bytes UTF String Entry name 500a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy// 4 bytes int Number of gestures 510a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy// Gesture 520a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy// 8 bytes long Gesture ID 530a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy// 4 bytes int Number of strokes 540a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy// Stroke 550a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy// 4 bytes int Number of points 560a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy// Point 570a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy// 4 bytes float X coordinate of the point 580a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy// 4 bytes float Y coordinate of the point 590a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy// 8 bytes long Time stamp 600a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy// 610a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guypublic class GestureStore { 620a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy public static final int SEQUENCE_INVARIANT = 1; 630a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy // when SEQUENCE_SENSITIVE is used, only single stroke gestures are currently allowed 640a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy public static final int SEQUENCE_SENSITIVE = 2; 650a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy 660a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy // ORIENTATION_SENSITIVE and ORIENTATION_INVARIANT are only for SEQUENCE_SENSITIVE gestures 670a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy public static final int ORIENTATION_INVARIANT = 1; 684758f1216bd16763c72500bc3c2f0fb43c08d613Yang Li // at most 2 directions can be recognized 690a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy public static final int ORIENTATION_SENSITIVE = 2; 704758f1216bd16763c72500bc3c2f0fb43c08d613Yang Li // at most 4 directions can be recognized 714758f1216bd16763c72500bc3c2f0fb43c08d613Yang Li static final int ORIENTATION_SENSITIVE_4 = 4; 724758f1216bd16763c72500bc3c2f0fb43c08d613Yang Li // at most 8 directions can be recognized 734758f1216bd16763c72500bc3c2f0fb43c08d613Yang Li static final int ORIENTATION_SENSITIVE_8 = 8; 740a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy 750a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy private static final short FILE_FORMAT_VERSION = 1; 760a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy 770a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy private static final boolean PROFILE_LOADING_SAVING = false; 780a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy 790a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy private int mSequenceType = SEQUENCE_SENSITIVE; 800a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy private int mOrientationStyle = ORIENTATION_SENSITIVE; 810a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy 820a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy private final HashMap<String, ArrayList<Gesture>> mNamedGestures = 830a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy new HashMap<String, ArrayList<Gesture>>(); 840a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy 850a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy private Learner mClassifier; 860a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy 870a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy private boolean mChanged = false; 880a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy 890a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy public GestureStore() { 900a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy mClassifier = new InstanceLearner(); 910a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy } 920a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy 930a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy /** 940a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy * Specify how the gesture library will handle orientation. 950a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy * Use ORIENTATION_INVARIANT or ORIENTATION_SENSITIVE 960a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy * 970a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy * @param style 980a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy */ 990a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy public void setOrientationStyle(int style) { 1000a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy mOrientationStyle = style; 1010a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy } 1020a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy 1030a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy public int getOrientationStyle() { 1040a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy return mOrientationStyle; 1050a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy } 1060a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy 1070a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy /** 1080a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy * @param type SEQUENCE_INVARIANT or SEQUENCE_SENSITIVE 1090a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy */ 1100a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy public void setSequenceType(int type) { 1110a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy mSequenceType = type; 1120a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy } 1130a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy 1140a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy /** 1150a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy * @return SEQUENCE_INVARIANT or SEQUENCE_SENSITIVE 1160a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy */ 1170a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy public int getSequenceType() { 1180a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy return mSequenceType; 1190a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy } 1200a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy 1210a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy /** 1220a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy * Get all the gesture entry names in the library 1230a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy * 1240a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy * @return a set of strings 1250a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy */ 1260a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy public Set<String> getGestureEntries() { 1270a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy return mNamedGestures.keySet(); 1280a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy } 1290a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy 1300a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy /** 1310a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy * Recognize a gesture 1320a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy * 1330a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy * @param gesture the query 1340a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy * @return a list of predictions of possible entries for a given gesture 1350a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy */ 1360a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy public ArrayList<Prediction> recognize(Gesture gesture) { 1370a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy Instance instance = Instance.createInstance(mSequenceType, 1380a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy mOrientationStyle, gesture, null); 1394758f1216bd16763c72500bc3c2f0fb43c08d613Yang Li return mClassifier.classify(mSequenceType, mOrientationStyle, instance.vector); 1400a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy } 1410a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy 1420a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy /** 1430a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy * Add a gesture for the entry 1440a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy * 1450a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy * @param entryName entry name 1460a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy * @param gesture 1470a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy */ 1480a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy public void addGesture(String entryName, Gesture gesture) { 1490a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy if (entryName == null || entryName.length() == 0) { 1500a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy return; 1510a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy } 1520a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy ArrayList<Gesture> gestures = mNamedGestures.get(entryName); 1530a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy if (gestures == null) { 1540a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy gestures = new ArrayList<Gesture>(); 1550a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy mNamedGestures.put(entryName, gestures); 1560a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy } 1570a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy gestures.add(gesture); 1580a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy mClassifier.addInstance( 1590a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy Instance.createInstance(mSequenceType, mOrientationStyle, gesture, entryName)); 1600a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy mChanged = true; 1610a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy } 1620a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy 1630a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy /** 1640a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy * Remove a gesture from the library. If there are no more gestures for the 1650a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy * given entry, the gesture entry will be removed. 1660a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy * 1670a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy * @param entryName entry name 1680a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy * @param gesture 1690a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy */ 1700a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy public void removeGesture(String entryName, Gesture gesture) { 1710a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy ArrayList<Gesture> gestures = mNamedGestures.get(entryName); 1720a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy if (gestures == null) { 1730a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy return; 1740a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy } 1750a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy 1760a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy gestures.remove(gesture); 1770a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy 1780a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy // if there are no more samples, remove the entry automatically 1790a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy if (gestures.isEmpty()) { 1800a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy mNamedGestures.remove(entryName); 1810a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy } 1820a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy 1830a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy mClassifier.removeInstance(gesture.getID()); 1840a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy 1850a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy mChanged = true; 1860a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy } 1870a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy 1880a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy /** 1890a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy * Remove a entry of gestures 1900a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy * 1910a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy * @param entryName the entry name 1920a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy */ 1930a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy public void removeEntry(String entryName) { 1940a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy mNamedGestures.remove(entryName); 1950a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy mClassifier.removeInstances(entryName); 1960a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy mChanged = true; 1970a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy } 1980a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy 1990a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy /** 2000a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy * Get all the gestures of an entry 2010a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy * 2020a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy * @param entryName 2030a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy * @return the list of gestures that is under this name 2040a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy */ 2050a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy public ArrayList<Gesture> getGestures(String entryName) { 2060a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy ArrayList<Gesture> gestures = mNamedGestures.get(entryName); 2070a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy if (gestures != null) { 2080a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy return new ArrayList<Gesture>(gestures); 2090a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy } else { 2100a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy return null; 2110a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy } 2120a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy } 2130a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy 21403f0b21b5a317aa6c0f0cd4d7ac91cabdf379d3eRomain Guy public boolean hasChanged() { 21503f0b21b5a317aa6c0f0cd4d7ac91cabdf379d3eRomain Guy return mChanged; 21603f0b21b5a317aa6c0f0cd4d7ac91cabdf379d3eRomain Guy } 21703f0b21b5a317aa6c0f0cd4d7ac91cabdf379d3eRomain Guy 2180a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy /** 2190a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy * Save the gesture library 2200a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy */ 2210a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy public void save(OutputStream stream) throws IOException { 2220a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy save(stream, false); 2230a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy } 2240a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy 2250a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy public void save(OutputStream stream, boolean closeStream) throws IOException { 2260a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy DataOutputStream out = null; 2270a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy 2280a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy try { 2290a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy long start; 2300a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy if (PROFILE_LOADING_SAVING) { 2310a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy start = SystemClock.elapsedRealtime(); 2320a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy } 2330a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy 2340a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy final HashMap<String, ArrayList<Gesture>> maps = mNamedGestures; 2350a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy 2367fe416e9436a7b2a00e27e73ceb725de4e763f30Romain Guy out = new DataOutputStream((stream instanceof BufferedOutputStream) ? stream : 2377fe416e9436a7b2a00e27e73ceb725de4e763f30Romain Guy new BufferedOutputStream(stream, GestureConstants.IO_BUFFER_SIZE)); 2380a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy // Write version number 2390a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy out.writeShort(FILE_FORMAT_VERSION); 2400a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy // Write number of entries 2410a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy out.writeInt(maps.size()); 2420a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy 2430a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy for (Map.Entry<String, ArrayList<Gesture>> entry : maps.entrySet()) { 2440a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy final String key = entry.getKey(); 2450a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy final ArrayList<Gesture> examples = entry.getValue(); 2460a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy final int count = examples.size(); 2470a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy 2480a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy // Write entry name 2490a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy out.writeUTF(key); 2500a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy // Write number of examples for this entry 2510a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy out.writeInt(count); 2520a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy 2530a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy for (int i = 0; i < count; i++) { 2540a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy examples.get(i).serialize(out); 2550a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy } 2560a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy } 2570a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy 2580a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy out.flush(); 2590a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy 2600a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy if (PROFILE_LOADING_SAVING) { 2610a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy long end = SystemClock.elapsedRealtime(); 2620a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy Log.d(LOG_TAG, "Saving gestures library = " + (end - start) + " ms"); 2630a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy } 2640a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy 2650a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy mChanged = false; 2660a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy } finally { 26746c53129c6f27c9193ab195a69cb50591b8c1fa2Romain Guy if (closeStream) GestureUtils.closeStream(out); 2680a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy } 2690a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy } 2700a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy 2710a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy /** 2720a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy * Load the gesture library 2730a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy */ 2740a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy public void load(InputStream stream) throws IOException { 2750a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy load(stream, false); 2760a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy } 2770a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy 2780a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy public void load(InputStream stream, boolean closeStream) throws IOException { 2790a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy DataInputStream in = null; 2800a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy try { 2810a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy in = new DataInputStream((stream instanceof BufferedInputStream) ? stream : 2820a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy new BufferedInputStream(stream, GestureConstants.IO_BUFFER_SIZE)); 2830a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy 2840a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy long start; 2850a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy if (PROFILE_LOADING_SAVING) { 2860a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy start = SystemClock.elapsedRealtime(); 2870a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy } 2880a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy 2890a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy // Read file format version number 2900a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy final short versionNumber = in.readShort(); 2910a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy switch (versionNumber) { 2920a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy case 1: 2930a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy readFormatV1(in); 2940a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy break; 2950a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy } 2960a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy 2970a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy if (PROFILE_LOADING_SAVING) { 2980a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy long end = SystemClock.elapsedRealtime(); 2990a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy Log.d(LOG_TAG, "Loading gestures library = " + (end - start) + " ms"); 3000a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy } 3010a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy } finally { 30246c53129c6f27c9193ab195a69cb50591b8c1fa2Romain Guy if (closeStream) GestureUtils.closeStream(in); 3030a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy } 3040a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy } 3050a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy 3060a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy private void readFormatV1(DataInputStream in) throws IOException { 3070a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy final Learner classifier = mClassifier; 3080a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy final HashMap<String, ArrayList<Gesture>> namedGestures = mNamedGestures; 3090a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy namedGestures.clear(); 3100a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy 3110a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy // Number of entries in the library 3120a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy final int entriesCount = in.readInt(); 3130a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy 3140a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy for (int i = 0; i < entriesCount; i++) { 3150a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy // Entry name 3160a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy final String name = in.readUTF(); 3170a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy // Number of gestures 3180a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy final int gestureCount = in.readInt(); 3190a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy 3200a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy final ArrayList<Gesture> gestures = new ArrayList<Gesture>(gestureCount); 3210a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy for (int j = 0; j < gestureCount; j++) { 3220a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy final Gesture gesture = Gesture.deserialize(in); 3230a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy gestures.add(gesture); 3240a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy classifier.addInstance( 3250a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy Instance.createInstance(mSequenceType, mOrientationStyle, gesture, name)); 3260a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy } 3270a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy 3280a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy namedGestures.put(name, gestures); 3290a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy } 3300a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy } 3310a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy 3320a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy Learner getLearner() { 3330a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy return mClassifier; 3340a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy } 3350a63716ed0e44f7cd32b81a444429318d42d8f08Romain Guy} 336