Home | History | Annotate | Download | only in tree
      1 /*
      2  * Copyright (C) 2012 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of 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,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.uiautomator.tree;
     18 
     19 import org.eclipse.swt.graphics.Rectangle;
     20 import org.xml.sax.Attributes;
     21 import org.xml.sax.SAXException;
     22 import org.xml.sax.helpers.DefaultHandler;
     23 
     24 import java.io.File;
     25 import java.io.IOException;
     26 import java.util.ArrayList;
     27 import java.util.Collections;
     28 import java.util.List;
     29 
     30 import javax.xml.parsers.ParserConfigurationException;
     31 import javax.xml.parsers.SAXParser;
     32 import javax.xml.parsers.SAXParserFactory;
     33 
     34 public class UiHierarchyXmlLoader {
     35 
     36     private BasicTreeNode mRootNode;
     37     private List<Rectangle> mNafNodes;
     38 
     39     public UiHierarchyXmlLoader() {
     40     }
     41 
     42     /**
     43      * Uses a SAX parser to process XML dump
     44      * @param xmlPath
     45      * @return
     46      */
     47     public BasicTreeNode parseXml(String xmlPath) {
     48         mRootNode = null;
     49         mNafNodes = new ArrayList<Rectangle>();
     50         // standard boilerplate to get a SAX parser
     51         SAXParserFactory factory = SAXParserFactory.newInstance();
     52         SAXParser parser = null;
     53         try {
     54             parser = factory.newSAXParser();
     55         } catch (ParserConfigurationException e) {
     56             e.printStackTrace();
     57             return null;
     58         } catch (SAXException e) {
     59             e.printStackTrace();
     60             return null;
     61         }
     62         // handler class for SAX parser to receiver standard parsing events:
     63         // e.g. on reading "<foo>", startElement is called, on reading "</foo>",
     64         // endElement is called
     65         DefaultHandler handler = new DefaultHandler(){
     66             BasicTreeNode mParentNode;
     67             BasicTreeNode mWorkingNode;
     68             @Override
     69             public void startElement(String uri, String localName, String qName,
     70                     Attributes attributes) throws SAXException {
     71                 boolean nodeCreated = false;
     72                 // starting an element implies that the element that has not yet been closed
     73                 // will be the parent of the element that is being started here
     74                 mParentNode = mWorkingNode;
     75                 if ("hierarchy".equals(qName)) {
     76                     mWorkingNode = new RootWindowNode(attributes.getValue("windowName"));
     77                     nodeCreated = true;
     78                 } else if ("node".equals(qName)) {
     79                     UiNode tmpNode = new UiNode();
     80                     for (int i = 0; i < attributes.getLength(); i++) {
     81                         tmpNode.addAtrribute(attributes.getQName(i), attributes.getValue(i));
     82                     }
     83                     mWorkingNode = tmpNode;
     84                     nodeCreated = true;
     85                     // check if current node is NAF
     86                     String naf = tmpNode.getAttribute("NAF");
     87                     if ("true".equals(naf)) {
     88                         mNafNodes.add(new Rectangle(tmpNode.x, tmpNode.y,
     89                                 tmpNode.width, tmpNode.height));
     90                     }
     91                 }
     92                 // nodeCreated will be false if the element started is neither
     93                 // "hierarchy" nor "node"
     94                 if (nodeCreated) {
     95                     if (mRootNode == null) {
     96                         // this will only happen once
     97                         mRootNode = mWorkingNode;
     98                     }
     99                     if (mParentNode != null) {
    100                         mParentNode.addChild(mWorkingNode);
    101                     }
    102                 }
    103             }
    104 
    105             @Override
    106             public void endElement(String uri, String localName, String qName) throws SAXException {
    107                 //mParentNode should never be null here in a well formed XML
    108                 if (mParentNode != null) {
    109                     // closing an element implies that we are back to working on
    110                     // the parent node of the element just closed, i.e. continue to
    111                     // parse more child nodes
    112                     mWorkingNode = mParentNode;
    113                     mParentNode = mParentNode.getParent();
    114                 }
    115             }
    116         };
    117         try {
    118             parser.parse(new File(xmlPath), handler);
    119         } catch (SAXException e) {
    120             e.printStackTrace();
    121             return null;
    122         } catch (IOException e) {
    123             e.printStackTrace();
    124             return null;
    125         }
    126         return mRootNode;
    127     }
    128 
    129     /**
    130      * Returns the list of "Not Accessibility Friendly" nodes found during parsing.
    131      *
    132      * Call this function after parsing
    133      *
    134      * @return
    135      */
    136     public List<Rectangle> getNafNodes() {
    137         return Collections.unmodifiableList(mNafNodes);
    138     }
    139 }
    140