1/* 2 * Copyright (C) 2012 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package com.android.uiautomator.actions; 18 19import com.android.ddmlib.IDevice; 20import com.android.uiautomator.DebugBridge; 21import com.android.uiautomator.UiAutomatorHelper; 22import com.android.uiautomator.UiAutomatorHelper.UiAutomatorException; 23import com.android.uiautomator.UiAutomatorHelper.UiAutomatorResult; 24import com.android.uiautomator.UiAutomatorViewer; 25 26import org.eclipse.core.runtime.IProgressMonitor; 27import org.eclipse.core.runtime.IStatus; 28import org.eclipse.core.runtime.Status; 29import org.eclipse.jface.action.Action; 30import org.eclipse.jface.dialogs.Dialog; 31import org.eclipse.jface.dialogs.ErrorDialog; 32import org.eclipse.jface.dialogs.MessageDialog; 33import org.eclipse.jface.dialogs.ProgressMonitorDialog; 34import org.eclipse.jface.operation.IRunnableWithProgress; 35import org.eclipse.jface.resource.ImageDescriptor; 36import org.eclipse.jface.window.Window; 37import org.eclipse.swt.SWT; 38import org.eclipse.swt.events.SelectionAdapter; 39import org.eclipse.swt.events.SelectionEvent; 40import org.eclipse.swt.layout.GridLayout; 41import org.eclipse.swt.widgets.Combo; 42import org.eclipse.swt.widgets.Composite; 43import org.eclipse.swt.widgets.Control; 44import org.eclipse.swt.widgets.Label; 45import org.eclipse.swt.widgets.Shell; 46 47import java.lang.reflect.InvocationTargetException; 48import java.util.List; 49 50public class ScreenshotAction extends Action { 51 UiAutomatorViewer mViewer; 52 53 public ScreenshotAction(UiAutomatorViewer viewer) { 54 super("&Device Screenshot"); 55 mViewer = viewer; 56 } 57 58 @Override 59 public ImageDescriptor getImageDescriptor() { 60 return ImageHelper.loadImageDescriptorFromResource("images/screenshot.png"); 61 } 62 63 @Override 64 public void run() { 65 if (!DebugBridge.isInitialized()) { 66 MessageDialog.openError(mViewer.getShell(), 67 "Error obtaining Device Screenshot", 68 "Unable to connect to adb. Check if adb is installed correctly."); 69 return; 70 } 71 72 final IDevice device = pickDevice(); 73 if (device == null) { 74 return; 75 } 76 77 ProgressMonitorDialog dialog = new ProgressMonitorDialog(mViewer.getShell()); 78 try { 79 dialog.run(true, false, new IRunnableWithProgress() { 80 @Override 81 public void run(IProgressMonitor monitor) throws InvocationTargetException, 82 InterruptedException { 83 UiAutomatorResult result = null; 84 try { 85 result = UiAutomatorHelper.takeSnapshot(device, monitor); 86 } catch (UiAutomatorException e) { 87 monitor.done(); 88 showError(e.getMessage(), e); 89 return; 90 } 91 92 mViewer.setModel(result.model, result.uiHierarchy, result.screenshot); 93 monitor.done(); 94 } 95 }); 96 } catch (Exception e) { 97 showError("Unexpected error while obtaining UI hierarchy", e); 98 } 99 } 100 101 private void showError(final String msg, final Throwable t) { 102 mViewer.getShell().getDisplay().syncExec(new Runnable() { 103 @Override 104 public void run() { 105 Status s = new Status(IStatus.ERROR, "Screenshot", msg, t); 106 ErrorDialog.openError( 107 mViewer.getShell(), "Error", "Error obtaining UI hierarchy", s); 108 } 109 }); 110 } 111 112 private IDevice pickDevice() { 113 List<IDevice> devices = DebugBridge.getDevices(); 114 if (devices.size() == 0) { 115 MessageDialog.openError(mViewer.getShell(), 116 "Error obtaining Device Screenshot", 117 "No Android devices were detected by adb."); 118 return null; 119 } else if (devices.size() == 1) { 120 return devices.get(0); 121 } else { 122 DevicePickerDialog dlg = new DevicePickerDialog(mViewer.getShell(), devices); 123 if (dlg.open() != Window.OK) { 124 return null; 125 } 126 return dlg.getSelectedDevice(); 127 } 128 } 129 130 private static class DevicePickerDialog extends Dialog { 131 private final List<IDevice> mDevices; 132 private final String[] mDeviceNames; 133 private static int sSelectedDeviceIndex; 134 135 public DevicePickerDialog(Shell parentShell, List<IDevice> devices) { 136 super(parentShell); 137 138 mDevices = devices; 139 mDeviceNames = new String[mDevices.size()]; 140 for (int i = 0; i < devices.size(); i++) { 141 mDeviceNames[i] = devices.get(i).getName(); 142 } 143 } 144 145 @Override 146 protected Control createDialogArea(Composite parentShell) { 147 Composite parent = (Composite) super.createDialogArea(parentShell); 148 Composite c = new Composite(parent, SWT.NONE); 149 150 c.setLayout(new GridLayout(2, false)); 151 152 Label l = new Label(c, SWT.NONE); 153 l.setText("Select device: "); 154 155 final Combo combo = new Combo(c, SWT.BORDER | SWT.READ_ONLY); 156 combo.setItems(mDeviceNames); 157 int defaultSelection = 158 sSelectedDeviceIndex < mDevices.size() ? sSelectedDeviceIndex : 0; 159 combo.select(defaultSelection); 160 sSelectedDeviceIndex = defaultSelection; 161 162 combo.addSelectionListener(new SelectionAdapter() { 163 @Override 164 public void widgetSelected(SelectionEvent arg0) { 165 sSelectedDeviceIndex = combo.getSelectionIndex(); 166 } 167 }); 168 169 return parent; 170 } 171 172 public IDevice getSelectedDevice() { 173 return mDevices.get(sSelectedDeviceIndex); 174 } 175 } 176} 177