package com.android.testing.uiautomation; import org.xmlpull.v1.XmlSerializer; import android.graphics.Rect; import android.os.Environment; import android.os.SystemClock; import android.util.Log; import android.util.Xml; import android.view.accessibility.AccessibilityNodeInfo; import java.io.File; import java.io.FileWriter; import java.io.IOException; import java.io.StringWriter; import java.util.LinkedList; import java.util.Queue; public class AccessibilityNodeInfoHelper { private static final String LOGTAG = "AccessibilityNodeInfoHelper"; public static void dumpWindowToFile(AccessibilityNodeInfo info) { AccessibilityNodeInfo root = getRootAccessibilityNodeInfo(info); if (root == null) { return; } final long startTime = SystemClock.uptimeMillis(); try { File baseDir = new File(Environment.getDataDirectory(), "uidump"); if (!baseDir.exists()) { baseDir.mkdir(); baseDir.setExecutable(true, false); baseDir.setWritable(true, false); baseDir.setReadable(true, false); } FileWriter writer = new FileWriter( new File(baseDir, "window_dump.xml")); XmlSerializer serializer = Xml.newSerializer(); StringWriter stringWriter = new StringWriter(); serializer.setOutput(stringWriter); serializer.startDocument("UTF-8", true); serializer.startTag("", "hierarchy"); dumpNodeRec(root, serializer, 0); if (root != info) root.recycle(); serializer.endTag("", "hierarchy"); serializer.endDocument(); writer.write(stringWriter.toString()); writer.close(); } catch (IOException e) { Log.e(LOGTAG, "failed to dump window to file", e); } final long endTime = SystemClock.uptimeMillis(); Log.w(LOGTAG, "Fetch time: " + (endTime - startTime) + "ms"); } public static void dumpNodeRec(AccessibilityNodeInfo node, XmlSerializer serializer, int index) throws IOException { serializer.startTag("", "node"); serializer.attribute("", "index", Integer.toString(index)); serializer.attribute("", "text", safeCharSeqToString(node.getText())); serializer.attribute("", "class", safeCharSeqToString(node.getClassName())); serializer.attribute("", "package", safeCharSeqToString(node.getPackageName())); serializer.attribute("", "content-desc", safeCharSeqToString(node.getContentDescription())); serializer.attribute("", "checkable", Boolean.toString(node.isCheckable())); serializer.attribute("", "checked", Boolean.toString(node.isChecked())); serializer.attribute("", "clickable", Boolean.toString(node.isClickable())); serializer.attribute("", "enabled", Boolean.toString(node.isEnabled())); serializer.attribute("", "focusable", Boolean.toString(node.isFocusable())); serializer.attribute("", "focused", Boolean.toString(node.isFocused())); serializer.attribute("", "long-clickable", Boolean.toString(node.isLongClickable())); serializer.attribute("", "password", Boolean.toString(node.isPassword())); serializer.attribute("", "selected", Boolean.toString(node.isSelected())); Rect bounds = new Rect(); node.getBoundsInScreen(bounds); serializer.attribute("", "bounds", bounds.toShortString()); for (int i = 0; i < node.getChildCount(); i++) { AccessibilityNodeInfo child = node.getChild(i); if (child != null) { dumpNodeRec(child, serializer, i); child.recycle(); } } serializer.endTag("", "node"); } public static void dumpWindow(AccessibilityNodeInfo info) { AccessibilityNodeInfo root = getRootAccessibilityNodeInfo(info); if (root == null) { return; } final long startTime = SystemClock.uptimeMillis(); Queue mFringe = new LinkedList(); mFringe.add(root); int fetchedNodeCount = 0; while (!mFringe.isEmpty()) { AccessibilityNodeInfo current = mFringe.poll(); Log.d(LOGTAG, String.format("class: %s; text: %s; content-desc: %s", current.getClassName(), current.getText(), current.getContentDescription())); fetchedNodeCount++; final int childCount = current.getChildCount(); for (int i = 0; i < childCount; i++) { AccessibilityNodeInfo child = current.getChild(i); if (child != null) { mFringe.add(child); } } } final long endTime = SystemClock.uptimeMillis(); Log.w(LOGTAG, "Fetch time: " + (endTime - startTime) + "ms; fetchedNodeCount: " + fetchedNodeCount); } public static void dumpNode(AccessibilityNodeInfo node) { Log.d(LOGTAG, String.format("class: %s; text: %s; content-desc: %s", node.getClassName(), node.getText(), node.getContentDescription())); } public static void dumpChildren(AccessibilityNodeInfo node) { int count = node.getChildCount(); for (int i = 0; i < count; i++) { AccessibilityNodeInfo child = node.getChild(i); dumpNode(child); child.recycle(); } } public static AccessibilityNodeInfo getRootAccessibilityNodeInfo(AccessibilityNodeInfo info) { if (info == null) return null; AccessibilityNodeInfo root = info.getParent(); while (root != null) { AccessibilityNodeInfo parent = root.getParent(); if (parent != null) { root.recycle(); root = parent; } else { break; } } return root == null ? info : root; } public static String safeCharSeqToString(CharSequence cs) { if (cs == null) return "[null]"; else return cs.toString(); } }