diff options
author | Siva Velusamy <vsiva@google.com> | 2012-08-08 17:22:04 -0700 |
---|---|---|
committer | Siva Velusamy <vsiva@google.com> | 2012-08-14 10:47:16 -0700 |
commit | 07750e98d91da6a1a906c73e2a2b92e46aedf4cf (patch) | |
tree | 50e8077a6beebc71ed0e6f2e36610ae36c19f13e /eclipse/plugins/com.android.ide.eclipse.ddms/src/com | |
parent | 2528d6f1dd7074f6a3e3b2e4d31ccc76c62558a8 (diff) | |
download | sdk-07750e98d91da6a1a906c73e2a2b92e46aedf4cf.tar.gz |
Integrate uiautomatorviewer into Eclipse
This CL integrates uiautomatorviewer into Eclipse. There are two
components to this:
1. Take UI Hierarchy Dump from a device: This is added as an action
to the device view in the DDMS perspective.
2. Viewing the resulting UI hierarchy: This is added as an editor,
associated with the .uix extension. The editor simply wraps a
UiAutomatorView.
The UiAutomatorView is modified slightly to allow for opening just
the hierarchy file without the associated screenshot. This is to
enable opening the .uix file via standard Eclipse Open File Dialog.
When opened this way, the canvas displaying the screenshot is replaced
with a button that allows the user to specify the actual screenshot
to be displayed.
Change-Id: I0f31fe95b2728123ff6f0f748478c18c0c2f1b48
Diffstat (limited to 'eclipse/plugins/com.android.ide.eclipse.ddms/src/com')
3 files changed, 239 insertions, 5 deletions
diff --git a/eclipse/plugins/com.android.ide.eclipse.ddms/src/com/android/ide/eclipse/ddms/DdmsPlugin.java b/eclipse/plugins/com.android.ide.eclipse.ddms/src/com/android/ide/eclipse/ddms/DdmsPlugin.java index a24f1222d..71639ec16 100644 --- a/eclipse/plugins/com.android.ide.eclipse.ddms/src/com/android/ide/eclipse/ddms/DdmsPlugin.java +++ b/eclipse/plugins/com.android.ide.eclipse.ddms/src/com/android/ide/eclipse/ddms/DdmsPlugin.java @@ -43,6 +43,7 @@ import org.eclipse.core.runtime.Status; import org.eclipse.core.runtime.jobs.Job; import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.jface.preference.IPreferenceStore; +import org.eclipse.jface.resource.ImageDescriptor; import org.eclipse.jface.util.IPropertyChangeListener; import org.eclipse.jface.util.PropertyChangeEvent; import org.eclipse.swt.SWTException; @@ -816,4 +817,9 @@ public final class DdmsPlugin extends AbstractUIPlugin implements IDeviceChangeL mLogCatMonitor.monitorDevice(device); } + + /** Returns an image descriptor for the image file at the given plug-in relative path */ + public static ImageDescriptor getImageDescriptor(String path) { + return imageDescriptorFromPlugin(PLUGIN_ID, path); + } } diff --git a/eclipse/plugins/com.android.ide.eclipse.ddms/src/com/android/ide/eclipse/ddms/editors/UiAutomatorViewer.java b/eclipse/plugins/com.android.ide.eclipse.ddms/src/com/android/ide/eclipse/ddms/editors/UiAutomatorViewer.java new file mode 100644 index 000000000..0843018aa --- /dev/null +++ b/eclipse/plugins/com.android.ide.eclipse.ddms/src/com/android/ide/eclipse/ddms/editors/UiAutomatorViewer.java @@ -0,0 +1,172 @@ +/* + * 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.ide.eclipse.ddms.editors; + +import com.android.ide.eclipse.base.InstallDetails; +import com.android.uiautomator.UiAutomatorHelper.UiAutomatorResult; +import com.android.uiautomator.UiAutomatorModel; +import com.android.uiautomator.UiAutomatorView; + +import org.eclipse.core.filesystem.EFS; +import org.eclipse.core.filesystem.IFileStore; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.Path; +import org.eclipse.jface.dialogs.MessageDialog; +import org.eclipse.swt.SWT; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.ui.IEditorInput; +import org.eclipse.ui.IEditorPart; +import org.eclipse.ui.IEditorSite; +import org.eclipse.ui.IURIEditorInput; +import org.eclipse.ui.IWorkbench; +import org.eclipse.ui.IWorkbenchPage; +import org.eclipse.ui.IWorkbenchWindow; +import org.eclipse.ui.PartInitException; +import org.eclipse.ui.PlatformUI; +import org.eclipse.ui.WorkbenchException; +import org.eclipse.ui.ide.IDE; +import org.eclipse.ui.part.EditorPart; + +import java.io.File; +import java.util.concurrent.atomic.AtomicBoolean; + +public class UiAutomatorViewer extends EditorPart { + private String mFilePath; + private UiAutomatorView mView; + + @Override + public void doSave(IProgressMonitor arg0) { + } + + @Override + public void doSaveAs() { + } + + @Override + public boolean isSaveAsAllowed() { + return false; + } + + @Override + public boolean isDirty() { + return false; + } + + @Override + public void init(IEditorSite site, IEditorInput input) throws PartInitException { + // we use a IURIEditorInput to allow opening files not within the workspace + if (!(input instanceof IURIEditorInput)) { + throw new PartInitException("UI Automator Hierarchy View: unsupported input type."); + } + + setSite(site); + setInput(input); + mFilePath = ((IURIEditorInput) input).getURI().getPath(); + + // set the editor part name to be the name of the file. + File f = new File(mFilePath); + setPartName(f.getName()); + } + + @Override + public void createPartControl(Composite parent) { + Composite c = new Composite(parent, SWT.NONE); + c.setLayout(new GridLayout(1, false)); + GridData gd = new GridData(GridData.FILL_BOTH); + c.setLayoutData(gd); + + mView = new UiAutomatorView(c, SWT.BORDER); + mView.setLayoutData(new GridData(GridData.FILL_BOTH)); + + if (mFilePath == null) { + return; + } + + UiAutomatorModel model = null; + File modelFile = new File(mFilePath); + try { + model = new UiAutomatorModel(modelFile); + } catch (Exception e) { + MessageDialog.openError(parent.getShell(), "Error opening " + mFilePath, + "Unexpected error while parsing input: " + e.getMessage()); + return; + } + + mView.setModel(model, modelFile, null); + } + + @Override + public void setFocus() { + } + + public static boolean openEditor(final UiAutomatorResult r) { + final IFileStore fileStore = EFS.getLocalFileSystem().getStore( + new Path(r.uiHierarchy.getAbsolutePath())); + if (!fileStore.fetchInfo().exists()) { + return false; + } + + final AtomicBoolean status = new AtomicBoolean(false); + + final IWorkbench workbench = PlatformUI.getWorkbench(); + workbench.getDisplay().syncExec(new Runnable() { + @Override + public void run() { + IWorkbenchWindow window = workbench.getActiveWorkbenchWindow(); + if (window == null) { + return; + } + + IWorkbenchPage page = window.getActivePage(); + if (page == null) { + return; + } + + // try to switch perspectives if possible + if (page.isEditorAreaVisible() == false && InstallDetails.isAdtInstalled()) { + try { + workbench.showPerspective("org.eclipse.jdt.ui.JavaPerspective", window); //$NON-NLS-1$ + } catch (WorkbenchException e) { + } + } + + IEditorPart editor = null; + try { + editor = IDE.openEditorOnFileStore(page, fileStore); + } catch (PartInitException e) { + return; + } + + if (!(editor instanceof UiAutomatorViewer)) { + return; + } + + ((UiAutomatorViewer) editor).setModel(r.model, r.uiHierarchy, r.screenshot); + status.set(true); + } + }); + + return status.get(); + } + + protected void setModel(UiAutomatorModel model, File modelFile, Image screenshot) { + mView.setModel(model, modelFile, screenshot); + } +} diff --git a/eclipse/plugins/com.android.ide.eclipse.ddms/src/com/android/ide/eclipse/ddms/views/DeviceView.java b/eclipse/plugins/com.android.ide.eclipse.ddms/src/com/android/ide/eclipse/ddms/views/DeviceView.java index 31ae3b856..17670e49e 100644 --- a/eclipse/plugins/com.android.ide.eclipse.ddms/src/com/android/ide/eclipse/ddms/views/DeviceView.java +++ b/eclipse/plugins/com.android.ide.eclipse.ddms/src/com/android/ide/eclipse/ddms/views/DeviceView.java @@ -38,20 +38,29 @@ import com.android.ddmuilib.handler.BaseFileHandler; import com.android.ddmuilib.handler.MethodProfilingHandler; import com.android.ide.eclipse.ddms.DdmsPlugin; import com.android.ide.eclipse.ddms.IDebuggerConnector; +import com.android.ide.eclipse.ddms.editors.UiAutomatorViewer; import com.android.ide.eclipse.ddms.i18n.Messages; import com.android.ide.eclipse.ddms.preferences.PreferenceInitializer; +import com.android.uiautomator.UiAutomatorHelper; +import com.android.uiautomator.UiAutomatorHelper.UiAutomatorException; +import com.android.uiautomator.UiAutomatorHelper.UiAutomatorResult; import org.eclipse.core.filesystem.EFS; import org.eclipse.core.filesystem.IFileStore; -import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.IAdaptable; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Path; +import org.eclipse.core.runtime.Status; import org.eclipse.jface.action.Action; import org.eclipse.jface.action.IAction; import org.eclipse.jface.action.IMenuManager; import org.eclipse.jface.action.IToolBarManager; import org.eclipse.jface.action.Separator; +import org.eclipse.jface.dialogs.ErrorDialog; import org.eclipse.jface.dialogs.MessageDialog; +import org.eclipse.jface.dialogs.ProgressMonitorDialog; +import org.eclipse.jface.operation.IRunnableWithProgress; import org.eclipse.jface.preference.IPreferenceStore; import org.eclipse.jface.resource.ImageDescriptor; import org.eclipse.swt.widgets.Composite; @@ -70,6 +79,7 @@ import org.eclipse.ui.part.ViewPart; import java.io.File; import java.io.IOException; +import java.lang.reflect.InvocationTargetException; public class DeviceView extends ViewPart implements IUiSelectionListener, IClientChangeListener { @@ -84,6 +94,7 @@ public class DeviceView extends ViewPart implements IUiSelectionListener, IClien private Action mResetAdbAction; private Action mCaptureAction; + private Action mViewUiAutomatorHierarchyAction; private Action mUpdateThreadAction; private Action mUpdateHeapAction; private Action mGcAction; @@ -255,12 +266,13 @@ public class DeviceView extends ViewPart implements IUiSelectionListener, IClien IWorkbench workbench = PlatformUI.getWorkbench(); IWorkbenchWindow window = workbench.getActiveWorkbenchWindow(); IWorkbenchPage page = window.getActivePage(); + if (page == null) { + return; + } + if (page.isEditorAreaVisible() == false) { IAdaptable input; - if (page != null) - input = page.getInput(); - else - input = ResourcesPlugin.getWorkspace().getRoot(); + input = page.getInput(); try { workbench.showPerspective("org.eclipse.debug.ui.DebugPerspective", //$NON-NLS-1$ window, input); @@ -308,6 +320,17 @@ public class DeviceView extends ViewPart implements IUiSelectionListener, IClien mCaptureAction.setToolTipText(Messages.DeviceView_Screen_Capture_Tooltip); mCaptureAction.setImageDescriptor(loader.loadDescriptor("capture.png")); //$NON-NLS-1$ + mViewUiAutomatorHierarchyAction = new Action("Dump View Hierarchy for UI Automator") { + @Override + public void run() { + takeUiAutomatorSnapshot(mDeviceList.getSelectedDevice(), + DdmsPlugin.getDisplay().getActiveShell()); + } + }; + mViewUiAutomatorHierarchyAction.setToolTipText("Dump View Hierarchy for UI Automator"); + mViewUiAutomatorHierarchyAction.setImageDescriptor( + DdmsPlugin.getImageDescriptor("icons/uiautomator.png")); //$NON-NLS-1$ + mResetAdbAction = new Action(Messages.DeviceView_Reset_ADB) { @Override public void run() { @@ -486,6 +509,34 @@ public class DeviceView extends ViewPart implements IUiSelectionListener, IClien }); } + private void takeUiAutomatorSnapshot(final IDevice device, final Shell shell) { + ProgressMonitorDialog dialog = new ProgressMonitorDialog(shell); + try { + dialog.run(true, false, new IRunnableWithProgress() { + @Override + public void run(IProgressMonitor monitor) throws InvocationTargetException, + InterruptedException { + UiAutomatorResult result = null; + try { + result = UiAutomatorHelper.takeSnapshot(device, monitor); + } catch (UiAutomatorException e) { + throw new InvocationTargetException(e); + } finally { + monitor.done(); + } + + UiAutomatorViewer.openEditor(result); + } + }); + } catch (Exception e) { + Status s = new Status(IStatus.ERROR, DdmsPlugin.PLUGIN_ID, + "Error obtaining UI hierarchy", e); + ErrorDialog.openError(shell, "UI Automator", + "Unexpected error while obtaining UI hierarchy", s); + } + }; + + @Override public void setFocus() { mDeviceList.setFocus(); @@ -585,6 +636,7 @@ public class DeviceView extends ViewPart implements IUiSelectionListener, IClien private void doSelectionChanged(IDevice selectedDevice) { mCaptureAction.setEnabled(selectedDevice != null); + mViewUiAutomatorHierarchyAction.setEnabled(selectedDevice != null); } /** @@ -609,6 +661,8 @@ public class DeviceView extends ViewPart implements IUiSelectionListener, IClien menuManager.add(new Separator()); menuManager.add(mCaptureAction); menuManager.add(new Separator()); + menuManager.add(mViewUiAutomatorHierarchyAction); + menuManager.add(new Separator()); menuManager.add(mResetAdbAction); // and then in the toolbar @@ -626,6 +680,8 @@ public class DeviceView extends ViewPart implements IUiSelectionListener, IClien toolBarManager.add(mKillAppAction); toolBarManager.add(new Separator()); toolBarManager.add(mCaptureAction); + toolBarManager.add(new Separator()); + toolBarManager.add(mViewUiAutomatorHierarchyAction); } @Override |