Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit bddd2805 authored by Evan Rosky's avatar Evan Rosky Committed by Android (Google) Code Review
Browse files

Merge "Add a window dump for uiautomator" into rvc-dev

parents 5fcae926 89f367d3
Loading
Loading
Loading
Loading
+26 −12
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

package com.android.commands.uiautomator;

import android.accessibilityservice.AccessibilityServiceInfo;
import android.app.UiAutomation;
import android.graphics.Point;
import android.hardware.display.DisplayManagerGlobal;
@@ -61,11 +62,14 @@ public class DumpCommand extends Command {
    public void run(String[] args) {
        File dumpFile = DEFAULT_DUMP_FILE;
        boolean verboseMode = true;
        boolean allWindows = false;

        for (String arg : args) {
            if (arg.equals("--compressed"))
                verboseMode = false;
            else if (!arg.startsWith("-")) {
            else if (arg.equals("--windows")) {
                allWindows = true;
            } else if (!arg.startsWith("-")) {
                dumpFile = new File(arg);
            }
        }
@@ -85,6 +89,14 @@ public class DumpCommand extends Command {
        try {
            UiAutomation uiAutomation = automationWrapper.getUiAutomation();
            uiAutomation.waitForIdle(1000, 1000 * 10);
            if (allWindows) {
                AccessibilityServiceInfo info = uiAutomation.getServiceInfo();
                info.flags |= AccessibilityServiceInfo.FLAG_RETRIEVE_INTERACTIVE_WINDOWS;
                uiAutomation.setServiceInfo(info);
                AccessibilityNodeInfoDumper.dumpWindowsToFile(
                        uiAutomation.getWindowsOnAllDisplays(), dumpFile,
                        DisplayManagerGlobal.getInstance());
            } else {
                AccessibilityNodeInfo info = uiAutomation.getRootInActiveWindow();
                if (info == null) {
                    System.err.println("ERROR: null root node returned by UiTestAutomationBridge.");
@@ -96,7 +108,9 @@ public class DumpCommand extends Command {
                int rotation = display.getRotation();
                Point size = new Point();
                display.getSize(size);
            AccessibilityNodeInfoDumper.dumpWindowToFile(info, dumpFile, rotation, size.x, size.y);
                AccessibilityNodeInfoDumper.dumpWindowToFile(info, dumpFile, rotation, size.x,
                        size.y);
            }
        } catch (TimeoutException re) {
            System.err.println("ERROR: could not get idle state.");
            return;
+96 −0
Original line number Diff line number Diff line
@@ -16,11 +16,17 @@

package com.android.uiautomator.core;

import android.graphics.Point;
import android.graphics.Rect;
import android.hardware.display.DisplayManagerGlobal;
import android.os.Environment;
import android.os.SystemClock;
import android.util.Log;
import android.util.SparseArray;
import android.util.Xml;
import android.view.Display;
import android.view.accessibility.AccessibilityNodeInfo;
import android.view.accessibility.AccessibilityWindowInfo;

import org.xmlpull.v1.XmlSerializer;

@@ -28,6 +34,7 @@ import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.StringWriter;
import java.util.List;

/**
 *
@@ -98,6 +105,95 @@ public class AccessibilityNodeInfoDumper {
        Log.w(LOGTAG, "Fetch time: " + (endTime - startTime) + "ms");
    }

    /**
     * Using {@link AccessibilityWindowInfo} this method will dump some window information and
     * then walk the layout hierarchy of it's
     * and generates an xml dump to the location specified by <code>dumpFile</code>
     * @param allWindows All windows indexed by display-id.
     * @param dumpFile The file to dump to.
     */
    public static void dumpWindowsToFile(SparseArray<List<AccessibilityWindowInfo>> allWindows,
            File dumpFile, DisplayManagerGlobal displayManager) {
        if (allWindows.size() == 0) {
            return;
        }
        final long startTime = SystemClock.uptimeMillis();
        try {
            FileWriter writer = new FileWriter(dumpFile);
            XmlSerializer serializer = Xml.newSerializer();
            StringWriter stringWriter = new StringWriter();
            serializer.setOutput(stringWriter);
            serializer.startDocument("UTF-8", true);
            serializer.startTag("", "displays");
            for (int d = 0, nd = allWindows.size(); d < nd; ++d) {
                int displayId = allWindows.keyAt(d);
                Display display = displayManager.getRealDisplay(displayId);
                if (display == null) {
                    continue;
                }
                final List<AccessibilityWindowInfo> windows = allWindows.valueAt(d);
                if (windows.isEmpty()) {
                    continue;
                }
                serializer.startTag("", "display");
                serializer.attribute("", "id", Integer.toString(displayId));
                int rotation = display.getRotation();
                Point size = new Point();
                display.getSize(size);
                for (int i = 0, n = windows.size(); i < n; ++i) {
                    dumpWindowRec(windows.get(i), serializer, i, size.x, size.y, rotation);
                }
                serializer.endTag("", "display");
            }
            serializer.endTag("", "displays");
            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");
    }

    private static void dumpWindowRec(AccessibilityWindowInfo winfo, XmlSerializer serializer,
            int index, int width, int height, int rotation) throws IOException {
        serializer.startTag("", "window");
        serializer.attribute("", "index", Integer.toString(index));
        final CharSequence title = winfo.getTitle();
        serializer.attribute("", "title", title != null ? title.toString() : "");
        final Rect tmpBounds = new Rect();
        winfo.getBoundsInScreen(tmpBounds);
        serializer.attribute("", "bounds", tmpBounds.toShortString());
        serializer.attribute("", "active", Boolean.toString(winfo.isActive()));
        serializer.attribute("", "focused", Boolean.toString(winfo.isFocused()));
        serializer.attribute("", "accessibility-focused",
                Boolean.toString(winfo.isAccessibilityFocused()));
        serializer.attribute("", "id", Integer.toString(winfo.getId()));
        serializer.attribute("", "layer", Integer.toString(winfo.getLayer()));
        serializer.attribute("", "type", AccessibilityWindowInfo.typeToString(winfo.getType()));
        int count = winfo.getChildCount();
        for (int i = 0; i < count; ++i) {
            AccessibilityWindowInfo child = winfo.getChild(i);
            if (child == null) {
                Log.i(LOGTAG, String.format("Null window child %d/%d, parent: %s", i, count,
                        winfo.getTitle()));
                continue;
            }
            dumpWindowRec(child, serializer, i, width, height, rotation);
            child.recycle();
        }
        AccessibilityNodeInfo root = winfo.getRoot();
        if (root != null) {
            serializer.startTag("", "hierarchy");
            serializer.attribute("", "rotation", Integer.toString(rotation));
            dumpNodeRec(root, serializer, 0, width, height);
            root.recycle();
            serializer.endTag("", "hierarchy");
        }
        serializer.endTag("", "window");
    }

    private static void dumpNodeRec(AccessibilityNodeInfo node, XmlSerializer serializer,int index,
            int width, int height) throws IOException {
        serializer.startTag("", "node");
+5 −2
Original line number Diff line number Diff line
@@ -752,7 +752,10 @@ public final class AccessibilityWindowInfo implements Parcelable {
        }
    }

    private static String typeToString(int type) {
    /**
     * @hide
     */
    public static String typeToString(int type) {
        switch (type) {
            case TYPE_APPLICATION: {
                return "TYPE_APPLICATION";
@@ -770,7 +773,7 @@ public final class AccessibilityWindowInfo implements Parcelable {
                return "TYPE_SPLIT_SCREEN_DIVIDER";
            }
            default:
                return "<UNKNOWN>";
                return "<UNKNOWN:" + type + ">";
        }
    }