/* * Copyright (C) 2012 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.uiautomator.tree; import java.awt.Rectangle; import org.apache.log4j.Logger; import org.xml.sax.Attributes; import org.xml.sax.SAXException; import org.xml.sax.helpers.DefaultHandler; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.Collections; import java.util.List; import javax.xml.parsers.ParserConfigurationException; import javax.xml.parsers.SAXParser; import javax.xml.parsers.SAXParserFactory; public class UiHierarchyXmlLoader { private BasicTreeNode mRootNode; private List<Rectangle> mNafNodes; public UiHierarchyXmlLoader() { } /** * Uses a SAX parser to process XML dump * @param xmlPath * @return */ public BasicTreeNode parseXml(String xmlPath) { mRootNode = null; mNafNodes = new ArrayList<Rectangle>(); // standard boilerplate to get a SAX parser SAXParserFactory factory = SAXParserFactory.newInstance(); SAXParser parser = null; try { parser = factory.newSAXParser(); } catch (ParserConfigurationException e) { Logger.getLogger(this.getClass() ).debug("/****UiHierarchyXmlLoader.Error while parsing XML file***/ "+ e.getMessage()); return null; } catch (SAXException e) { Logger.getLogger(this.getClass() ).debug("/****UiHierarchyXmlLoader.Error while parsing XML file***/ "+ e.getMessage()); return null; } // handler class for SAX parser to receiver standard parsing events: // e.g. on reading "<foo>", startElement is called, on reading "</foo>", // endElement is called DefaultHandler handler = new DefaultHandler(){ BasicTreeNode mParentNode; BasicTreeNode mWorkingNode; @Override public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { boolean nodeCreated = false; // starting an element implies that the element that has not yet been closed // will be the parent of the element that is being started here mParentNode = mWorkingNode; if ("hierarchy".equals(qName)) { int rotation = 0; for (int i = 0; i < attributes.getLength(); i++) { if ("rotation".equals(attributes.getQName(i))) try { rotation = Integer.parseInt(attributes.getValue(i)); } catch (NumberFormatException nfe) { Logger.getLogger(this.getClass() ).debug("/****UiHierarchyXmlLoader.Error while parsing XML file***/ "+ nfe.getMessage()); } } this.mWorkingNode = new RootWindowNode(attributes.getValue("windowName"), rotation); nodeCreated = true; } else if ("node".equals(qName)) { UiNode tmpNode = new UiNode(); for (int i = 0; i < attributes.getLength(); i++) { tmpNode.addAtrribute(attributes.getQName(i), attributes.getValue(i)); } mWorkingNode = tmpNode; nodeCreated = true; // check if current node is NAF String naf = tmpNode.getAttribute("NAF"); if ("true".equals(naf)) { mNafNodes.add(new Rectangle(tmpNode.x, tmpNode.y, tmpNode.width, tmpNode.height)); } } // nodeCreated will be false if the element started is neither // "hierarchy" nor "node" if (nodeCreated) { if (mRootNode == null) { // this will only happen once mRootNode = mWorkingNode; } if (mParentNode != null) { mParentNode.addChild(mWorkingNode); } } } @Override public void endElement(String uri, String localName, String qName) throws SAXException { //mParentNode should never be null here in a well formed XML if (mParentNode != null) { // closing an element implies that we are back to working on // the parent node of the element just closed, i.e. continue to // parse more child nodes mWorkingNode = mParentNode; mParentNode = mParentNode.getParent(); } } }; try { parser.parse(new File(xmlPath), handler); } catch (SAXException e) { Logger.getLogger(this.getClass() ).debug("/****UiHierarchyXmlLoader.Error while parsing XML file***/ "+ e.getMessage()); return null; } catch (IOException e) { Logger.getLogger(this.getClass() ).debug("/****UiHierarchyXmlLoader.Error while parsing XML file***/ "+ e.getMessage()); return null; } return mRootNode; } /** * Returns the list of "Not Accessibility Friendly" nodes found during parsing. * * Call this function after parsing * * @return */ public List<Rectangle> getNafNodes() { return Collections.unmodifiableList(mNafNodes); } }