diff options
Diffstat (limited to 'uiautomatorviewer/src/com/android/uiautomator/actions')
5 files changed, 477 insertions, 0 deletions
diff --git a/uiautomatorviewer/src/com/android/uiautomator/actions/ExpandAllAction.java b/uiautomatorviewer/src/com/android/uiautomator/actions/ExpandAllAction.java new file mode 100644 index 0000000..3c73fdc --- /dev/null +++ b/uiautomatorviewer/src/com/android/uiautomator/actions/ExpandAllAction.java @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.uiautomator.actions; + +import com.android.uiautomator.UiAutomatorViewer; + +import org.eclipse.jface.action.Action; +import org.eclipse.jface.resource.ImageDescriptor; + +public class ExpandAllAction extends Action { + + UiAutomatorViewer mWindow; + + public ExpandAllAction(UiAutomatorViewer window) { + super("&Expand All"); + mWindow = window; + } + + @Override + public ImageDescriptor getImageDescriptor() { + return ImageHelper.loadImageDescriptorFromResource("images/expandall.png"); + } + + @Override + public void run() { + mWindow.expandAll(); + } + +} diff --git a/uiautomatorviewer/src/com/android/uiautomator/actions/ImageHelper.java b/uiautomatorviewer/src/com/android/uiautomator/actions/ImageHelper.java new file mode 100644 index 0000000..c22f1fd --- /dev/null +++ b/uiautomatorviewer/src/com/android/uiautomator/actions/ImageHelper.java @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.uiautomator.actions; + +import org.eclipse.jface.resource.ImageDescriptor; +import org.eclipse.swt.SWTException; +import org.eclipse.swt.graphics.ImageData; +import org.eclipse.swt.graphics.ImageLoader; + +import java.io.InputStream; + +public class ImageHelper { + + public static ImageDescriptor loadImageDescriptorFromResource(String path) { + InputStream is = ImageHelper.class.getClassLoader().getResourceAsStream(path); + if (is != null) { + ImageData[] data = null; + try { + data = new ImageLoader().load(is); + } catch (SWTException e) { + } + if (data != null && data.length > 0) { + return ImageDescriptor.createFromImageData(data[0]); + } + } + return null; + } +} diff --git a/uiautomatorviewer/src/com/android/uiautomator/actions/OpenFilesAction.java b/uiautomatorviewer/src/com/android/uiautomator/actions/OpenFilesAction.java new file mode 100644 index 0000000..3232857 --- /dev/null +++ b/uiautomatorviewer/src/com/android/uiautomator/actions/OpenFilesAction.java @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.uiautomator.actions; + +import com.android.uiautomator.OpenDialog; +import com.android.uiautomator.UiAutomatorModel; + +import org.eclipse.jface.action.Action; +import org.eclipse.jface.resource.ImageDescriptor; +import org.eclipse.jface.window.ApplicationWindow; + +public class OpenFilesAction extends Action { + + ApplicationWindow mWindow; + + public OpenFilesAction(ApplicationWindow window) { + super("&Open"); + mWindow = window; + } + + @Override + public ImageDescriptor getImageDescriptor() { + return ImageHelper.loadImageDescriptorFromResource("images/open-folder.png"); + } + + @Override + public void run() { + OpenDialog d = new OpenDialog(mWindow.getShell()); + if (d.open() == OpenDialog.OK) { + UiAutomatorModel.getModel().loadScreenshotAndXmlDump( + d.getScreenshotFile(), d.getXmlDumpFile()); + } + } +} diff --git a/uiautomatorviewer/src/com/android/uiautomator/actions/ScreenshotAction.java b/uiautomatorviewer/src/com/android/uiautomator/actions/ScreenshotAction.java new file mode 100644 index 0000000..7d1eaa3 --- /dev/null +++ b/uiautomatorviewer/src/com/android/uiautomator/actions/ScreenshotAction.java @@ -0,0 +1,302 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.uiautomator.actions; + +import com.android.uiautomator.UiAutomatorModel; +import com.android.uiautomator.UiAutomatorViewer; + +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.jface.action.Action; +import org.eclipse.jface.dialogs.ErrorDialog; +import org.eclipse.jface.dialogs.ProgressMonitorDialog; +import org.eclipse.jface.operation.IRunnableWithProgress; +import org.eclipse.jface.resource.ImageDescriptor; + +import java.io.BufferedReader; +import java.io.File; +import java.io.IOException; +import java.io.InputStreamReader; +import java.lang.reflect.InvocationTargetException; +import java.util.ArrayList; +import java.util.List; + +public class ScreenshotAction extends Action { + + UiAutomatorViewer mViewer; + + public ScreenshotAction(UiAutomatorViewer viewer) { + super("&Device Screenshot"); + mViewer = viewer; + } + + @Override + public ImageDescriptor getImageDescriptor() { + return ImageHelper.loadImageDescriptorFromResource("images/screenshot.png"); + } + + @Override + public void run() { + ProgressMonitorDialog dialog = new ProgressMonitorDialog(mViewer.getShell()); + try { + dialog.run(true, false, new IRunnableWithProgress() { + private void showError(final String msg, final Throwable t, + IProgressMonitor monitor) { + monitor.done(); + mViewer.getShell().getDisplay().syncExec(new Runnable() { + @Override + public void run() { + Status s = new Status(IStatus.ERROR, "Screenshot", msg, t); + ErrorDialog.openError( + mViewer.getShell(), "Error", "Cannot take screenshot", s); + } + }); + } + + @Override + public void run(IProgressMonitor monitor) throws InvocationTargetException, + InterruptedException { + ProcRunner procRunner = null; + String serial = System.getenv("ANDROID_SERIAL"); + File tmpDir = null; + File xmlDumpFile = null; + File screenshotFile = null; + int retCode = -1; + try { + tmpDir = File.createTempFile("uiautomatorviewer_", ""); + tmpDir.delete(); + if (!tmpDir.mkdirs()) + throw new IOException("Failed to mkdir"); + xmlDumpFile = File.createTempFile("dump_", ".xml", tmpDir); + screenshotFile = File.createTempFile("screenshot_", ".png", tmpDir); + } catch (IOException e) { + e.printStackTrace(); + showError("Cannot get temp directory", e, monitor); + return; + } + UiAutomatorModel.getModel().registerTempDirectory(tmpDir); + + // boiler plates to do a bunch of adb stuff to take XML snapshot and screenshot + monitor.beginTask("Getting UI status dump from device...", + IProgressMonitor.UNKNOWN); + monitor.subTask("Detecting device..."); + procRunner = getAdbRunner(serial, "shell", "ls", "/system/bin/uiautomator"); + try { + retCode = procRunner.run(30000); + } catch (IOException e) { + e.printStackTrace(); + showError("Failed to detect device", e, monitor); + return; + } + if (retCode != 0) { + showError("No device or multiple devices connected. " + + "Use ANDROID_SERIAL environment variable " + + "if you have multiple devices", null, monitor); + return; + } + if (procRunner.getOutputBlob().indexOf("No such file or directory") != -1) { + showError("/system/bin/uiautomator not found on device", null, monitor); + return; + } + monitor.subTask("Deleting old UI XML snapshot ..."); + procRunner = getAdbRunner(serial, + "shell", "rm", "/sdcard/uidump.xml"); + try { + retCode = procRunner.run(30000); + if (retCode != 0) { + throw new IOException( + "Non-zero return code from \"rm\" xml dump command:\n" + + procRunner.getOutputBlob()); + } + } catch (IOException e) { + e.printStackTrace(); + showError("Failed to execute \"rm\" xml dump command.", e, monitor); + return; + } + + monitor.subTask("Taking UI XML snapshot..."); + procRunner = getAdbRunner(serial, + "shell", "/system/bin/uiautomator", "dump", "/sdcard/uidump.xml"); + try { + retCode = procRunner.run(30000); + if (retCode != 0) { + throw new IOException("Non-zero return code from dump command:\n" + + procRunner.getOutputBlob()); + } + } catch (IOException e) { + e.printStackTrace(); + showError("Failed to execute dump command.", e, monitor); + return; + } + procRunner = getAdbRunner(serial, + "pull", "/sdcard/uidump.xml", xmlDumpFile.getAbsolutePath()); + try { + retCode = procRunner.run(30000); + if (retCode != 0) { + throw new IOException("Non-zero return code from pull command:\n" + + procRunner.getOutputBlob()); + } + } catch (IOException e) { + e.printStackTrace(); + showError("Failed to pull dump file.", e, monitor); + return; + } + + monitor.subTask("Deleting old device screenshot..."); + procRunner = getAdbRunner(serial, + "shell", "rm", "/sdcard/screenshot.png"); + try { + retCode = procRunner.run(30000); + if (retCode != 0) { + throw new IOException( + "Non-zero return code from \"rm\" screenshot command:\n" + + procRunner.getOutputBlob()); + } + } catch (IOException e) { + e.printStackTrace(); + showError("Failed to execute \"rm\" screenshot command.", e, monitor); + return; + } + + monitor.subTask("Taking device screenshot..."); + procRunner = getAdbRunner(serial, + "shell", "screencap", "-p", "/sdcard/screenshot.png"); + try { + retCode = procRunner.run(30000); + if (retCode != 0) { + throw new IOException("Non-zero return code from screenshot command:\n" + + procRunner.getOutputBlob()); + } + } catch (IOException e) { + e.printStackTrace(); + showError("Failed to execute screenshot command.", e, monitor); + return; + } + procRunner = getAdbRunner(serial, + "pull", "/sdcard/screenshot.png", screenshotFile.getAbsolutePath()); + try { + retCode = procRunner.run(30000); + if (retCode != 0) { + throw new IOException("Non-zero return code from pull command:\n" + + procRunner.getOutputBlob()); + } + } catch (IOException e) { + e.printStackTrace(); + showError("Failed to pull dump file.", e, monitor); + return; + } + final File png = screenshotFile, xml = xmlDumpFile; + if(png.length() == 0) { + showError("Screenshot file size is 0", null, monitor); + return; + } else { + mViewer.getShell().getDisplay().syncExec(new Runnable() { + @Override + public void run() { + UiAutomatorModel.getModel().loadScreenshotAndXmlDump(png, xml); + } + }); + } + monitor.done(); + } + }); + } catch (InvocationTargetException e) { + e.printStackTrace(); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + + /* + * Convenience function to construct an 'adb' command, e.g. use 'adb' or 'adb -s NNN' + */ + private ProcRunner getAdbRunner(String serial, String... command) { + List<String> cmd = new ArrayList<String>(); + cmd.add("adb"); + if (serial != null) { + cmd.add("-s"); + cmd.add(serial); + } + for (String s : command) { + cmd.add(s); + } + return new ProcRunner(cmd); + } + + /** + * Convenience class to run external process. + * + * Always redirects stderr into stdout, has timeout control + * + */ + private static class ProcRunner { + + ProcessBuilder mProcessBuilder; + + List<String> mOutput = new ArrayList<String>(); + + public ProcRunner(List<String> command) { + mProcessBuilder = new ProcessBuilder(command).redirectErrorStream(true); + } + + public int run(long timeout) throws IOException { + final Process p = mProcessBuilder.start(); + Thread t = new Thread() { + @Override + public void run() { + String line; + mOutput.clear(); + try { + BufferedReader br = new BufferedReader(new InputStreamReader( + p.getInputStream())); + while ((line = br.readLine()) != null) { + mOutput.add(line); + } + br.close(); + } catch (IOException e) { + e.printStackTrace(); + } + }; + }; + t.start(); + try { + t.join(timeout); + } catch (InterruptedException e) { + e.printStackTrace(); + } + if (t.isAlive()) { + throw new IOException("external process not terminating."); + } + try { + return p.waitFor(); + } catch (InterruptedException e) { + e.printStackTrace(); + throw new IOException(e); + } + } + + public String getOutputBlob() { + StringBuilder sb = new StringBuilder(); + for (String line : mOutput) { + sb.append(line); + sb.append(System.getProperty("line.separator")); + } + return sb.toString(); + } + } +} diff --git a/uiautomatorviewer/src/com/android/uiautomator/actions/ToggleNafAction.java b/uiautomatorviewer/src/com/android/uiautomator/actions/ToggleNafAction.java new file mode 100644 index 0000000..afc422d --- /dev/null +++ b/uiautomatorviewer/src/com/android/uiautomator/actions/ToggleNafAction.java @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.uiautomator.actions; + +import com.android.uiautomator.UiAutomatorModel; + +import org.eclipse.jface.action.Action; +import org.eclipse.jface.action.IAction; +import org.eclipse.jface.resource.ImageDescriptor; + +public class ToggleNafAction extends Action { + + public ToggleNafAction() { + super("&Toggle NAF Nodes", IAction.AS_CHECK_BOX); + setChecked(UiAutomatorModel.getModel().shouldShowNafNodes()); + } + + @Override + public ImageDescriptor getImageDescriptor() { + return ImageHelper.loadImageDescriptorFromResource("images/warning.png"); + } + + @Override + public void run() { + UiAutomatorModel.getModel().toggleShowNaf(); + setChecked(UiAutomatorModel.getModel().shouldShowNafNodes()); + } +} |