Java tutorial
/* * Copyright 2015 - 2016 Nebula Bay. * * 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.tascape.qa.th.android.model; import com.android.uiautomator.stub.Rect; import com.tascape.qa.th.android.driver.UiAutomatorDevice; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.util.regex.Matcher; import java.util.regex.Pattern; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import org.apache.commons.io.FileUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.xml.sax.SAXException; /** * * @author linsong wang */ public class UIA { private static final Logger LOG = LoggerFactory.getLogger(UIA.class); public static WindowHierarchy parseHierarchy(File file, UiAutomatorDevice device) throws IOException, SAXException, ParserConfigurationException { try (InputStream in = FileUtils.openInputStream(file)) { return parseHierarchy(in, device); } } public static WindowHierarchy parseHierarchy(InputStream in, UiAutomatorDevice device) throws SAXException, ParserConfigurationException, IOException { DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); DocumentBuilder builder = factory.newDocumentBuilder(); Document document = builder.parse(in); Element doc = document.getDocumentElement(); NodeList nl = doc.getChildNodes(); for (int i = 0; i < nl.getLength(); i++) { Node node = nl.item(i); UIANode uiNode = parseNode(node); if (uiNode != null) { WindowHierarchy hierarchy = new WindowHierarchy(uiNode); hierarchy.setRotation(doc.getAttribute("rotation")); LOG.debug("{}", hierarchy); hierarchy.setUiAutomatorDevice(device); return hierarchy; } } throw new UIAException("Cannot parse view hierarchy"); } public static UIANode parseNode(Node node) { if (!node.getNodeName().equals(UIANode.TAG_NAME)) { return null; } NamedNodeMap map = node.getAttributes(); String klass = map.getNamedItem("class").getNodeValue(); UIANode uiNode = newNode(klass); for (int i = 0, j = map.getLength(); i < j; i++) { Node attr = map.item(i); uiNode.setAttribute(attr.getNodeName(), attr.getNodeValue()); } NodeList nl = node.getChildNodes(); for (int i = 0; i < nl.getLength(); i++) { UIANode n = parseNode(nl.item(i)); if (n == null) { continue; } uiNode.addNode(n); } return uiNode; } private static UIANode newNode(String klass) { switch (klass) { case ActionMenuView.CLASS_ANME: return new ActionMenuView(); case AutoCompleteTextView.CLASS_ANME: return new AutoCompleteTextView(); case Button.CLASS_ANME: return new Button(); case CalendarView.CLASS_ANME: return new CalendarView(); case CheckBox.CLASS_ANME: return new CheckBox(); case Chronometer.CLASS_ANME: return new Chronometer(); case CompoundButton.CLASS_ANME: return new CompoundButton(); case DatePicker.CLASS_ANME: return new DatePicker(); case EditText.CLASS_ANME: return new EditText(); case FrameLayout.CLASS_ANME: return new FrameLayout(); case GridLayout.CLASS_ANME: return new GridLayout(); case GridView.CLASS_ANME: return new GridView(); case HorizontalScrollView.CLASS_ANME: return new HorizontalScrollView(); case ImageButton.CLASS_ANME: return new ImageButton(); case ImageView.CLASS_ANME: return new ImageView(); case LinearLayout.CLASS_ANME: return new LinearLayout(); case ListView.CLASS_ANME: return new ListView(); case NumberPicker.CLASS_ANME: return new NumberPicker(); case OverScroller.CLASS_ANME: return new OverScroller(); case PopupMenu.CLASS_ANME: return new PopupMenu(); case PopupWindow.CLASS_ANME: return new PopupWindow(); case ProgressBar.CLASS_ANME: return new ProgressBar(); case QuickContactBadge.CLASS_ANME: return new QuickContactBadge(); case RadioButton.CLASS_ANME: return new RadioButton(); case RadioGroup.CLASS_ANME: return new RadioGroup(); case RatingBar.CLASS_ANME: return new RatingBar(); case RecyclerView.CLASS_ANME: return new RecyclerView(); case RelativeLayout.CLASS_ANME: return new RelativeLayout(); case RemoteViews.CLASS_ANME: return new RemoteViews(); case ScrollView.CLASS_ANME: return new ScrollView(); case Scroller.CLASS_ANME: return new Scroller(); case SearchView.CLASS_ANME: return new SearchView(); case SeekBar.CLASS_ANME: return new SeekBar(); case Space.CLASS_ANME: return new Space(); case Spinner.CLASS_ANME: return new Spinner(); case Switch.CLASS_ANME: return new Switch(); case TabHost.CLASS_ANME: return new TabHost(); case TabWidget.CLASS_ANME: return new TabWidget(); case TableLayout.CLASS_ANME: return new TableLayout(); case TableRow.CLASS_ANME: return new TableRow(); case TextClock.CLASS_ANME: return new TextClock(); case TextSwitcher.CLASS_ANME: return new TextSwitcher(); case TextView.CLASS_ANME: return new TextView(); case TimePicker.CLASS_ANME: return new TimePicker(); case Toast.CLASS_ANME: return new Toast(); case ToggleButton.CLASS_ANME: return new ToggleButton(); case Toolbar.CLASS_ANME: return new Toolbar(); case VideoView.CLASS_ANME: return new VideoView(); case View.CLASS_ANME: return new View(); case ViewAnimator.CLASS_ANME: return new ViewAnimator(); case ViewFlipper.CLASS_ANME: return new ViewFlipper(); case ViewGroup.CLASS_ANME: return new ViewGroup(); case ViewPager.CLASS_ANME: return new ViewPager(); case ViewSwitcher.CLASS_ANME: return new ViewSwitcher(); case ZoomControls.CLASS_ANME: return new ZoomControls(); default: LOG.trace("Unkown node type {}, use " + UIANode.class.getSimpleName(), klass); return new UIANode(); } } public static Rect parseBounds(String bounds) { Pattern pattern = Pattern.compile("\\[(\\d+?),(\\d+?)\\]\\[(\\d+?),(\\d+?)\\]"); Matcher matcher = pattern.matcher(bounds); if (matcher.matches()) { Rect rect = new Rect(); rect.left = Integer.parseInt(matcher.group(1)); rect.top = Integer.parseInt(matcher.group(2)); rect.right = Integer.parseInt(matcher.group(3)); rect.bottom = Integer.parseInt(matcher.group(4)); return rect; } throw new UIAException("Cannot parse bounds " + bounds); } public static void main(String[] args) throws Exception { Rect r = UIA.parseBounds("[0,0][1080,1812]"); LOG.debug("{}", r); InputStream in = UIA.class.getResourceAsStream("hierarchy.xml"); LOG.debug("{}", in); WindowHierarchy hierarchy = parseHierarchy(in, null); LOG.debug("{}", hierarchy.toString()); LOG.debug("\n{}", hierarchy.toJson().toString(2)); } }