diff options
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 |