12da677e322f0d46b8ea4f882d780f5ee4e97647aGuang Zhu/*
22da677e322f0d46b8ea4f882d780f5ee4e97647aGuang Zhu * Copyright (C) 2012 The Android Open Source Project
32da677e322f0d46b8ea4f882d780f5ee4e97647aGuang Zhu *
42da677e322f0d46b8ea4f882d780f5ee4e97647aGuang Zhu * Licensed under the Apache License, Version 2.0 (the "License");
52da677e322f0d46b8ea4f882d780f5ee4e97647aGuang Zhu * you may not use this file except in compliance with the License.
62da677e322f0d46b8ea4f882d780f5ee4e97647aGuang Zhu * You may obtain a copy of the License at
72da677e322f0d46b8ea4f882d780f5ee4e97647aGuang Zhu *
82da677e322f0d46b8ea4f882d780f5ee4e97647aGuang Zhu *      http://www.apache.org/licenses/LICENSE-2.0
92da677e322f0d46b8ea4f882d780f5ee4e97647aGuang Zhu *
102da677e322f0d46b8ea4f882d780f5ee4e97647aGuang Zhu * Unless required by applicable law or agreed to in writing, software
112da677e322f0d46b8ea4f882d780f5ee4e97647aGuang Zhu * distributed under the License is distributed on an "AS IS" BASIS,
122da677e322f0d46b8ea4f882d780f5ee4e97647aGuang Zhu * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
132da677e322f0d46b8ea4f882d780f5ee4e97647aGuang Zhu * See the License for the specific language governing permissions and
142da677e322f0d46b8ea4f882d780f5ee4e97647aGuang Zhu * limitations under the License.
152da677e322f0d46b8ea4f882d780f5ee4e97647aGuang Zhu */
162da677e322f0d46b8ea4f882d780f5ee4e97647aGuang Zhu
172da677e322f0d46b8ea4f882d780f5ee4e97647aGuang Zhupackage com.android.commands.uiautomator;
182da677e322f0d46b8ea4f882d780f5ee4e97647aGuang Zhu
192da677e322f0d46b8ea4f882d780f5ee4e97647aGuang Zhuimport android.accessibilityservice.UiTestAutomationBridge;
202da677e322f0d46b8ea4f882d780f5ee4e97647aGuang Zhuimport android.os.Environment;
21784337a4ccd52aeafa062f38a2605f547fca6472Guang Zhuimport android.view.accessibility.AccessibilityNodeInfo;
222da677e322f0d46b8ea4f882d780f5ee4e97647aGuang Zhu
232da677e322f0d46b8ea4f882d780f5ee4e97647aGuang Zhuimport com.android.commands.uiautomator.Launcher.Command;
242da677e322f0d46b8ea4f882d780f5ee4e97647aGuang Zhuimport com.android.uiautomator.core.AccessibilityNodeInfoDumper;
252da677e322f0d46b8ea4f882d780f5ee4e97647aGuang Zhu
262da677e322f0d46b8ea4f882d780f5ee4e97647aGuang Zhuimport java.io.File;
272da677e322f0d46b8ea4f882d780f5ee4e97647aGuang Zhu
282da677e322f0d46b8ea4f882d780f5ee4e97647aGuang Zhu/**
292da677e322f0d46b8ea4f882d780f5ee4e97647aGuang Zhu * Implementation of the dump subcommand
302da677e322f0d46b8ea4f882d780f5ee4e97647aGuang Zhu *
312da677e322f0d46b8ea4f882d780f5ee4e97647aGuang Zhu * This creates an XML dump of current UI hierarchy
322da677e322f0d46b8ea4f882d780f5ee4e97647aGuang Zhu */
332da677e322f0d46b8ea4f882d780f5ee4e97647aGuang Zhupublic class DumpCommand extends Command {
342da677e322f0d46b8ea4f882d780f5ee4e97647aGuang Zhu
352da677e322f0d46b8ea4f882d780f5ee4e97647aGuang Zhu    private static final File DEFAULT_DUMP_FILE = new File(
36784337a4ccd52aeafa062f38a2605f547fca6472Guang Zhu            Environment.getLegacyExternalStorageDirectory(), "window_dump.xml");
372da677e322f0d46b8ea4f882d780f5ee4e97647aGuang Zhu
382da677e322f0d46b8ea4f882d780f5ee4e97647aGuang Zhu    public DumpCommand() {
392da677e322f0d46b8ea4f882d780f5ee4e97647aGuang Zhu        super("dump");
402da677e322f0d46b8ea4f882d780f5ee4e97647aGuang Zhu    }
412da677e322f0d46b8ea4f882d780f5ee4e97647aGuang Zhu
422da677e322f0d46b8ea4f882d780f5ee4e97647aGuang Zhu    @Override
432da677e322f0d46b8ea4f882d780f5ee4e97647aGuang Zhu    public String shortHelp() {
442da677e322f0d46b8ea4f882d780f5ee4e97647aGuang Zhu        return "creates an XML dump of current UI hierarchy";
452da677e322f0d46b8ea4f882d780f5ee4e97647aGuang Zhu    }
462da677e322f0d46b8ea4f882d780f5ee4e97647aGuang Zhu
472da677e322f0d46b8ea4f882d780f5ee4e97647aGuang Zhu    @Override
482da677e322f0d46b8ea4f882d780f5ee4e97647aGuang Zhu    public String detailedOptions() {
492da677e322f0d46b8ea4f882d780f5ee4e97647aGuang Zhu        return "    dump [file]\n"
502da677e322f0d46b8ea4f882d780f5ee4e97647aGuang Zhu            + "      [file]: the location where the dumped XML should be stored, default is\n      "
512da677e322f0d46b8ea4f882d780f5ee4e97647aGuang Zhu            + DEFAULT_DUMP_FILE.getAbsolutePath() + "\n";
522da677e322f0d46b8ea4f882d780f5ee4e97647aGuang Zhu    }
532da677e322f0d46b8ea4f882d780f5ee4e97647aGuang Zhu
542da677e322f0d46b8ea4f882d780f5ee4e97647aGuang Zhu    @Override
552da677e322f0d46b8ea4f882d780f5ee4e97647aGuang Zhu    public void run(String[] args) {
562da677e322f0d46b8ea4f882d780f5ee4e97647aGuang Zhu        File dumpFile = DEFAULT_DUMP_FILE;
572da677e322f0d46b8ea4f882d780f5ee4e97647aGuang Zhu        if (args.length > 0) {
582da677e322f0d46b8ea4f882d780f5ee4e97647aGuang Zhu            dumpFile = new File(args[0]);
592da677e322f0d46b8ea4f882d780f5ee4e97647aGuang Zhu        }
602da677e322f0d46b8ea4f882d780f5ee4e97647aGuang Zhu        UiTestAutomationBridge bridge = new UiTestAutomationBridge();
612da677e322f0d46b8ea4f882d780f5ee4e97647aGuang Zhu        bridge.connect();
622da677e322f0d46b8ea4f882d780f5ee4e97647aGuang Zhu        // It appears that the bridge needs time to be ready. Making calls to the
632da677e322f0d46b8ea4f882d780f5ee4e97647aGuang Zhu        // bridge immediately after connecting seems to cause exceptions. So let's also
642da677e322f0d46b8ea4f882d780f5ee4e97647aGuang Zhu        // do a wait for idle in case the app is busy.
652da677e322f0d46b8ea4f882d780f5ee4e97647aGuang Zhu        bridge.waitForIdle(1000, 1000 * 10);
66784337a4ccd52aeafa062f38a2605f547fca6472Guang Zhu        AccessibilityNodeInfo info = bridge.getRootAccessibilityNodeInfoInActiveWindow();
67784337a4ccd52aeafa062f38a2605f547fca6472Guang Zhu        if (info == null) {
68784337a4ccd52aeafa062f38a2605f547fca6472Guang Zhu            System.err.println("ERROR: null root node returned by UiTestAutomationBridge.");
69784337a4ccd52aeafa062f38a2605f547fca6472Guang Zhu            return;
70784337a4ccd52aeafa062f38a2605f547fca6472Guang Zhu        }
71784337a4ccd52aeafa062f38a2605f547fca6472Guang Zhu        AccessibilityNodeInfoDumper.dumpWindowToFile(info, dumpFile);
722da677e322f0d46b8ea4f882d780f5ee4e97647aGuang Zhu        bridge.disconnect();
732da677e322f0d46b8ea4f882d780f5ee4e97647aGuang Zhu        System.out.println(
742da677e322f0d46b8ea4f882d780f5ee4e97647aGuang Zhu                String.format("UI hierchary dumped to: %s", dumpFile.getAbsolutePath()));
752da677e322f0d46b8ea4f882d780f5ee4e97647aGuang Zhu    }
762da677e322f0d46b8ea4f882d780f5ee4e97647aGuang Zhu
772da677e322f0d46b8ea4f882d780f5ee4e97647aGuang Zhu}
78