1 package com.android.testing.uiautomation; 2 3 import org.xmlpull.v1.XmlSerializer; 4 5 import android.graphics.Rect; 6 import android.os.Environment; 7 import android.os.SystemClock; 8 import android.util.Log; 9 import android.util.Xml; 10 import android.view.accessibility.AccessibilityNodeInfo; 11 12 import java.io.File; 13 import java.io.FileWriter; 14 import java.io.IOException; 15 import java.io.StringWriter; 16 import java.util.LinkedList; 17 import java.util.Queue; 18 19 public class AccessibilityNodeInfoHelper { 20 21 private static final String LOGTAG = "AccessibilityNodeInfoHelper"; 22 23 public static void dumpWindowToFile(AccessibilityNodeInfo info) { 24 AccessibilityNodeInfo root = getRootAccessibilityNodeInfo(info); 25 if (root == null) { 26 return; 27 } 28 final long startTime = SystemClock.uptimeMillis(); 29 try { 30 File baseDir = new File(Environment.getDataDirectory(), "uidump"); 31 if (!baseDir.exists()) { 32 baseDir.mkdir(); 33 baseDir.setExecutable(true, false); 34 baseDir.setWritable(true, false); 35 baseDir.setReadable(true, false); 36 } 37 FileWriter writer = new FileWriter( 38 new File(baseDir, "window_dump.xml")); 39 XmlSerializer serializer = Xml.newSerializer(); 40 StringWriter stringWriter = new StringWriter(); 41 serializer.setOutput(stringWriter); 42 serializer.startDocument("UTF-8", true); 43 serializer.startTag("", "hierarchy"); 44 dumpNodeRec(root, serializer, 0); 45 if (root != info) 46 root.recycle(); 47 serializer.endTag("", "hierarchy"); 48 serializer.endDocument(); 49 writer.write(stringWriter.toString()); 50 writer.close(); 51 } catch (IOException e) { 52 Log.e(LOGTAG, "failed to dump window to file", e); 53 } 54 final long endTime = SystemClock.uptimeMillis(); 55 Log.w(LOGTAG, "Fetch time: " + (endTime - startTime) + "ms"); 56 } 57 58 public static void dumpNodeRec(AccessibilityNodeInfo node, XmlSerializer serializer, int index) 59 throws IOException { 60 serializer.startTag("", "node"); 61 serializer.attribute("", "index", Integer.toString(index)); 62 serializer.attribute("", "text", safeCharSeqToString(node.getText())); 63 serializer.attribute("", "class", safeCharSeqToString(node.getClassName())); 64 serializer.attribute("", "package", safeCharSeqToString(node.getPackageName())); 65 serializer.attribute("", "content-desc", safeCharSeqToString(node.getContentDescription())); 66 serializer.attribute("", "checkable", Boolean.toString(node.isCheckable())); 67 serializer.attribute("", "checked", Boolean.toString(node.isChecked())); 68 serializer.attribute("", "clickable", Boolean.toString(node.isClickable())); 69 serializer.attribute("", "enabled", Boolean.toString(node.isEnabled())); 70 serializer.attribute("", "focusable", Boolean.toString(node.isFocusable())); 71 serializer.attribute("", "focused", Boolean.toString(node.isFocused())); 72 serializer.attribute("", "long-clickable", Boolean.toString(node.isLongClickable())); 73 serializer.attribute("", "password", Boolean.toString(node.isPassword())); 74 serializer.attribute("", "selected", Boolean.toString(node.isSelected())); 75 Rect bounds = new Rect(); 76 node.getBoundsInScreen(bounds); 77 serializer.attribute("", "bounds", bounds.toShortString()); 78 for (int i = 0; i < node.getChildCount(); i++) { 79 AccessibilityNodeInfo child = node.getChild(i); 80 if (child != null) { 81 dumpNodeRec(child, serializer, i); 82 child.recycle(); 83 } 84 } 85 serializer.endTag("", "node"); 86 } 87 88 public static void dumpWindow(AccessibilityNodeInfo info) { 89 AccessibilityNodeInfo root = getRootAccessibilityNodeInfo(info); 90 if (root == null) { 91 return; 92 } 93 final long startTime = SystemClock.uptimeMillis(); 94 Queue<AccessibilityNodeInfo> mFringe = new LinkedList<AccessibilityNodeInfo>(); 95 mFringe.add(root); 96 int fetchedNodeCount = 0; 97 while (!mFringe.isEmpty()) { 98 AccessibilityNodeInfo current = mFringe.poll(); 99 Log.d(LOGTAG, String.format("class: %s; text: %s; content-desc: %s", 100 current.getClassName(), 101 current.getText(), 102 current.getContentDescription())); 103 fetchedNodeCount++; 104 final int childCount = current.getChildCount(); 105 for (int i = 0; i < childCount; i++) { 106 AccessibilityNodeInfo child = current.getChild(i); 107 if (child != null) { 108 mFringe.add(child); 109 } 110 } 111 } 112 final long endTime = SystemClock.uptimeMillis(); 113 Log.w(LOGTAG, "Fetch time: " + (endTime - startTime) + "ms; fetchedNodeCount: " 114 + fetchedNodeCount); 115 } 116 117 public static void dumpNode(AccessibilityNodeInfo node) { 118 Log.d(LOGTAG, String.format("class: %s; text: %s; content-desc: %s", 119 node.getClassName(), 120 node.getText(), 121 node.getContentDescription())); 122 } 123 124 public static void dumpChildren(AccessibilityNodeInfo node) { 125 int count = node.getChildCount(); 126 for (int i = 0; i < count; i++) { 127 AccessibilityNodeInfo child = node.getChild(i); 128 dumpNode(child); 129 child.recycle(); 130 } 131 } 132 133 public static AccessibilityNodeInfo getRootAccessibilityNodeInfo(AccessibilityNodeInfo info) { 134 if (info == null) 135 return null; 136 AccessibilityNodeInfo root = info.getParent(); 137 while (root != null) { 138 AccessibilityNodeInfo parent = root.getParent(); 139 if (parent != null) { 140 root.recycle(); 141 root = parent; 142 } else { 143 break; 144 } 145 } 146 return root == null ? info : root; 147 } 148 149 public static String safeCharSeqToString(CharSequence cs) { 150 if (cs == null) 151 return "[null]"; 152 else 153 return cs.toString(); 154 } 155 } 156