/* * Copyright (C) 2007 The Android Open Source Project * * Licensed under the Eclipse Public License, Version 1.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.eclipse.org/org/documents/epl-v10.php * * 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.adt.internal.launch; import com.android.ddmuilib.ImageLoader; import com.android.ide.eclipse.adt.AdtPlugin; import com.android.ide.eclipse.adt.internal.editors.manifest.ManifestInfo; import com.android.ide.eclipse.adt.internal.launch.AndroidLaunchConfiguration.TargetMode; import com.android.ide.eclipse.adt.internal.launch.AvdCompatibility.Compatibility; import com.android.ide.eclipse.adt.internal.preferences.AdtPrefs; import com.android.ide.eclipse.adt.internal.project.BaseProjectHelper; import com.android.ide.eclipse.adt.internal.sdk.AdtConsoleSdkLog; import com.android.ide.eclipse.adt.internal.sdk.Sdk; import com.android.prefs.AndroidLocation.AndroidLocationException; import com.android.sdklib.AndroidVersion; import com.android.sdklib.IAndroidTarget; import com.android.sdklib.internal.avd.AvdInfo; import com.android.sdklib.internal.avd.AvdManager; import com.android.sdkuilib.internal.widgets.AvdSelector; import com.android.sdkuilib.internal.widgets.AvdSelector.DisplayMode; import com.android.sdkuilib.internal.widgets.AvdSelector.IAvdFilter; import com.android.utils.NullLogger; import org.eclipse.core.resources.IProject; import org.eclipse.core.runtime.CoreException; import org.eclipse.debug.core.ILaunchConfiguration; import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy; import org.eclipse.debug.ui.AbstractLaunchConfigurationTab; import org.eclipse.jdt.core.IJavaProject; import org.eclipse.jdt.launching.IJavaLaunchConfigurationConstants; import org.eclipse.jface.preference.IPreferenceStore; import org.eclipse.swt.SWT; import org.eclipse.swt.events.ModifyEvent; import org.eclipse.swt.events.ModifyListener; import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.events.SelectionListener; import org.eclipse.swt.graphics.Font; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Combo; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Group; import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Text; /** * Launch configuration tab to control the parameters of the Emulator */ public class EmulatorConfigTab extends AbstractLaunchConfigurationTab { private final static String[][] NETWORK_SPEEDS = new String[][] { { "Full", "full" }, //$NON-NLS-2$ { "GSM", "gsm" }, //$NON-NLS-2$ { "HSCSD", "hscsd" }, //$NON-NLS-2$ { "GPRS", "gprs" }, //$NON-NLS-2$ { "EDGE", "edge" }, //$NON-NLS-2$ { "UMTS", "umts" }, //$NON-NLS-2$ { "HSPDA", "hsdpa" }, //$NON-NLS-2$ }; private final static String[][] NETWORK_LATENCIES = new String[][] { { "None", "none" }, //$NON-NLS-2$ { "GPRS", "gprs" }, //$NON-NLS-2$ { "EDGE", "edge" }, //$NON-NLS-2$ { "UMTS", "umts" }, //$NON-NLS-2$ }; private Button mAutoTargetButton; private Button mManualTargetButton; private AvdSelector mPreferredAvdSelector; private Combo mSpeedCombo; private Combo mDelayCombo; private Group mEmulatorOptionsGroup; private Text mEmulatorCLOptions; private Button mWipeDataButton; private Button mNoBootAnimButton; private Label mPreferredAvdLabel; private IAndroidTarget mProjectTarget; private AndroidVersion mProjectMinApiVersion; private boolean mSupportMultiDeviceLaunch; private Button mAllDevicesTargetButton; private Combo mDeviceTypeCombo; private static final String DEVICES_AND_EMULATORS = "Active devices and AVD's"; private static final String EMULATORS_ONLY = "Active AVD's"; private static final String DEVICES_ONLY = "Active devices"; /** * Returns the emulator ready speed option value. * @param value The index of the combo selection. */ public static String getSpeed(int value) { try { return NETWORK_SPEEDS[value][1]; } catch (ArrayIndexOutOfBoundsException e) { return NETWORK_SPEEDS[LaunchConfigDelegate.DEFAULT_SPEED][1]; } } /** * Returns the emulator ready network latency value. * @param value The index of the combo selection. */ public static String getDelay(int value) { try { return NETWORK_LATENCIES[value][1]; } catch (ArrayIndexOutOfBoundsException e) { return NETWORK_LATENCIES[LaunchConfigDelegate.DEFAULT_DELAY][1]; } } /** * */ public EmulatorConfigTab(boolean supportMultiDeviceLaunch) { mSupportMultiDeviceLaunch = supportMultiDeviceLaunch; } /** * @wbp.parser.entryPoint */ @Override public void createControl(Composite parent) { Font font = parent.getFont(); // Reload the AVDs to make sure we are up to date try { // SDK can be null if the user opens the dialog before ADT finished // initializing the SDK itself. In this case just don't reload anything // so there's nothing obsolete yet. Sdk sdk = Sdk.getCurrent(); if (sdk != null) { AvdManager avdMan = sdk.getAvdManager(); assert avdMan != null; avdMan.reloadAvds(NullLogger.getLogger()); } } catch (AndroidLocationException e1) { // this happens if the AVD Manager failed to find the folder in which the AVDs are // stored. There isn't much we can do at this point. } Composite topComp = new Composite(parent, SWT.NONE); setControl(topComp); GridLayout topLayout = new GridLayout(); topLayout.numColumns = 1; topLayout.verticalSpacing = 0; topComp.setLayout(topLayout); topComp.setFont(font); GridData gd; GridLayout layout; // radio button for the target mode Group targetModeGroup = new Group(topComp, SWT.NONE); targetModeGroup.setText("Deployment Target Selection Mode"); gd = new GridData(GridData.FILL_HORIZONTAL); targetModeGroup.setLayoutData(gd); layout = new GridLayout(); layout.numColumns = 1; targetModeGroup.setLayout(layout); targetModeGroup.setFont(font); mManualTargetButton = new Button(targetModeGroup, SWT.RADIO); mManualTargetButton.setText("Always prompt to pick device"); mAllDevicesTargetButton = new Button(targetModeGroup, SWT.RADIO); mAllDevicesTargetButton.setText("Launch on all compatible devices/AVD's"); mAllDevicesTargetButton.setEnabled(mSupportMultiDeviceLaunch); Composite deviceTypeOffsetComp = new Composite(targetModeGroup, SWT.NONE); deviceTypeOffsetComp.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); layout = new GridLayout(1, false); layout.marginRight = layout.marginHeight = 0; layout.marginLeft = 30; deviceTypeOffsetComp.setLayout(layout); mDeviceTypeCombo = new Combo(deviceTypeOffsetComp, SWT.READ_ONLY); mDeviceTypeCombo.setItems(new String[] { DEVICES_AND_EMULATORS, EMULATORS_ONLY, DEVICES_ONLY, }); mDeviceTypeCombo.select(0); mDeviceTypeCombo.setEnabled(false); // add the radio button mAutoTargetButton = new Button(targetModeGroup, SWT.RADIO); mAutoTargetButton.setText("Automatically pick compatible device: " + "Always uses preferred AVD if set below, " + "launches on compatible device/AVD otherwise."); mAutoTargetButton.setSelection(true); SelectionListener targetModeChangeListener = new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { targetModeChanged(); } }; mAutoTargetButton.addSelectionListener(targetModeChangeListener); mAllDevicesTargetButton.addSelectionListener(targetModeChangeListener); mManualTargetButton.addSelectionListener(targetModeChangeListener); Composite avdOffsetComp = new Composite(targetModeGroup, SWT.NONE); avdOffsetComp.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); layout = new GridLayout(1, false); layout.marginRight = layout.marginHeight = 0; layout.marginLeft = 30; avdOffsetComp.setLayout(layout); mPreferredAvdLabel = new Label(avdOffsetComp, SWT.NONE); mPreferredAvdLabel.setText("Select a preferred Android Virtual Device for deployment:"); // create the selector with no manager, we'll reset the manager every time this is // displayed to ensure we have the latest one (dialog is reused but SDK could have // been changed in between. mPreferredAvdSelector = new AvdSelector(avdOffsetComp, Sdk.getCurrent().getSdkLocation(), null /* avd manager */, DisplayMode.SIMPLE_CHECK, new AdtConsoleSdkLog()); mPreferredAvdSelector.setTableHeightHint(100); SelectionListener listener = new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { updateLaunchConfigurationDialog(); } }; mPreferredAvdSelector.setSelectionListener(listener); mDeviceTypeCombo.addSelectionListener(listener); // emulator size mEmulatorOptionsGroup = new Group(topComp, SWT.NONE); mEmulatorOptionsGroup.setText("Emulator launch parameters:"); mEmulatorOptionsGroup.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); layout = new GridLayout(); layout.numColumns = 2; mEmulatorOptionsGroup.setLayout(layout); mEmulatorOptionsGroup.setFont(font); // Explanation Label l = new Label(mEmulatorOptionsGroup, SWT.NONE); l.setText("If no compatible and active devices or AVD's are found, then an AVD " + "might be launched. Provide options for the AVD launch below."); gd = new GridData(); gd.horizontalSpan = 2; l.setLayoutData(gd); // network options new Label(mEmulatorOptionsGroup, SWT.NONE).setText("Network Speed:"); mSpeedCombo = new Combo(mEmulatorOptionsGroup, SWT.READ_ONLY); for (String[] speed : NETWORK_SPEEDS) { mSpeedCombo.add(speed[0]); } mSpeedCombo.addSelectionListener(new SelectionAdapter() { // called when selection changes @Override public void widgetSelected(SelectionEvent e) { updateLaunchConfigurationDialog(); } }); mSpeedCombo.pack(); new Label(mEmulatorOptionsGroup, SWT.NONE).setText("Network Latency:"); mDelayCombo = new Combo(mEmulatorOptionsGroup, SWT.READ_ONLY); for (String[] delay : NETWORK_LATENCIES) { mDelayCombo.add(delay[0]); } mDelayCombo.addSelectionListener(new SelectionAdapter() { // called when selection changes @Override public void widgetSelected(SelectionEvent e) { updateLaunchConfigurationDialog(); } }); mDelayCombo.pack(); // wipe data option mWipeDataButton = new Button(mEmulatorOptionsGroup, SWT.CHECK); mWipeDataButton.setText("Wipe User Data"); 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."); gd = new GridData(GridData.FILL_HORIZONTAL); gd.horizontalSpan = 2; mWipeDataButton.setLayoutData(gd); mWipeDataButton.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { updateLaunchConfigurationDialog(); } }); // no boot anim option mNoBootAnimButton = new Button(mEmulatorOptionsGroup, SWT.CHECK); mNoBootAnimButton.setText("Disable Boot Animation"); mNoBootAnimButton.setToolTipText("Check this if you want to disable the boot animation. This can help the emulator start faster on slow machines."); gd = new GridData(GridData.FILL_HORIZONTAL); gd.horizontalSpan = 2; mNoBootAnimButton.setLayoutData(gd); mNoBootAnimButton.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { updateLaunchConfigurationDialog(); } }); // custom command line option for emulator l = new Label(mEmulatorOptionsGroup, SWT.NONE); l.setText("Additional Emulator Command Line Options"); gd = new GridData(GridData.FILL_HORIZONTAL); gd.horizontalSpan = 2; l.setLayoutData(gd); mEmulatorCLOptions = new Text(mEmulatorOptionsGroup, SWT.BORDER); gd = new GridData(GridData.FILL_HORIZONTAL); gd.horizontalSpan = 2; mEmulatorCLOptions.setLayoutData(gd); mEmulatorCLOptions.addModifyListener(new ModifyListener() { @Override public void modifyText(ModifyEvent e) { updateLaunchConfigurationDialog(); } }); } private void targetModeChanged() { updateLaunchConfigurationDialog(); boolean auto = mAutoTargetButton.getSelection(); mPreferredAvdSelector.setEnabled(auto); mPreferredAvdLabel.setEnabled(auto); boolean all = mAllDevicesTargetButton.getSelection(); mDeviceTypeCombo.setEnabled(all); } /* (non-Javadoc) * @see org.eclipse.debug.ui.ILaunchConfigurationTab#getName() */ @Override public String getName() { return "Target"; } @Override public Image getImage() { return ImageLoader.getDdmUiLibLoader().loadImage("emulator.png", null); //$NON-NLS-1$ } private void updateAvdList(AvdManager avdManager) { if (avdManager == null) { avdManager = Sdk.getCurrent().getAvdManager(); } mPreferredAvdSelector.setManager(avdManager); mPreferredAvdSelector.refresh(false); mPreferredAvdSelector.setFilter(new IAvdFilter() { @Override public void prepare() { } @Override public void cleanup() { } @Override public boolean accept(AvdInfo avd) { AvdCompatibility.Compatibility c = AvdCompatibility.canRun(avd, mProjectTarget, mProjectMinApiVersion); return (c == Compatibility.NO) ? false : true; } }); } /* (non-Javadoc) * @see org.eclipse.debug.ui.ILaunchConfigurationTab#initializeFrom(org.eclipse.debug.core.ILaunchConfiguration) */ @Override public void initializeFrom(ILaunchConfiguration configuration) { AvdManager avdManager = Sdk.getCurrent().getAvdManager(); TargetMode mode = AndroidLaunchConfiguration.parseTargetMode(configuration, LaunchConfigDelegate.DEFAULT_TARGET_MODE); boolean multipleDevices = mode.isMultiDevice(); if (multipleDevices && !mSupportMultiDeviceLaunch) { // The launch config says to run on multiple devices, but this launch type does not // suppport multiple devices. In such a case, switch back to default mode. // This could happen if a launch config used for Run is then used for Debug. multipleDevices = false; mode = LaunchConfigDelegate.DEFAULT_TARGET_MODE; } mAutoTargetButton.setSelection(mode == TargetMode.AUTO); mManualTargetButton.setSelection(mode == TargetMode.MANUAL); mAllDevicesTargetButton.setSelection(multipleDevices); targetModeChanged(); mDeviceTypeCombo.setEnabled(multipleDevices); if (multipleDevices) { int index = 0; if (mode == TargetMode.ALL_EMULATORS) { index = 1; } else if (mode == TargetMode.ALL_DEVICES) { index = 2; } mDeviceTypeCombo.select(index); } // look for the project name to get its target. String stringValue = ""; try { stringValue = configuration.getAttribute( IJavaLaunchConfigurationConstants.ATTR_PROJECT_NAME, stringValue); } catch (CoreException ce) { // let's not do anything here, we'll use the default value } IProject project = null; // get the list of existing Android projects from the workspace. IJavaProject[] projects = BaseProjectHelper.getAndroidProjects(null /*filter*/); if (projects != null) { // look for the project whose name we read from the configuration. for (IJavaProject p : projects) { if (p.getElementName().equals(stringValue)) { project = p.getProject(); break; } } } // update the AVD list if (project != null) { mProjectTarget = Sdk.getCurrent().getTarget(project); ManifestInfo mi = ManifestInfo.get(project); final int minApiLevel = mi.getMinSdkVersion(); final String minApiCodeName = mi.getMinSdkCodeName(); mProjectMinApiVersion = new AndroidVersion(minApiLevel, minApiCodeName); } updateAvdList(avdManager); stringValue = ""; try { stringValue = configuration.getAttribute(LaunchConfigDelegate.ATTR_AVD_NAME, stringValue); } catch (CoreException e) { // let's not do anything here, we'll use the default value } if (stringValue != null && stringValue.length() > 0 && avdManager != null) { AvdInfo targetAvd = avdManager.getAvd(stringValue, true /*validAvdOnly*/); mPreferredAvdSelector.setSelection(targetAvd); } else { mPreferredAvdSelector.setSelection(null); } boolean value = LaunchConfigDelegate.DEFAULT_WIPE_DATA; try { value = configuration.getAttribute(LaunchConfigDelegate.ATTR_WIPE_DATA, value); } catch (CoreException e) { // let's not do anything here, we'll use the default value } mWipeDataButton.setSelection(value); value = LaunchConfigDelegate.DEFAULT_NO_BOOT_ANIM; try { value = configuration.getAttribute(LaunchConfigDelegate.ATTR_NO_BOOT_ANIM, value); } catch (CoreException e) { // let's not do anything here, we'll use the default value } mNoBootAnimButton.setSelection(value); int index = -1; index = LaunchConfigDelegate.DEFAULT_SPEED; try { index = configuration.getAttribute(LaunchConfigDelegate.ATTR_SPEED, index); } catch (CoreException e) { // let's not do anything here, we'll use the default value } if (index == -1) { mSpeedCombo.clearSelection(); } else { mSpeedCombo.select(index); } index = LaunchConfigDelegate.DEFAULT_DELAY; try { index = configuration.getAttribute(LaunchConfigDelegate.ATTR_DELAY, index); } catch (CoreException e) { // let's not do anything here, we'll put a proper value in // performApply anyway } if (index == -1) { mDelayCombo.clearSelection(); } else { mDelayCombo.select(index); } String commandLine = null; try { commandLine = configuration.getAttribute( LaunchConfigDelegate.ATTR_COMMANDLINE, ""); //$NON-NLS-1$ } catch (CoreException e) { // let's not do anything here, we'll use the default value } if (commandLine != null) { mEmulatorCLOptions.setText(commandLine); } } /* (non-Javadoc) * @see org.eclipse.debug.ui.ILaunchConfigurationTab#performApply(org.eclipse.debug.core.ILaunchConfigurationWorkingCopy) */ @Override public void performApply(ILaunchConfigurationWorkingCopy configuration) { configuration.setAttribute(LaunchConfigDelegate.ATTR_TARGET_MODE, getCurrentTargetMode().toString()); AvdInfo avd = mPreferredAvdSelector.getSelected(); if (avd != null) { configuration.setAttribute(LaunchConfigDelegate.ATTR_AVD_NAME, avd.getName()); } else { configuration.setAttribute(LaunchConfigDelegate.ATTR_AVD_NAME, (String)null); } configuration.setAttribute(LaunchConfigDelegate.ATTR_SPEED, mSpeedCombo.getSelectionIndex()); configuration.setAttribute(LaunchConfigDelegate.ATTR_DELAY, mDelayCombo.getSelectionIndex()); configuration.setAttribute(LaunchConfigDelegate.ATTR_COMMANDLINE, mEmulatorCLOptions.getText()); configuration.setAttribute(LaunchConfigDelegate.ATTR_WIPE_DATA, mWipeDataButton.getSelection()); configuration.setAttribute(LaunchConfigDelegate.ATTR_NO_BOOT_ANIM, mNoBootAnimButton.getSelection()); } private TargetMode getCurrentTargetMode() { if (mAutoTargetButton.getSelection()) { return TargetMode.AUTO; } else if (mManualTargetButton.getSelection()) { return TargetMode.MANUAL; } else { String selection = mDeviceTypeCombo.getText(); if (DEVICES_AND_EMULATORS.equals(selection)) { return TargetMode.ALL_DEVICES_AND_EMULATORS; } else if (DEVICES_ONLY.equals(selection)) { return TargetMode.ALL_DEVICES; } else if (EMULATORS_ONLY.equals(selection)) { return TargetMode.ALL_EMULATORS; } } return TargetMode.AUTO; } /* (non-Javadoc) * @see org.eclipse.debug.ui.ILaunchConfigurationTab#setDefaults(org.eclipse.debug.core.ILaunchConfigurationWorkingCopy) */ @Override public void setDefaults(ILaunchConfigurationWorkingCopy configuration) { configuration.setAttribute(LaunchConfigDelegate.ATTR_TARGET_MODE, LaunchConfigDelegate.DEFAULT_TARGET_MODE.toString()); configuration.setAttribute(LaunchConfigDelegate.ATTR_SPEED, LaunchConfigDelegate.DEFAULT_SPEED); configuration.setAttribute(LaunchConfigDelegate.ATTR_DELAY, LaunchConfigDelegate.DEFAULT_DELAY); configuration.setAttribute(LaunchConfigDelegate.ATTR_WIPE_DATA, LaunchConfigDelegate.DEFAULT_WIPE_DATA); configuration.setAttribute(LaunchConfigDelegate.ATTR_NO_BOOT_ANIM, LaunchConfigDelegate.DEFAULT_NO_BOOT_ANIM); IPreferenceStore store = AdtPlugin.getDefault().getPreferenceStore(); String emuOptions = store.getString(AdtPrefs.PREFS_EMU_OPTIONS); configuration.setAttribute(LaunchConfigDelegate.ATTR_COMMANDLINE, emuOptions); } }