1 /* 2 * Copyright (C) 2007 The Android Open Source Project 3 * 4 * Licensed under the Eclipse Public License, Version 1.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.eclipse.org/org/documents/epl-v10.php 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 17 package com.android.ide.eclipse.adt.internal.launch; 18 19 import com.android.ide.eclipse.adt.AdtPlugin; 20 import com.android.ide.eclipse.adt.internal.launch.AndroidLaunchConfiguration.TargetMode; 21 import com.android.ide.eclipse.adt.internal.project.BaseProjectHelper; 22 import com.android.ide.eclipse.adt.internal.sdk.Sdk; 23 import com.android.ide.eclipse.ddms.DdmsPlugin; 24 import com.android.prefs.AndroidLocation.AndroidLocationException; 25 import com.android.sdklib.IAndroidTarget; 26 import com.android.sdklib.NullSdkLog; 27 import com.android.sdklib.internal.avd.AvdManager; 28 import com.android.sdklib.internal.avd.AvdManager.AvdInfo; 29 import com.android.sdkuilib.internal.widgets.AvdSelector; 30 import com.android.sdkuilib.internal.widgets.AvdSelector.DisplayMode; 31 32 import org.eclipse.core.resources.IProject; 33 import org.eclipse.core.runtime.CoreException; 34 import org.eclipse.debug.core.ILaunchConfiguration; 35 import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy; 36 import org.eclipse.debug.ui.AbstractLaunchConfigurationTab; 37 import org.eclipse.jdt.core.IJavaProject; 38 import org.eclipse.jdt.launching.IJavaLaunchConfigurationConstants; 39 import org.eclipse.jface.preference.IPreferenceStore; 40 import org.eclipse.swt.SWT; 41 import org.eclipse.swt.events.ModifyEvent; 42 import org.eclipse.swt.events.ModifyListener; 43 import org.eclipse.swt.events.SelectionAdapter; 44 import org.eclipse.swt.events.SelectionEvent; 45 import org.eclipse.swt.graphics.Font; 46 import org.eclipse.swt.graphics.Image; 47 import org.eclipse.swt.layout.GridData; 48 import org.eclipse.swt.layout.GridLayout; 49 import org.eclipse.swt.widgets.Button; 50 import org.eclipse.swt.widgets.Combo; 51 import org.eclipse.swt.widgets.Composite; 52 import org.eclipse.swt.widgets.Group; 53 import org.eclipse.swt.widgets.Label; 54 import org.eclipse.swt.widgets.Text; 55 56 /** 57 * Launch configuration tab to control the parameters of the Emulator 58 */ 59 public class EmulatorConfigTab extends AbstractLaunchConfigurationTab { 60 61 private final static String[][] NETWORK_SPEEDS = new String[][] { 62 { "Full", "full" }, //$NON-NLS-2$ 63 { "GSM", "gsm" }, //$NON-NLS-2$ 64 { "HSCSD", "hscsd" }, //$NON-NLS-2$ 65 { "GPRS", "gprs" }, //$NON-NLS-2$ 66 { "EDGE", "edge" }, //$NON-NLS-2$ 67 { "UMTS", "umts" }, //$NON-NLS-2$ 68 { "HSPDA", "hsdpa" }, //$NON-NLS-2$ 69 }; 70 71 private final static String[][] NETWORK_LATENCIES = new String[][] { 72 { "None", "none" }, //$NON-NLS-2$ 73 { "GPRS", "gprs" }, //$NON-NLS-2$ 74 { "EDGE", "edge" }, //$NON-NLS-2$ 75 { "UMTS", "umts" }, //$NON-NLS-2$ 76 }; 77 78 private Button mAutoTargetButton; 79 private Button mManualTargetButton; 80 81 private AvdSelector mPreferredAvdSelector; 82 83 private Combo mSpeedCombo; 84 85 private Combo mDelayCombo; 86 87 private Group mEmulatorOptionsGroup; 88 89 private Text mEmulatorCLOptions; 90 91 private Button mWipeDataButton; 92 93 private Button mNoBootAnimButton; 94 95 private Label mPreferredAvdLabel; 96 97 private IAndroidTarget mProjectTarget; 98 99 /** 100 * Returns the emulator ready speed option value. 101 * @param value The index of the combo selection. 102 */ getSpeed(int value)103 public static String getSpeed(int value) { 104 try { 105 return NETWORK_SPEEDS[value][1]; 106 } catch (ArrayIndexOutOfBoundsException e) { 107 return NETWORK_SPEEDS[LaunchConfigDelegate.DEFAULT_SPEED][1]; 108 } 109 } 110 111 /** 112 * Returns the emulator ready network latency value. 113 * @param value The index of the combo selection. 114 */ getDelay(int value)115 public static String getDelay(int value) { 116 try { 117 return NETWORK_LATENCIES[value][1]; 118 } catch (ArrayIndexOutOfBoundsException e) { 119 return NETWORK_LATENCIES[LaunchConfigDelegate.DEFAULT_DELAY][1]; 120 } 121 } 122 123 /** 124 * 125 */ EmulatorConfigTab()126 public EmulatorConfigTab() { 127 } 128 129 /* (non-Javadoc) 130 * @see org.eclipse.debug.ui.ILaunchConfigurationTab#createControl(org.eclipse.swt.widgets.Composite) 131 */ createControl(Composite parent)132 public void createControl(Composite parent) { 133 Font font = parent.getFont(); 134 135 // reload the AVDs to make sure we are up to date 136 try { 137 Sdk.getCurrent().getAvdManager().reloadAvds(NullSdkLog.getLogger()); 138 } catch (AndroidLocationException e1) { 139 // this happens if the AVD Manager failed to find the folder in which the AVDs are 140 // stored. There isn't much we can do at this point. 141 } 142 143 Composite topComp = new Composite(parent, SWT.NONE); 144 setControl(topComp); 145 GridLayout topLayout = new GridLayout(); 146 topLayout.numColumns = 1; 147 topLayout.verticalSpacing = 0; 148 topComp.setLayout(topLayout); 149 topComp.setFont(font); 150 151 GridData gd; 152 GridLayout layout; 153 154 // radio button for the target mode 155 Group targetModeGroup = new Group(topComp, SWT.NONE); 156 targetModeGroup.setText("Deployment Target Selection Mode"); 157 gd = new GridData(GridData.FILL_HORIZONTAL); 158 targetModeGroup.setLayoutData(gd); 159 layout = new GridLayout(); 160 layout.numColumns = 1; 161 targetModeGroup.setLayout(layout); 162 targetModeGroup.setFont(font); 163 164 mManualTargetButton = new Button(targetModeGroup, SWT.RADIO); 165 mManualTargetButton.setText("Manual"); 166 // Since there are only 2 radio buttons, we can put a listener on only one (they 167 // are both called on select and unselect event. 168 169 // add the radio button 170 mAutoTargetButton = new Button(targetModeGroup, SWT.RADIO); 171 mAutoTargetButton.setText("Automatic"); 172 mAutoTargetButton.setSelection(true); 173 mAutoTargetButton.addSelectionListener(new SelectionAdapter() { 174 // called when selection changes 175 @Override 176 public void widgetSelected(SelectionEvent e) { 177 updateLaunchConfigurationDialog(); 178 179 boolean auto = mAutoTargetButton.getSelection(); 180 mPreferredAvdSelector.setEnabled(auto); 181 mPreferredAvdLabel.setEnabled(auto); 182 } 183 }); 184 185 Composite offsetComp = new Composite(targetModeGroup, SWT.NONE); 186 offsetComp.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); 187 layout = new GridLayout(1, false); 188 layout.marginRight = layout.marginHeight = 0; 189 layout.marginLeft = 30; 190 offsetComp.setLayout(layout); 191 192 mPreferredAvdLabel = new Label(offsetComp, SWT.NONE); 193 mPreferredAvdLabel.setText("Select a preferred Android Virtual Device for deployment:"); 194 195 // create the selector with no manager, we'll reset the manager every time this is 196 // displayed to ensure we have the latest one (dialog is reused but SDK could have 197 // been changed in between. 198 mPreferredAvdSelector = new AvdSelector(offsetComp, 199 Sdk.getCurrent().getSdkLocation(), 200 null /* avd manager */, 201 DisplayMode.SIMPLE_CHECK); 202 mPreferredAvdSelector.setTableHeightHint(100); 203 mPreferredAvdSelector.setSelectionListener(new SelectionAdapter() { 204 @Override 205 public void widgetSelected(SelectionEvent e) { 206 updateLaunchConfigurationDialog(); 207 } 208 }); 209 210 // emulator size 211 mEmulatorOptionsGroup = new Group(topComp, SWT.NONE); 212 mEmulatorOptionsGroup.setText("Emulator launch parameters:"); 213 mEmulatorOptionsGroup.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); 214 layout = new GridLayout(); 215 layout.numColumns = 2; 216 mEmulatorOptionsGroup.setLayout(layout); 217 mEmulatorOptionsGroup.setFont(font); 218 219 // network options 220 new Label(mEmulatorOptionsGroup, SWT.NONE).setText("Network Speed:"); 221 222 mSpeedCombo = new Combo(mEmulatorOptionsGroup, SWT.READ_ONLY); 223 for (String[] speed : NETWORK_SPEEDS) { 224 mSpeedCombo.add(speed[0]); 225 } 226 mSpeedCombo.addSelectionListener(new SelectionAdapter() { 227 // called when selection changes 228 @Override 229 public void widgetSelected(SelectionEvent e) { 230 updateLaunchConfigurationDialog(); 231 } 232 }); 233 mSpeedCombo.pack(); 234 235 new Label(mEmulatorOptionsGroup, SWT.NONE).setText("Network Latency:"); 236 237 mDelayCombo = new Combo(mEmulatorOptionsGroup, SWT.READ_ONLY); 238 239 for (String[] delay : NETWORK_LATENCIES) { 240 mDelayCombo.add(delay[0]); 241 } 242 mDelayCombo.addSelectionListener(new SelectionAdapter() { 243 // called when selection changes 244 @Override 245 public void widgetSelected(SelectionEvent e) { 246 updateLaunchConfigurationDialog(); 247 } 248 }); 249 mDelayCombo.pack(); 250 251 // wipe data option 252 mWipeDataButton = new Button(mEmulatorOptionsGroup, SWT.CHECK); 253 mWipeDataButton.setText("Wipe User Data"); 254 mWipeDataButton.setToolTipText("Check this if you want to wipe your user data each time you start the emulator. You will be prompted for confirmation when the emulator starts."); 255 gd = new GridData(GridData.FILL_HORIZONTAL); 256 gd.horizontalSpan = 2; 257 mWipeDataButton.setLayoutData(gd); 258 mWipeDataButton.addSelectionListener(new SelectionAdapter() { 259 @Override 260 public void widgetSelected(SelectionEvent e) { 261 updateLaunchConfigurationDialog(); 262 } 263 }); 264 265 // no boot anim option 266 mNoBootAnimButton = new Button(mEmulatorOptionsGroup, SWT.CHECK); 267 mNoBootAnimButton.setText("Disable Boot Animation"); 268 mNoBootAnimButton.setToolTipText("Check this if you want to disable the boot animation. This can help the emulator start faster on slow machines."); 269 gd = new GridData(GridData.FILL_HORIZONTAL); 270 gd.horizontalSpan = 2; 271 mNoBootAnimButton.setLayoutData(gd); 272 mNoBootAnimButton.addSelectionListener(new SelectionAdapter() { 273 @Override 274 public void widgetSelected(SelectionEvent e) { 275 updateLaunchConfigurationDialog(); 276 } 277 }); 278 279 // custom command line option for emulator 280 Label l = new Label(mEmulatorOptionsGroup, SWT.NONE); 281 l.setText("Additional Emulator Command Line Options"); 282 gd = new GridData(GridData.FILL_HORIZONTAL); 283 gd.horizontalSpan = 2; 284 l.setLayoutData(gd); 285 286 mEmulatorCLOptions = new Text(mEmulatorOptionsGroup, SWT.BORDER); 287 gd = new GridData(GridData.FILL_HORIZONTAL); 288 gd.horizontalSpan = 2; 289 mEmulatorCLOptions.setLayoutData(gd); 290 mEmulatorCLOptions.addModifyListener(new ModifyListener() { 291 public void modifyText(ModifyEvent e) { 292 updateLaunchConfigurationDialog(); 293 } 294 }); 295 } 296 297 /* (non-Javadoc) 298 * @see org.eclipse.debug.ui.ILaunchConfigurationTab#getName() 299 */ getName()300 public String getName() { 301 return "Target"; 302 } 303 304 @Override getImage()305 public Image getImage() { 306 return DdmsPlugin.getImageLoader().loadImage("emulator.png", null); //$NON-NLS-1$ 307 } 308 309 updateAvdList(AvdManager avdManager)310 private void updateAvdList(AvdManager avdManager) { 311 if (avdManager == null) { 312 avdManager = Sdk.getCurrent().getAvdManager(); 313 } 314 315 mPreferredAvdSelector.setManager(avdManager); 316 mPreferredAvdSelector.setFilter(mProjectTarget); 317 mPreferredAvdSelector.refresh(false); 318 } 319 320 /* (non-Javadoc) 321 * @see org.eclipse.debug.ui.ILaunchConfigurationTab#initializeFrom(org.eclipse.debug.core.ILaunchConfiguration) 322 */ initializeFrom(ILaunchConfiguration configuration)323 public void initializeFrom(ILaunchConfiguration configuration) { 324 AvdManager avdManager = Sdk.getCurrent().getAvdManager(); 325 326 TargetMode mode = LaunchConfigDelegate.DEFAULT_TARGET_MODE; // true == automatic 327 try { 328 mode = TargetMode.getMode(configuration.getAttribute( 329 LaunchConfigDelegate.ATTR_TARGET_MODE, mode.getValue())); 330 } catch (CoreException e) { 331 // let's not do anything here, we'll use the default value 332 } 333 mAutoTargetButton.setSelection(mode.getValue()); 334 mManualTargetButton.setSelection(!mode.getValue()); 335 336 // look for the project name to get its target. 337 String stringValue = ""; 338 try { 339 stringValue = configuration.getAttribute( 340 IJavaLaunchConfigurationConstants.ATTR_PROJECT_NAME, stringValue); 341 } catch (CoreException ce) { 342 // let's not do anything here, we'll use the default value 343 } 344 345 IProject project = null; 346 347 // get the list of existing Android projects from the workspace. 348 IJavaProject[] projects = BaseProjectHelper.getAndroidProjects(); 349 if (projects != null) { 350 // look for the project whose name we read from the configuration. 351 for (IJavaProject p : projects) { 352 if (p.getElementName().equals(stringValue)) { 353 project = p.getProject(); 354 break; 355 } 356 } 357 } 358 359 // update the AVD list 360 if (project != null) { 361 mProjectTarget = Sdk.getCurrent().getTarget(project); 362 } 363 364 updateAvdList(avdManager); 365 366 stringValue = ""; 367 try { 368 stringValue = configuration.getAttribute(LaunchConfigDelegate.ATTR_AVD_NAME, 369 stringValue); 370 } catch (CoreException e) { 371 // let's not do anything here, we'll use the default value 372 } 373 374 if (stringValue != null && stringValue.length() > 0 && avdManager != null) { 375 AvdInfo targetAvd = avdManager.getAvd(stringValue, true /*validAvdOnly*/); 376 mPreferredAvdSelector.setSelection(targetAvd); 377 } else { 378 mPreferredAvdSelector.setSelection(null); 379 } 380 381 boolean value = LaunchConfigDelegate.DEFAULT_WIPE_DATA; 382 try { 383 value = configuration.getAttribute(LaunchConfigDelegate.ATTR_WIPE_DATA, value); 384 } catch (CoreException e) { 385 // let's not do anything here, we'll use the default value 386 } 387 mWipeDataButton.setSelection(value); 388 389 value = LaunchConfigDelegate.DEFAULT_NO_BOOT_ANIM; 390 try { 391 value = configuration.getAttribute(LaunchConfigDelegate.ATTR_NO_BOOT_ANIM, value); 392 } catch (CoreException e) { 393 // let's not do anything here, we'll use the default value 394 } 395 mNoBootAnimButton.setSelection(value); 396 397 int index = -1; 398 399 index = LaunchConfigDelegate.DEFAULT_SPEED; 400 try { 401 index = configuration.getAttribute(LaunchConfigDelegate.ATTR_SPEED, 402 index); 403 } catch (CoreException e) { 404 // let's not do anything here, we'll use the default value 405 } 406 if (index == -1) { 407 mSpeedCombo.clearSelection(); 408 } else { 409 mSpeedCombo.select(index); 410 } 411 412 index = LaunchConfigDelegate.DEFAULT_DELAY; 413 try { 414 index = configuration.getAttribute(LaunchConfigDelegate.ATTR_DELAY, 415 index); 416 } catch (CoreException e) { 417 // let's not do anything here, we'll put a proper value in 418 // performApply anyway 419 } 420 if (index == -1) { 421 mDelayCombo.clearSelection(); 422 } else { 423 mDelayCombo.select(index); 424 } 425 426 String commandLine = null; 427 try { 428 commandLine = configuration.getAttribute( 429 LaunchConfigDelegate.ATTR_COMMANDLINE, ""); //$NON-NLS-1$ 430 } catch (CoreException e) { 431 // let's not do anything here, we'll use the default value 432 } 433 if (commandLine != null) { 434 mEmulatorCLOptions.setText(commandLine); 435 } 436 } 437 438 /* (non-Javadoc) 439 * @see org.eclipse.debug.ui.ILaunchConfigurationTab#performApply(org.eclipse.debug.core.ILaunchConfigurationWorkingCopy) 440 */ performApply(ILaunchConfigurationWorkingCopy configuration)441 public void performApply(ILaunchConfigurationWorkingCopy configuration) { 442 configuration.setAttribute(LaunchConfigDelegate.ATTR_TARGET_MODE, 443 mAutoTargetButton.getSelection()); 444 AvdInfo avd = mPreferredAvdSelector.getSelected(); 445 if (avd != null) { 446 configuration.setAttribute(LaunchConfigDelegate.ATTR_AVD_NAME, avd.getName()); 447 } else { 448 configuration.setAttribute(LaunchConfigDelegate.ATTR_AVD_NAME, (String)null); 449 } 450 configuration.setAttribute(LaunchConfigDelegate.ATTR_SPEED, 451 mSpeedCombo.getSelectionIndex()); 452 configuration.setAttribute(LaunchConfigDelegate.ATTR_DELAY, 453 mDelayCombo.getSelectionIndex()); 454 configuration.setAttribute(LaunchConfigDelegate.ATTR_COMMANDLINE, 455 mEmulatorCLOptions.getText()); 456 configuration.setAttribute(LaunchConfigDelegate.ATTR_WIPE_DATA, 457 mWipeDataButton.getSelection()); 458 configuration.setAttribute(LaunchConfigDelegate.ATTR_NO_BOOT_ANIM, 459 mNoBootAnimButton.getSelection()); 460 } 461 462 /* (non-Javadoc) 463 * @see org.eclipse.debug.ui.ILaunchConfigurationTab#setDefaults(org.eclipse.debug.core.ILaunchConfigurationWorkingCopy) 464 */ setDefaults(ILaunchConfigurationWorkingCopy configuration)465 public void setDefaults(ILaunchConfigurationWorkingCopy configuration) { 466 configuration.setAttribute(LaunchConfigDelegate.ATTR_TARGET_MODE, 467 LaunchConfigDelegate.DEFAULT_TARGET_MODE.getValue()); 468 configuration.setAttribute(LaunchConfigDelegate.ATTR_SPEED, 469 LaunchConfigDelegate.DEFAULT_SPEED); 470 configuration.setAttribute(LaunchConfigDelegate.ATTR_DELAY, 471 LaunchConfigDelegate.DEFAULT_DELAY); 472 configuration.setAttribute(LaunchConfigDelegate.ATTR_WIPE_DATA, 473 LaunchConfigDelegate.DEFAULT_WIPE_DATA); 474 configuration.setAttribute(LaunchConfigDelegate.ATTR_NO_BOOT_ANIM, 475 LaunchConfigDelegate.DEFAULT_NO_BOOT_ANIM); 476 477 IPreferenceStore store = AdtPlugin.getDefault().getPreferenceStore(); 478 String emuOptions = store.getString(AdtPlugin.PREFS_EMU_OPTIONS); 479 configuration.setAttribute(LaunchConfigDelegate.ATTR_COMMANDLINE, emuOptions); 480 } 481 } 482