blob: 20bdfad897cf9c010e187a0eb7e8a560770a706d [file] [log] [blame]
/*
* 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);
mSdCardSizeCombo = new Combo(sdCardGroup, SWT.DROP_DOWN | SWT.READ_ONLY);
mSdCardSizeCombo.add("KiB");
mSdCardSizeCombo.add("MiB");
mSdCardSizeCombo.select(1);
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.";
}
}
}
// 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;
}
}