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