//throw new RuntimeException("Unhandled menu tag " + guiName);
private void readMenu(String file, AndroidView root, boolean isSys) {
    Document doc;
    try {
      DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
      dbFactory.setNamespaceAware(true);
      DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
      doc = dBuilder.parse(file);
    } catch (Exception ex) {
      throw new RuntimeException(ex);
    }
    LinkedList<Pair<Node, AndroidView>> worklist = Lists.newLinkedList();
    worklist.add(new Pair<Node, AndroidView>(doc.getDocumentElement(), root));
    root = null;
    while (!worklist.isEmpty()) {
      Pair<Node, AndroidView> pair = worklist.remove();
      Node node = pair.getO1();
      AndroidView view = pair.getO2();
      NamedNodeMap attrMap = node.getAttributes();
      Node idNode = attrMap.getNamedItemNS(ANDROID_NS, "id");
      int guiId = -1;
      String id = null;
      if (idNode != null) {
        String txt = idNode.getTextContent();
        Pair<String, Integer> p = parseAndroidId(txt, isSys);
        id = p.getO1();
        Integer guiIdObj = p.getO2();
        if (guiIdObj == null) {
          if (!isSys) {
            Logger.warn(this.getClass().getSimpleName(),
                    "unresolved android:id " + id + " in "
                    + file);
          }
          guiId = nonRId--; // negative value to indicate it is a unique id but
          // we don't know its value
          feedIdIntoGeneralMap("id", id, guiId, isSys);
//          if (isSys) {
//            sysRIdMap.put(id, guiId);
//            invSysRIdMap.put(guiId, id);
//          } else {
//            rIdMap.put(id, guiId);
//            invRIdMap.put(guiId, id);
//          }
        } else {
          guiId = guiIdObj.intValue();
        }
      }
      // FIXME(tony): this is an "approximation"
      String guiName = node.getNodeName();
      if (guiName.equals("menu")) {
        guiName = "android.view.Menu";
      } else if (guiName.equals("item")) {
        guiName = "android.view.MenuItem";
        NodeList childNodes = node.getChildNodes();
        if(childNodes!=null) {
          for (int i = 0; i < childNodes.getLength(); i++) {
            Node newNode = childNodes.item(i);
            String nodeName = newNode.getNodeName();
            if("menu".equals(nodeName)) {
              guiName = "android.view.ViewGroup";
            }
          }
        }
      } else if (guiName.equals("group")) {
        // TODO(tony): we might want to create a special fake class to
        // represent menu groups. But for now, let's simply pretend it's
        // a ViewGroup. Also, print a warning when we do see <group>
        Logger.trace(this.getClass().getSimpleName(), "[TODO] <group> used in " + file);
        guiName = "android.view.ViewGroup";
      } else {
        Logger.trace("XML", "Unhandled menu tag " + guiName);
        //throw new RuntimeException("Unhandled menu tag " + guiName);
      }
      if (debug) {
        Logger.verb(this.getClass().getSimpleName(), guiName + " (" + guiId + ", " + id + ")");
      }
      String text = readAndroidTextOrTitle(attrMap, "title");
      // hailong: add hint support
      String hint = readAndroidTextOrTitle(attrMap, "hint");
      String autofillHints = readAndroidTextOrTitle(attrMap, "autofillHints");
      if (hint != null && autofillHints != null) hint += PropertyManager.SEPARATOR + autofillHints;
      else if (autofillHints != null) hint = autofillHints;
      String tooltip = readAndroidTextOrTitle(attrMap, "tooltipText");
      String contentDescription = readAndroidTextOrTitle(attrMap, "contentDescription");
      if (hint != null && autofillHints != null) hint += PropertyManager.SEPARATOR + autofillHints;
      else if (autofillHints != null) hint = autofillHints;
      String images = readAndroidImageResource(attrMap);
      view.save(guiId, text, hint, tooltip, contentDescription, images, guiName);
      //view.save(guiId, text, hint, guiName);
      NodeList children = node.getChildNodes();
      for (int i = 0; i < children.getLength(); i++) {
        Node newNode = children.item(i);
        String nodeName = newNode.getNodeName();
        if ("#comment".equals(nodeName)) {
          continue;
        }
        if ("#text".equals(nodeName)) {
          // possible for XML files created on a different operating system
          // than the one our analysis is run on
          continue;
        }
        AndroidView newView = new AndroidView();
        // FIXME: we assume that every node has attributes, may be wrong
        if (!newNode.hasAttributes()) {
          Logger.verb("WARNING", "xml node " + newNode + " has no attributes");
          // continue;
        } else {
          NamedNodeMap attrs = newNode.getAttributes();
          for (int idx = 0; idx < attrs.getLength(); idx += 1) {
            Node attr = attrs.item(idx);
            String name = attr.getNodeName();
            String value = attr.getNodeValue();
            newView.addAttr(name, value);
          }
        }
        newView.setParent(view);
        worklist.add(new Pair<Node, AndroidView>(newNode, newView));
      }
    }
  }
} else {
Logger.trace("XML", "Unhandled menu tag " + guiName);
//throw new RuntimeException("Unhandled menu tag " + guiName);
}
if (debug) {
}
}
} else if (guiName.equals("group")) {
// TODO(tony): we might want to create a special fake class to
// represent menu groups. But for now, let's simply pretend it's
// a ViewGroup. Also, print a warning when we do see <group>
Logger.trace(this.getClass().getSimpleName(), "[TODO] <group> used in " + file);
guiName = "android.view.ViewGroup";
} else {
Logger.trace("XML", "Unhandled menu tag " + guiName);
//throw new RuntimeException("Unhandled menu tag " + guiName);
}
if (debug) {
Logger.verb(this.getClass().getSimpleName(), guiName + " (" + guiId + ", " + id + ")");
}
String text = readAndroidTextOrTitle(attrMap, "title");
// hailong: add hint support
String hint = readAndroidTextOrTitle(attrMap, "hint");
String autofillHints = readAndroidTextOrTitle(attrMap, "autofillHints");
if (hint != null && autofillHints != null) hint += PropertyManager.SEPARATOR + autofillHints;
else if (autofillHints != null) hint = autofillHints;
} else if (guiName.equals("item")) {
guiName = "android.view.MenuItem";
NodeList childNodes = node.getChildNodes();
if(childNodes!=null) {
for (int i = 0; i < childNodes.getLength(); i++) {
Node newNode = childNodes.item(i);
String nodeName = newNode.getNodeName();
if("menu".equals(nodeName)) {
guiName = "android.view.ViewGroup";
}
}
}
} else if (guiName.equals("group")) {
// TODO(tony): we might want to create a special fake class to
// represent menu groups. But for now, let's simply pretend it's
// a ViewGroup. Also, print a warning when we do see <group>
Logger.trace(this.getClass().getSimpleName(), "[TODO] <group> used in " + file);
guiName = "android.view.ViewGroup";
} else {
Logger.trace("XML", "Unhandled menu tag " + guiName);
//throw new RuntimeException("Unhandled menu tag " + guiName);
}
if (debug) {
Logger.verb(this.getClass().getSimpleName(), guiName + " (" + guiId + ", " + id + ")");
}
String text = readAndroidTextOrTitle(attrMap, "title");
// hailong: add hint support
String hint = readAndroidTextOrTitle(attrMap, "hint");
String autofillHints = readAndroidTextOrTitle(attrMap, "autofillHints");
if (hint != null && autofillHints != null) hint += PropertyManager.SEPARATOR + autofillHints;
else if (autofillHints != null) hint = autofillHints;
String tooltip = readAndroidTextOrTitle(attrMap, "tooltipText");
String contentDescription = readAndroidTextOrTitle(attrMap, "contentDescription");
if (hint != null && autofillHints != null) hint += PropertyManager.SEPARATOR + autofillHints;
else if (autofillHints != null) hint = autofillHints;
String images = readAndroidImageResource(attrMap);
view.save(guiId, text, hint, tooltip, contentDescription, images, guiName);
//view.save(guiId, text, hint, guiName);
NodeList children = node.getChildNodes();
for (int i = 0; i < children.getLength(); i++) {
Node newNode = children.item(i);