| /* |
| * 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 org.eclipse.swt.graphics.Rectangle; |
| 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) { |
| e.printStackTrace(); |
| return null; |
| } catch (SAXException e) { |
| e.printStackTrace(); |
| 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)) { |
| mWorkingNode = new RootWindowNode(attributes.getValue("windowName")); |
| 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) { |
| e.printStackTrace(); |
| return null; |
| } catch (IOException e) { |
| e.printStackTrace(); |
| 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); |
| } |
| } |