/* * Copyright (C) 2009 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.sdkuilib.internal.widgets; import com.android.prefs.AndroidLocation; import com.android.prefs.AndroidLocation.AndroidLocationException; import com.android.sdklib.IAndroidTarget; import com.android.sdklib.SdkConstants; import com.android.sdklib.SdkManager; import com.android.sdklib.internal.avd.AvdManager; import com.android.sdklib.internal.avd.HardwareProperties; import com.android.sdklib.internal.avd.AvdManager.AvdInfo; import com.android.sdklib.internal.avd.HardwareProperties.HardwareProperty; import com.android.sdkuilib.internal.repository.icons.ImageFactory; import com.android.sdkuilib.internal.widgets.AvdSelector.SdkLog; import com.android.sdkuilib.ui.GridDialog; import org.eclipse.jface.dialogs.IDialogConstants; import org.eclipse.jface.viewers.CellEditor; import org.eclipse.jface.viewers.CellLabelProvider; import org.eclipse.jface.viewers.ComboBoxCellEditor; import org.eclipse.jface.viewers.EditingSupport; import org.eclipse.jface.viewers.ISelection; import org.eclipse.jface.viewers.ISelectionChangedListener; import org.eclipse.jface.viewers.IStructuredContentProvider; import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.jface.viewers.SelectionChangedEvent; import org.eclipse.jface.viewers.TableViewer; import org.eclipse.jface.viewers.TableViewerColumn; import org.eclipse.jface.viewers.TextCellEditor; import org.eclipse.jface.viewers.Viewer; import org.eclipse.jface.viewers.ViewerCell; import org.eclipse.jface.window.Window; 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.VerifyEvent; import org.eclipse.swt.events.VerifyListener; import org.eclipse.swt.graphics.Point; 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.Control; import org.eclipse.swt.widgets.FileDialog; import org.eclipse.swt.widgets.Group; import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Shell; import org.eclipse.swt.widgets.Table; import org.eclipse.swt.widgets.TableColumn; import org.eclipse.swt.widgets.Text; import java.io.File; import java.util.ArrayList; import java.util.HashMap; import java.util.Map; import java.util.TreeMap; import java.util.Map.Entry; /** * AVD creator dialog. * * TODO: * - use SdkTargetSelector instead of Combo * - tooltips on widgets. * */ final class AvdCreationDialog extends GridDialog { private final AvdManager mAvdManager; private final TreeMap<String, IAndroidTarget> mCurrentTargets = new TreeMap<String, IAndroidTarget>(); private final Map<String, HardwareProperty> mHardwareMap; private final Map<String, String> mProperties = new HashMap<String, String>(); // a list of user-edited properties. private final ArrayList<String> mEditedProperties = new ArrayList<String>(); private Text mAvdName; private Combo mTargetCombo; private Button mSdCardSizeRadio; private Text mSdCardSize; private Combo mSdCardSizeCombo; private Text mSdCardFile; private Button mBrowseSdCard; private Button mSdCardFileRadio; private Button mSkinListRadio; private Combo mSkinCombo; private Button mSkinSizeRadio; private Text mSkinSizeWidth; private Text mSkinSizeHeight; private TableViewer mHardwareViewer; private Button mDeleteHardwareProp; private Button mForceCreation; private Button mOkButton; private Label mStatusIcon; private Label mStatusLabel; private Composite mStatusComposite; private final ImageFactory mImageFactory; /** * {@link VerifyListener} for {@link Text} widgets that should only contains numbers. */ private final VerifyListener mDigitVerifier = new VerifyListener() { public void verifyText(VerifyEvent event) { int count = event.text.length(); for (int i = 0 ; i < count ; i++) { char c = event.text.charAt(i); if (c < '0' || c > '9') { event.doit = false; return; } } } }; /** * Callback when the AVD name is changed. * Enables the force checkbox if the name is a duplicate. */ private class CreateNameModifyListener implements ModifyListener { public void modifyText(ModifyEvent e) { String name = mAvdName.getText().trim(); AvdInfo avdMatch = mAvdManager.getAvd(name, false /*validAvdOnly*/); if (avdMatch != null) { mForceCreation.setEnabled(true); } else { mForceCreation.setEnabled(false); mForceCreation.setSelection(false); } validatePage(); } } /** * {@link ModifyListener} used for live-validation of the fields content. */ private class ValidateListener extends SelectionAdapter implements ModifyListener { public void modifyText(ModifyEvent e) { validatePage(); } @Override public void widgetSelected(SelectionEvent e) { super.widgetSelected(e); validatePage(); } } protected AvdCreationDialog(Shell parentShell, AvdManager avdManager, ImageFactory imageFactory) { super(parentShell, 2, false); mAvdManager = avdManager; mImageFactory = imageFactory; File hardwareDefs = new File (avdManager.getSdkManager().getLocation() + File.separator + SdkConstants.OS_SDK_TOOLS_LIB_FOLDER, SdkConstants.FN_HARDWARE_INI); mHardwareMap = HardwareProperties.parseHardwareDefinitions( hardwareDefs, null /*sdkLog*/); } @Override public void create() { super.create(); Point p = getShell().getSize(); if (p.x < 400) { p.x = 400; } getShell().setSize(p); } @Override protected Control createContents(Composite parent) { Control control = super.createContents(parent); getShell().setText("Create new AVD"); mOkButton = getButton(IDialogConstants.OK_ID); validatePage(); return control; } @Override public void createDialogContent(final Composite parent) { GridData gd; GridLayout gl; Label label = new Label(parent, SWT.NONE); label.setText("Name:"); mAvdName = new Text(parent, SWT.BORDER); mAvdName.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); mAvdName.addModifyListener(new CreateNameModifyListener()); label = new Label(parent, SWT.NONE); label.setText("Target:"); mTargetCombo = new Combo(parent, SWT.READ_ONLY | SWT.DROP_DOWN); mTargetCombo.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); mTargetCombo.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { super.widgetSelected(e); reloadSkinCombo(); validatePage(); } }); // --- sd card group label = new Label(parent, SWT.NONE); label.setText("SD Card:"); label.setLayoutData(new GridData(GridData.BEGINNING, GridData.BEGINNING, false, false)); final Group sdCardGroup = new Group(parent, SWT.NONE); sdCardGroup.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); sdCardGroup.setLayout(new GridLayout(3, false)); mSdCardSizeRadio = new Button(sdCardGroup, SWT.RADIO); mSdCardSizeRadio.setText("Size:"); mSdCardSizeRadio.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent arg0) { boolean sizeMode = mSdCardSizeRadio.getSelection(); enableSdCardWidgets(sizeMode); validatePage(); } }); ValidateListener validateListener = new ValidateListener(); mSdCardSize = new Text(sdCardGroup, SWT.BORDER); mSdCardSize.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); mSdCardSize.addVerifyListener(mDigitVerifier); mSdCardSize.addModifyListener(validateListener); mSdCardSizeCombo = new Combo(sdCardGroup, SWT.DROP_DOWN | SWT.READ_ONLY); mSdCardSizeCombo.add("KiB"); mSdCardSizeCombo.add("MiB"); mSdCardSizeCombo.select(1); mSdCardSizeCombo.addSelectionListener(validateListener); mSdCardFileRadio = new Button(sdCardGroup, SWT.RADIO); mSdCardFileRadio.setText("File:"); mSdCardFile = new Text(sdCardGroup, SWT.BORDER); mSdCardFile.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); mSdCardFile.addModifyListener(validateListener); mBrowseSdCard = new Button(sdCardGroup, SWT.PUSH); mBrowseSdCard.setText("Browse..."); mBrowseSdCard.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent arg0) { onBrowseSdCard(); validatePage(); } }); mSdCardSizeRadio.setSelection(true); enableSdCardWidgets(true); // --- skin group label = new Label(parent, SWT.NONE); label.setText("Skin:"); label.setLayoutData(new GridData(GridData.BEGINNING, GridData.BEGINNING, false, false)); final Group skinGroup = new Group(parent, SWT.NONE); skinGroup.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); skinGroup.setLayout(new GridLayout(4, false)); mSkinListRadio = new Button(skinGroup, SWT.RADIO); mSkinListRadio.setText("Built-in:"); mSkinListRadio.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent arg0) { boolean listMode = mSkinListRadio.getSelection(); enableSkinWidgets(listMode); validatePage(); } }); mSkinCombo = new Combo(skinGroup, SWT.READ_ONLY | SWT.DROP_DOWN); mSkinCombo.setLayoutData(gd = new GridData(GridData.FILL_HORIZONTAL)); gd.horizontalSpan = 3; mSkinCombo.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent arg0) { // get the skin info loadSkin(); } }); mSkinSizeRadio = new Button(skinGroup, SWT.RADIO); mSkinSizeRadio.setText("Resolution:"); mSkinSizeWidth = new Text(skinGroup, SWT.BORDER); mSkinSizeWidth.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); mSkinSizeWidth.addVerifyListener(mDigitVerifier); mSkinSizeWidth.addModifyListener(validateListener); new Label(skinGroup, SWT.NONE).setText("x"); mSkinSizeHeight = new Text(skinGroup, SWT.BORDER); mSkinSizeHeight.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); mSkinSizeHeight.addVerifyListener(mDigitVerifier); mSkinSizeHeight.addModifyListener(validateListener); mSkinListRadio.setSelection(true); enableSkinWidgets(true); // --- hardware group label = new Label(parent, SWT.NONE); label.setText("Hardware:"); label.setLayoutData(new GridData(GridData.BEGINNING, GridData.BEGINNING, false, false)); final Group hwGroup = new Group(parent, SWT.NONE); hwGroup.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); hwGroup.setLayout(new GridLayout(2, false)); createHardwareTable(hwGroup); // composite for the side buttons Composite hwButtons = new Composite(hwGroup, SWT.NONE); hwButtons.setLayoutData(new GridData(GridData.FILL_VERTICAL)); hwButtons.setLayout(gl = new GridLayout(1, false)); gl.marginHeight = gl.marginWidth = 0; Button b = new Button(hwButtons, SWT.PUSH | SWT.FLAT); b.setText("New..."); b.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); b.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent event) { HardwarePropertyChooser dialog = new HardwarePropertyChooser(parent.getShell(), mHardwareMap, mProperties.keySet()); if (dialog.open() == Window.OK) { HardwareProperty choice = dialog.getProperty(); if (choice != null) { mProperties.put(choice.getName(), choice.getDefault()); mHardwareViewer.refresh(); } } } }); mDeleteHardwareProp = new Button(hwButtons, SWT.PUSH | SWT.FLAT); mDeleteHardwareProp.setText("Delete"); mDeleteHardwareProp.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); mDeleteHardwareProp.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent arg0) { ISelection selection = mHardwareViewer.getSelection(); if (selection instanceof IStructuredSelection) { String hwName = (String)((IStructuredSelection)selection).getFirstElement(); mProperties.remove(hwName); mHardwareViewer.refresh(); } } }); mDeleteHardwareProp.setEnabled(false); // --- end hardware group mForceCreation = new Button(parent, SWT.CHECK); mForceCreation.setText("Force create"); mForceCreation.setToolTipText("Select this to override any existing AVD"); mForceCreation.setLayoutData(new GridData(GridData.END, GridData.CENTER, true, false, 2, 1)); mForceCreation.setEnabled(false); mForceCreation.addSelectionListener(validateListener); // add a separator to separate from the ok/cancel button label = new Label(parent, SWT.SEPARATOR | SWT.HORIZONTAL); label.setLayoutData(new GridData(GridData.FILL, GridData.CENTER, true, false, 3, 1)); // add stuff for the error display mStatusComposite = new Composite(parent, SWT.NONE); mStatusComposite.setLayoutData(new GridData(GridData.FILL, GridData.CENTER, true, false, 3, 1)); mStatusComposite.setLayout(gl = new GridLayout(2, false)); gl.marginHeight = gl.marginWidth = 0; mStatusIcon = new Label(mStatusComposite, SWT.NONE); mStatusIcon.setLayoutData(new GridData(GridData.BEGINNING, GridData.BEGINNING, false, false)); mStatusLabel = new Label(mStatusComposite, SWT.NONE); mStatusLabel.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); mStatusLabel.setText(" \n "); //$NON-NLS-1$ reloadTargetCombo(); } /** * Creates the UI for the hardware properties table. * This creates the {@link Table}, and several viewers ({@link TableViewer}, * {@link TableViewerColumn}) and adds edit support for the 2nd column */ private void createHardwareTable(Composite parent) { final Table hardwareTable = new Table(parent, SWT.SINGLE | SWT.FULL_SELECTION); GridData gd = new GridData(GridData.FILL_HORIZONTAL | GridData.FILL_VERTICAL); gd.widthHint = 200; gd.heightHint = 100; hardwareTable.setLayoutData(gd); hardwareTable.setHeaderVisible(true); hardwareTable.setLinesVisible(true); // -- Table viewer mHardwareViewer = new TableViewer(hardwareTable); mHardwareViewer.addSelectionChangedListener(new ISelectionChangedListener() { public void selectionChanged(SelectionChangedEvent event) { // it's a single selection mode, we can just access the selection index // from the table directly. mDeleteHardwareProp.setEnabled(hardwareTable.getSelectionIndex() != -1); } }); // only a content provider. Use viewers per column below (for editing support) mHardwareViewer.setContentProvider(new IStructuredContentProvider() { public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { // we can just ignore this. we just use mProperties directly. } public Object[] getElements(Object arg0) { return mProperties.keySet().toArray(); } public void dispose() { // pass } }); // -- column 1: prop abstract name TableColumn col1 = new TableColumn(hardwareTable, SWT.LEFT); col1.setText("Property"); col1.setWidth(150); TableViewerColumn tvc1 = new TableViewerColumn(mHardwareViewer, col1); tvc1.setLabelProvider(new CellLabelProvider() { @Override public void update(ViewerCell cell) { HardwareProperty prop = mHardwareMap.get(cell.getElement()); cell.setText(prop != null ? prop.getAbstract() : ""); } }); // -- column 2: prop value TableColumn col2 = new TableColumn(hardwareTable, SWT.LEFT); col2.setText("Value"); col2.setWidth(50); TableViewerColumn tvc2 = new TableViewerColumn(mHardwareViewer, col2); tvc2.setLabelProvider(new CellLabelProvider() { @Override public void update(ViewerCell cell) { String value = mProperties.get(cell.getElement()); cell.setText(value != null ? value : ""); } }); // add editing support to the 2nd column tvc2.setEditingSupport(new EditingSupport(mHardwareViewer) { @Override protected void setValue(Object element, Object value) { String hardwareName = (String)element; HardwareProperty property = mHardwareMap.get(hardwareName); switch (property.getType()) { case INTEGER: mProperties.put((String)element, (String)value); break; case DISKSIZE: if (HardwareProperties.DISKSIZE_PATTERN.matcher((String)value).matches()) { mProperties.put((String)element, (String)value); } break; case BOOLEAN: int index = (Integer)value; mProperties.put((String)element, HardwareProperties.BOOLEAN_VALUES[index]); break; } mHardwareViewer.refresh(element); } @Override protected Object getValue(Object element) { String hardwareName = (String)element; HardwareProperty property = mHardwareMap.get(hardwareName); String value = mProperties.get(hardwareName); switch (property.getType()) { case INTEGER: // intended fall-through. case DISKSIZE: return value; case BOOLEAN: return HardwareProperties.getBooleanValueIndex(value); } return null; } @Override protected CellEditor getCellEditor(Object element) { String hardwareName = (String)element; HardwareProperty property = mHardwareMap.get(hardwareName); switch (property.getType()) { // TODO: custom TextCellEditor that restrict input. case INTEGER: // intended fall-through. case DISKSIZE: return new TextCellEditor(hardwareTable); case BOOLEAN: return new ComboBoxCellEditor(hardwareTable, HardwareProperties.BOOLEAN_VALUES, SWT.READ_ONLY | SWT.DROP_DOWN); } return null; } @Override protected boolean canEdit(Object element) { String hardwareName = (String)element; HardwareProperty property = mHardwareMap.get(hardwareName); return property != null; } }); mHardwareViewer.setInput(mProperties); } @Override protected Button createButton(Composite parent, int id, String label, boolean defaultButton) { if (id == IDialogConstants.OK_ID) { label = "Create AVD"; } return super.createButton(parent, id, label, defaultButton); } @Override protected void okPressed() { if (createAvd()) { super.okPressed(); } } /** * Enable or disable the sd card widgets. * @param sizeMode if true the size-based widgets are to be enabled, and the file-based ones * disabled. */ private void enableSdCardWidgets(boolean sizeMode) { mSdCardSize.setEnabled(sizeMode); mSdCardSizeCombo.setEnabled(sizeMode); mSdCardFile.setEnabled(!sizeMode); mBrowseSdCard.setEnabled(!sizeMode); } /** * Enable or disable the skin widgets. * @param listMode if true the list-based widgets are to be enabled, and the size-based ones * disabled. */ private void enableSkinWidgets(boolean listMode) { mSkinCombo.setEnabled(listMode); mSkinSizeWidth.setEnabled(!listMode); mSkinSizeHeight.setEnabled(!listMode); } private void onBrowseSdCard() { FileDialog dlg = new FileDialog(getContents().getShell(), SWT.OPEN); dlg.setText("Choose SD Card image file."); String fileName = dlg.open(); if (fileName != null) { mSdCardFile.setText(fileName); } } private void reloadTargetCombo() { String selected = null; int index = mTargetCombo.getSelectionIndex(); if (index >= 0) { selected = mTargetCombo.getItem(index); } mCurrentTargets.clear(); mTargetCombo.removeAll(); boolean found = false; index = -1; SdkManager sdkManager = mAvdManager.getSdkManager(); if (sdkManager != null) { for (IAndroidTarget target : sdkManager.getTargets()) { String name; if (target.isPlatform()) { name = String.format("%s - API Level %s", target.getName(), target.getVersion().getApiString()); } else { name = String.format("%s (%s) - API Level %s", target.getName(), target.getVendor(), target.getVersion().getApiString()); } mCurrentTargets.put(name, target); mTargetCombo.add(name); if (!found) { index++; found = name.equals(selected); } } } mTargetCombo.setEnabled(mCurrentTargets.size() > 0); if (found) { mTargetCombo.select(index); } reloadSkinCombo(); } private void reloadSkinCombo() { String selected = null; int index = mSkinCombo.getSelectionIndex(); if (index >= 0) { selected = mSkinCombo.getItem(index); } mSkinCombo.removeAll(); mSkinCombo.setEnabled(false); index = mTargetCombo.getSelectionIndex(); if (index >= 0) { String targetName = mTargetCombo.getItem(index); boolean found = false; IAndroidTarget target = mCurrentTargets.get(targetName); if (target != null) { mSkinCombo.add(String.format("Default (%s)", target.getDefaultSkin())); index = -1; for (String skin : target.getSkins()) { mSkinCombo.add(skin); if (!found) { index++; found = skin.equals(selected); } } mSkinCombo.setEnabled(true); if (found) { mSkinCombo.select(index); } else { mSkinCombo.select(0); // default loadSkin(); } } } } /** * Validates the fields, displays errors and warnings. * Enables the finish button if there are no errors. */ private void validatePage() { String error = null; // Validate AVD name String avdName = mAvdName.getText().trim(); boolean hasAvdName = avdName.length() > 0; if (hasAvdName && !AvdManager.RE_AVD_NAME.matcher(avdName).matches()) { error = String.format( "AVD name '%1$s' contains invalid characters.\nAllowed characters are: %2$s", avdName, AvdManager.CHARS_AVD_NAME); } // Validate target if (hasAvdName && error == null && mTargetCombo.getSelectionIndex() < 0) { error = "A target must be selected in order to create an AVD."; } // Validate SDCard path or value if (error == null) { // get the mode. We only need to check the file since the // verifier on the size Text will prevent invalid input boolean sdcardFileMode = mSdCardFileRadio.getSelection(); if (sdcardFileMode) { String sdName = mSdCardFile.getText().trim(); if (sdName.length() > 0 && !new File(sdName).isFile()) { error = "SD Card path isn't valid."; } } else { String valueString = mSdCardSize.getText(); if (valueString.length() > 0) { int value = Integer.parseInt(valueString); // verifier makes this // unlikely to fail. switch (mSdCardSizeCombo.getSelectionIndex()) { case 0: value *= 1024; break; case 1: value *= 1024 * 1024; break; } if (value < 9 * 1024 * 1024) { error = "SD Card size must be at least 9MB"; } } } } // validate the skin if (error == null) { // get the mode, we should only check if it's in size mode since // the built-in list mode is always valid. if (mSkinSizeRadio.getSelection()) { // need both with and heigh to be non null String width = mSkinSizeWidth.getText(); // no need for trim, since the verifier String height = mSkinSizeHeight.getText(); // rejects non digit. if (width.length() == 0 || height.length() == 0) { error = "Skin size is incorrect.\nBoth dimensions must be > 0"; } } } // Check for duplicate AVD name if (hasAvdName && error == null) { AvdInfo avdMatch = mAvdManager.getAvd(avdName, false /*validAvdOnly*/); if (avdMatch != null && !mForceCreation.getSelection()) { error = String.format( "The AVD name '%s' is already used.\n" + "Check \"Force create\" to override existing AVD.", avdName); } } // Validate the create button boolean can_create = hasAvdName && error == null; if (can_create) { can_create &= mTargetCombo.getSelectionIndex() >= 0; } mOkButton.setEnabled(can_create); // -- update UI if (error != null) { mStatusIcon.setImage(mImageFactory.getImageByName("reject_icon16.png")); mStatusLabel.setText(error); } else { mStatusIcon.setImage(null); mStatusLabel.setText(" \n "); //$NON-NLS-1$ } mStatusComposite.pack(true); } private void loadSkin() { int targetIndex = mTargetCombo.getSelectionIndex(); if (targetIndex < 0) { return; } // resolve the target. String targetName = mTargetCombo.getItem(targetIndex); IAndroidTarget target = mCurrentTargets.get(targetName); if (target == null) { return; } // get the skin name String skinName = null; int skinIndex = mSkinCombo.getSelectionIndex(); if (skinIndex < 0) { return; } else if (skinIndex == 0) { // default skin for the target skinName = target.getDefaultSkin(); } else { skinName = mSkinCombo.getItem(skinIndex); } // load the skin properties String path = target.getPath(IAndroidTarget.SKINS); File skin = new File(path, skinName); if (skin.isDirectory() == false && target.isPlatform() == false) { // it's possible the skin is in the parent target path = target.getParent().getPath(IAndroidTarget.SKINS); skin = new File(path, skinName); } if (skin.isDirectory() == false) { return; } // now get the hardware.ini from the add-on (if applicable) and from the skin // (if applicable) HashMap<String, String> hardwareValues = new HashMap<String, String>(); if (target.isPlatform() == false) { File targetHardwareFile = new File(target.getLocation(), AvdManager.HARDWARE_INI); if (targetHardwareFile.isFile()) { Map<String, String> targetHardwareConfig = SdkManager.parsePropertyFile( targetHardwareFile, null /*log*/); if (targetHardwareConfig != null) { hardwareValues.putAll(targetHardwareConfig); } } } // from the skin File skinHardwareFile = new File(skin, AvdManager.HARDWARE_INI); if (skinHardwareFile.isFile()) { Map<String, String> skinHardwareConfig = SdkManager.parsePropertyFile( skinHardwareFile, null /*log*/); if (skinHardwareConfig != null) { hardwareValues.putAll(skinHardwareConfig); } } // now set those values in the list of properties for the AVD. // We just check that none of those properties have been edited by the user yet. for (Entry<String, String> entry : hardwareValues.entrySet()) { if (mEditedProperties.contains(entry.getKey()) == false) { mProperties.put(entry.getKey(), entry.getValue()); } } mHardwareViewer.refresh(); } /** * Creates an AVD from the values in the UI. Called when the user presses the OK button. */ private boolean createAvd() { String avdName = mAvdName.getText().trim(); int targetIndex = mTargetCombo.getSelectionIndex(); // quick check on the name and the target selection if (avdName.length() == 0 || targetIndex < 0) { return false; } // resolve the target. String targetName = mTargetCombo.getItem(targetIndex); IAndroidTarget target = mCurrentTargets.get(targetName); if (target == null) { return false; } // get the SD card data from the UI. String sdName = null; if (mSdCardSizeRadio.getSelection()) { // size mode String value = mSdCardSize.getText().trim(); if (value.length() > 0) { sdName = value; // add the unit switch (mSdCardSizeCombo.getSelectionIndex()) { case 0: sdName += "K"; break; case 1: sdName += "M"; break; default: // shouldn't be here assert false; } } } else { // file mode. sdName = mSdCardFile.getText().trim(); } // get the Skin data from the UI String skinName = null; if (mSkinListRadio.getSelection()) { // built-in list provides the skin int skinIndex = mSkinCombo.getSelectionIndex(); if (skinIndex > 0) { // index 0 is the default, we don't use it skinName = mSkinCombo.getItem(skinIndex); } } else { // size mode. get both size and writes it as a skin name // thanks to validatePage() we know the content of the fields is correct skinName = mSkinSizeWidth.getText() + "x" + mSkinSizeHeight.getText(); //$NON-NLS-1$ } SdkLog log = new SdkLog(String.format("Result of creating AVD '%s':", avdName), getContents().getDisplay()); File avdFolder; try { avdFolder = new File( AndroidLocation.getFolder() + AndroidLocation.FOLDER_AVD, avdName + AvdManager.AVD_FOLDER_EXTENSION); } catch (AndroidLocationException e) { return false; } boolean force = mForceCreation.getSelection(); boolean success = false; AvdInfo avdInfo = mAvdManager.createAvd( avdFolder, avdName, target, skinName, sdName, mProperties, force, log); success = avdInfo != null; log.displayResult(success); return success; } }