/shell/src/com/google/marvin/shell/MenuManager.java

http://eyes-free.googlecode.com/ · Java · 278 lines · 204 code · 23 blank · 51 comment · 40 complexity · 32bab27337b42c2bb0ef5b26ffcf7a73 MD5 · raw file

  1. /*
  2. * Copyright (C) 2010 Google Inc.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License"); you may not
  5. * use this file except in compliance with the License. You may obtain a copy of
  6. * the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  12. * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
  13. * License for the specific language governing permissions and limitations under
  14. * the License.
  15. */
  16. package com.google.marvin.shell;
  17. import android.content.Context;
  18. import android.content.pm.PackageManager;
  19. import android.content.res.Resources;
  20. import com.google.marvin.widget.GestureOverlay.Gesture;
  21. import org.w3c.dom.Document;
  22. import org.w3c.dom.NamedNodeMap;
  23. import org.w3c.dom.Node;
  24. import org.w3c.dom.NodeList;
  25. import java.io.FileInputStream;
  26. import java.io.FileNotFoundException;
  27. import java.io.FileOutputStream;
  28. import java.io.IOException;
  29. import java.io.InputStream;
  30. import java.io.OutputStreamWriter;
  31. import java.util.HashMap;
  32. import javax.xml.parsers.DocumentBuilder;
  33. import javax.xml.parsers.DocumentBuilderFactory;
  34. /**
  35. * Manages a set of menus and provides functions for saving/loading XML and
  36. * editing menus.
  37. *
  38. * @author clchen@google.com (Charles L. Chen)
  39. * @author credo@google.com (Tim Credo)
  40. */
  41. public final class MenuManager extends HashMap<String, Menu> {
  42. private static String XML_SHELL_TAG = "<shell>\n";
  43. private static String XML_VERSION_TAG = "<version number='0.1' />\n";
  44. private static String XML_SHELL_CLOSE_TAG = "</shell>\n";
  45. /**
  46. * Write out the currently loaded set of menus to an XML string.
  47. */
  48. public String toXml() {
  49. StringBuffer xml = new StringBuffer();
  50. xml.append(XML_SHELL_TAG);
  51. xml.append(XML_VERSION_TAG);
  52. for (String menuName : keySet()) {
  53. xml.append(get(menuName).toXml());
  54. }
  55. xml.append(XML_SHELL_CLOSE_TAG);
  56. return xml.toString();
  57. }
  58. /**
  59. * Write currently loaded menus to an XML file.
  60. */
  61. public void save(String filename) {
  62. try {
  63. FileOutputStream fileOutputStream = new FileOutputStream(filename);
  64. OutputStreamWriter outputStreamWriter = new OutputStreamWriter(fileOutputStream);
  65. outputStreamWriter.write(toXml());
  66. outputStreamWriter.close();
  67. } catch (FileNotFoundException e) {
  68. e.printStackTrace();
  69. } catch (IOException e) {
  70. e.printStackTrace();
  71. }
  72. }
  73. /**
  74. * Insert a new menu.
  75. */
  76. public void insertMenu(Menu currentMenu, Integer gesture, String menuName) {
  77. String id = menuName;
  78. int n = 1;
  79. // if the id is a duplicate, add a number
  80. while (containsKey(id)) {
  81. n = n + 1;
  82. id = menuName + " " + String.valueOf(n);
  83. }
  84. int oppositeGesture;
  85. if (gesture == Gesture.EDGELEFT) {
  86. oppositeGesture = Gesture.EDGERIGHT;
  87. } else if (gesture == Gesture.EDGERIGHT) {
  88. oppositeGesture = Gesture.EDGELEFT;
  89. } else {
  90. return;
  91. }
  92. Menu nextMenu = null;
  93. MenuItem item = currentMenu.get(gesture);
  94. if (item.action.equalsIgnoreCase("MENU")) {
  95. nextMenu = get(item.data);
  96. }
  97. Menu newMenu = new Menu(menuName);
  98. put(id, newMenu);
  99. newMenu.setID(id);
  100. MenuItem link = new MenuItem(menuName, "MENU", id, null);
  101. MenuItem homeLink = new MenuItem(currentMenu.getName(), "MENU", currentMenu.getID(), null);
  102. currentMenu.put(gesture, link);
  103. newMenu.put(oppositeGesture, homeLink);
  104. if (nextMenu != null) {
  105. MenuItem nextLink = new MenuItem(nextMenu.getName(), "MENU", nextMenu.getID(), null);
  106. newMenu.put(gesture, nextLink);
  107. nextMenu.put(oppositeGesture, link);
  108. }
  109. }
  110. /**
  111. * Load a set of menus from an XML file.
  112. */
  113. public static MenuManager loadMenus(Context context, String filename) {
  114. MenuManager manager = new MenuManager();
  115. try {
  116. FileInputStream fis = new FileInputStream(filename);
  117. manager = loadMenus(context, fis);
  118. } catch (Exception e) {
  119. e.printStackTrace();
  120. }
  121. return manager;
  122. }
  123. /**
  124. * Load a set of menus from an XML input stream.
  125. */
  126. public static MenuManager loadMenus(Context context, InputStream is) {
  127. HashMap<String, Menu> shortcutMenus = new HashMap<String, Menu>();
  128. try {
  129. DocumentBuilder docBuild = DocumentBuilderFactory.newInstance().newDocumentBuilder();
  130. Document doc = docBuild.parse(is);
  131. String versionNumber;
  132. NodeList versionNodes = doc.getElementsByTagName("version");
  133. if (versionNodes.getLength() == 0) {
  134. versionNumber = "0.0";
  135. } else {
  136. Node versionNumberNode = versionNodes.item(0).getAttributes().getNamedItem(
  137. "number");
  138. if (versionNumberNode == null) {
  139. versionNumber = "0.0";
  140. } else {
  141. versionNumber = versionNumberNode.getNodeValue();
  142. }
  143. }
  144. if (versionNumber.equalsIgnoreCase("0.0")) {
  145. // Load new default and wipe over one screen with old shortcuts
  146. Resources res = context.getResources();
  147. InputStream defaultIs = res.openRawResource(R.raw.default_shortcuts);
  148. shortcutMenus = loadMenus(context, defaultIs);
  149. NodeList items = doc.getElementsByTagName("item");
  150. shortcutMenus.get("Shortcuts Left").putAll(readItems(context, items));
  151. } else {
  152. // Load everything normally
  153. NodeList menus = doc.getElementsByTagName("menu");
  154. for (int i = 0; i < menus.getLength(); i++) {
  155. NamedNodeMap attribs = menus.item(i).getAttributes();
  156. String label = attribs.getNamedItem("label").getNodeValue();
  157. String wallpaper = "";
  158. Node wallpaperNode = attribs.getNamedItem("wallpaper");
  159. if (wallpaperNode != null) {
  160. wallpaper = wallpaperNode.getNodeValue();
  161. }
  162. Node idAttrNode = attribs.getNamedItem("id");
  163. if (idAttrNode != null) {
  164. String id = idAttrNode.getNodeValue();
  165. Menu menu = new Menu(label,
  166. readItems(context, menus.item(i).getChildNodes()), wallpaper);
  167. menu.setID(id);
  168. shortcutMenus.put(id, menu);
  169. } else {
  170. Menu menu = new Menu(label,
  171. readItems(context, menus.item(i).getChildNodes()), wallpaper);
  172. shortcutMenus.put(label, menu);
  173. }
  174. }
  175. }
  176. } catch (Exception e) {
  177. e.printStackTrace();
  178. }
  179. MenuManager manager = new MenuManager();
  180. manager.putAll(shortcutMenus);
  181. return manager;
  182. }
  183. /**
  184. * Loads menu items from a list of XML nodes containing menu items.
  185. */
  186. public static HashMap<Integer, MenuItem> readItems(Context context, NodeList itemNodes) {
  187. HashMap<Integer, MenuItem> menu = new HashMap<Integer, MenuItem>();
  188. for (int i = 0; i < itemNodes.getLength(); i++) {
  189. if (itemNodes.item(i).getNodeName().equalsIgnoreCase("item")) {
  190. NamedNodeMap attribs = itemNodes.item(i).getAttributes();
  191. int g = Integer.parseInt(attribs.getNamedItem("gesture").getNodeValue());
  192. String label = attribs.getNamedItem("label").getNodeValue();
  193. String action = attribs.getNamedItem("action").getNodeValue();
  194. String data = null;
  195. Node dataAttrNode = attribs.getNamedItem("data");
  196. if (dataAttrNode != null) {
  197. data = dataAttrNode.getNodeValue();
  198. }
  199. AppInfo appInfo = null;
  200. if (action.equalsIgnoreCase("launch")) {
  201. Node appInfoNode = null;
  202. NodeList nodes = itemNodes.item(i).getChildNodes();
  203. for (int j = 0; j < nodes.getLength(); j++) {
  204. Node currentNode = nodes.item(j);
  205. String tagName = currentNode.getNodeName();
  206. // Only process actual nodes
  207. if (tagName != null) {
  208. if (tagName.equalsIgnoreCase("appInfo")) {
  209. appInfoNode = currentNode;
  210. }
  211. }
  212. }
  213. NamedNodeMap appInfoAttr = appInfoNode.getAttributes();
  214. String packageName = "";
  215. Node packageAttrNode = appInfoAttr.getNamedItem("package");
  216. if (packageAttrNode != null) {
  217. packageName = packageAttrNode.getNodeValue();
  218. }
  219. String className = "";
  220. Node classAttrNode = appInfoAttr.getNamedItem("class");
  221. if (classAttrNode != null) {
  222. className = classAttrNode.getNodeValue();
  223. }
  224. appInfo = new AppInfo(null, packageName, className);
  225. // Check to see if the package is still installed
  226. if (packageExists(context, appInfo)) {
  227. menu.put(g, new MenuItem(label, action, data, appInfo));
  228. }
  229. } else {
  230. menu.put(g, new MenuItem(label, action, data, appInfo));
  231. }
  232. }
  233. }
  234. return menu;
  235. }
  236. /**
  237. * Check to see if application is installed.
  238. */
  239. private static boolean packageExists(Context context, AppInfo application) {
  240. PackageManager manager = context.getPackageManager();
  241. try {
  242. manager.getApplicationInfo(application.getPackageName(), 0);
  243. return true;
  244. } catch (PackageManager.NameNotFoundException e) {
  245. return false;
  246. }
  247. }
  248. /**
  249. * Escape entities in text for XML.
  250. */
  251. public static String escapeEntities(String string) {
  252. return string.replaceAll("\"", "&quot;").replaceAll("<", "&lt;").replaceAll(">", "&gt;")
  253. .replaceAll("'", "&apos;").replaceAll("&", "&amp;");
  254. }
  255. }