2 * Copyright (C) 2009 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 package com.android.sdkuilib.internal.widgets;
19 import com.android.prefs.AndroidLocation;
20 import com.android.prefs.AndroidLocation.AndroidLocationException;
21 import com.android.sdklib.IAndroidTarget;
22 import com.android.sdklib.ISdkLog;
23 import com.android.sdklib.SdkConstants;
24 import com.android.sdklib.SdkManager;
25 import com.android.sdklib.internal.avd.AvdManager;
26 import com.android.sdklib.internal.avd.HardwareProperties;
27 import com.android.sdklib.internal.avd.AvdManager.AvdInfo;
28 import com.android.sdklib.internal.avd.HardwareProperties.HardwareProperty;
29 import com.android.sdkuilib.internal.repository.icons.ImageFactory;
30 import com.android.sdkuilib.ui.GridDialog;
32 import org.eclipse.jface.dialogs.IDialogConstants;
33 import org.eclipse.jface.viewers.CellEditor;
34 import org.eclipse.jface.viewers.CellLabelProvider;
35 import org.eclipse.jface.viewers.ComboBoxCellEditor;
36 import org.eclipse.jface.viewers.EditingSupport;
37 import org.eclipse.jface.viewers.ISelection;
38 import org.eclipse.jface.viewers.ISelectionChangedListener;
39 import org.eclipse.jface.viewers.IStructuredContentProvider;
40 import org.eclipse.jface.viewers.IStructuredSelection;
41 import org.eclipse.jface.viewers.SelectionChangedEvent;
42 import org.eclipse.jface.viewers.TableViewer;
43 import org.eclipse.jface.viewers.TableViewerColumn;
44 import org.eclipse.jface.viewers.TextCellEditor;
45 import org.eclipse.jface.viewers.Viewer;
46 import org.eclipse.jface.viewers.ViewerCell;
47 import org.eclipse.jface.window.Window;
48 import org.eclipse.swt.SWT;
49 import org.eclipse.swt.events.ModifyEvent;
50 import org.eclipse.swt.events.ModifyListener;
51 import org.eclipse.swt.events.SelectionAdapter;
52 import org.eclipse.swt.events.SelectionEvent;
53 import org.eclipse.swt.events.VerifyEvent;
54 import org.eclipse.swt.events.VerifyListener;
55 import org.eclipse.swt.graphics.Point;
56 import org.eclipse.swt.layout.GridData;
57 import org.eclipse.swt.layout.GridLayout;
58 import org.eclipse.swt.widgets.Button;
59 import org.eclipse.swt.widgets.Combo;
60 import org.eclipse.swt.widgets.Composite;
61 import org.eclipse.swt.widgets.Control;
62 import org.eclipse.swt.widgets.FileDialog;
63 import org.eclipse.swt.widgets.Group;
64 import org.eclipse.swt.widgets.Label;
65 import org.eclipse.swt.widgets.Shell;
66 import org.eclipse.swt.widgets.Table;
67 import org.eclipse.swt.widgets.TableColumn;
68 import org.eclipse.swt.widgets.Text;
71 import java.util.ArrayList;
72 import java.util.HashMap;
74 import java.util.TreeMap;
75 import java.util.Map.Entry;
81 * - use SdkTargetSelector instead of Combo
82 * - tooltips on widgets.
85 final class AvdCreationDialog extends GridDialog {
87 private final AvdManager mAvdManager;
88 private final TreeMap<String, IAndroidTarget> mCurrentTargets =
89 new TreeMap<String, IAndroidTarget>();
91 private final Map<String, HardwareProperty> mHardwareMap;
92 private final Map<String, String> mProperties = new HashMap<String, String>();
93 // a list of user-edited properties.
94 private final ArrayList<String> mEditedProperties = new ArrayList<String>();
95 private final ImageFactory mImageFactory;
96 private final ISdkLog mSdkLog;
98 private Text mAvdName;
99 private Combo mTargetCombo;
101 private Button mSdCardSizeRadio;
102 private Text mSdCardSize;
103 private Combo mSdCardSizeCombo;
105 private Text mSdCardFile;
106 private Button mBrowseSdCard;
107 private Button mSdCardFileRadio;
109 private Button mSkinListRadio;
110 private Combo mSkinCombo;
112 private Button mSkinSizeRadio;
113 private Text mSkinSizeWidth;
114 private Text mSkinSizeHeight;
116 private TableViewer mHardwareViewer;
117 private Button mDeleteHardwareProp;
119 private Button mForceCreation;
120 private Button mOkButton;
121 private Label mStatusIcon;
122 private Label mStatusLabel;
123 private Composite mStatusComposite;
126 * {@link VerifyListener} for {@link Text} widgets that should only contains numbers.
128 private final VerifyListener mDigitVerifier = new VerifyListener() {
129 public void verifyText(VerifyEvent event) {
130 int count = event.text.length();
131 for (int i = 0 ; i < count ; i++) {
132 char c = event.text.charAt(i);
133 if (c < '0' || c > '9') {
142 * Callback when the AVD name is changed.
143 * Enables the force checkbox if the name is a duplicate.
145 private class CreateNameModifyListener implements ModifyListener {
146 public void modifyText(ModifyEvent e) {
147 String name = mAvdName.getText().trim();
148 AvdInfo avdMatch = mAvdManager.getAvd(name, false /*validAvdOnly*/);
149 if (avdMatch != null) {
150 mForceCreation.setEnabled(true);
152 mForceCreation.setEnabled(false);
153 mForceCreation.setSelection(false);
161 * {@link ModifyListener} used for live-validation of the fields content.
163 private class ValidateListener extends SelectionAdapter implements ModifyListener {
164 public void modifyText(ModifyEvent e) {
169 public void widgetSelected(SelectionEvent e) {
170 super.widgetSelected(e);
175 protected AvdCreationDialog(Shell parentShell,
176 AvdManager avdManager,
177 ImageFactory imageFactory,
179 super(parentShell, 2, false);
180 mAvdManager = avdManager;
181 mImageFactory = imageFactory;
184 File hardwareDefs = null;
186 SdkManager sdkMan = avdManager.getSdkManager();
187 if (sdkMan != null) {
188 String sdkPath = sdkMan.getLocation();
189 if (sdkPath != null) {
190 hardwareDefs = new File (sdkPath + File.separator +
191 SdkConstants.OS_SDK_TOOLS_LIB_FOLDER, SdkConstants.FN_HARDWARE_INI);
195 if (hardwareDefs == null) {
196 log.error(null, "Failed to load file %s from SDK", SdkConstants.FN_HARDWARE_INI);
197 mHardwareMap = new HashMap<String, HardwareProperty>();
199 mHardwareMap = HardwareProperties.parseHardwareDefinitions(
200 hardwareDefs, null /*sdkLog*/);
205 public void create() {
208 Point p = getShell().getSize();
212 getShell().setSize(p);
216 protected Control createContents(Composite parent) {
217 Control control = super.createContents(parent);
218 getShell().setText("Create new AVD");
220 mOkButton = getButton(IDialogConstants.OK_ID);
227 public void createDialogContent(final Composite parent) {
231 Label label = new Label(parent, SWT.NONE);
232 label.setText("Name:");
234 mAvdName = new Text(parent, SWT.BORDER);
235 mAvdName.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
236 mAvdName.addModifyListener(new CreateNameModifyListener());
238 label = new Label(parent, SWT.NONE);
239 label.setText("Target:");
241 mTargetCombo = new Combo(parent, SWT.READ_ONLY | SWT.DROP_DOWN);
242 mTargetCombo.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
243 mTargetCombo.addSelectionListener(new SelectionAdapter() {
245 public void widgetSelected(SelectionEvent e) {
246 super.widgetSelected(e);
253 label = new Label(parent, SWT.NONE);
254 label.setText("SD Card:");
255 label.setLayoutData(new GridData(GridData.BEGINNING, GridData.BEGINNING,
258 final Group sdCardGroup = new Group(parent, SWT.NONE);
259 sdCardGroup.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
260 sdCardGroup.setLayout(new GridLayout(3, false));
262 mSdCardSizeRadio = new Button(sdCardGroup, SWT.RADIO);
263 mSdCardSizeRadio.setText("Size:");
264 mSdCardSizeRadio.addSelectionListener(new SelectionAdapter() {
266 public void widgetSelected(SelectionEvent arg0) {
267 boolean sizeMode = mSdCardSizeRadio.getSelection();
268 enableSdCardWidgets(sizeMode);
273 ValidateListener validateListener = new ValidateListener();
275 mSdCardSize = new Text(sdCardGroup, SWT.BORDER);
276 mSdCardSize.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
277 mSdCardSize.addVerifyListener(mDigitVerifier);
278 mSdCardSize.addModifyListener(validateListener);
280 mSdCardSizeCombo = new Combo(sdCardGroup, SWT.DROP_DOWN | SWT.READ_ONLY);
281 mSdCardSizeCombo.add("KiB");
282 mSdCardSizeCombo.add("MiB");
283 mSdCardSizeCombo.select(1);
284 mSdCardSizeCombo.addSelectionListener(validateListener);
286 mSdCardFileRadio = new Button(sdCardGroup, SWT.RADIO);
287 mSdCardFileRadio.setText("File:");
289 mSdCardFile = new Text(sdCardGroup, SWT.BORDER);
290 mSdCardFile.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
291 mSdCardFile.addModifyListener(validateListener);
293 mBrowseSdCard = new Button(sdCardGroup, SWT.PUSH);
294 mBrowseSdCard.setText("Browse...");
295 mBrowseSdCard.addSelectionListener(new SelectionAdapter() {
297 public void widgetSelected(SelectionEvent arg0) {
303 mSdCardSizeRadio.setSelection(true);
304 enableSdCardWidgets(true);
307 label = new Label(parent, SWT.NONE);
308 label.setText("Skin:");
309 label.setLayoutData(new GridData(GridData.BEGINNING, GridData.BEGINNING,
312 final Group skinGroup = new Group(parent, SWT.NONE);
313 skinGroup.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
314 skinGroup.setLayout(new GridLayout(4, false));
316 mSkinListRadio = new Button(skinGroup, SWT.RADIO);
317 mSkinListRadio.setText("Built-in:");
318 mSkinListRadio.addSelectionListener(new SelectionAdapter() {
320 public void widgetSelected(SelectionEvent arg0) {
321 boolean listMode = mSkinListRadio.getSelection();
322 enableSkinWidgets(listMode);
327 mSkinCombo = new Combo(skinGroup, SWT.READ_ONLY | SWT.DROP_DOWN);
328 mSkinCombo.setLayoutData(gd = new GridData(GridData.FILL_HORIZONTAL));
329 gd.horizontalSpan = 3;
330 mSkinCombo.addSelectionListener(new SelectionAdapter() {
332 public void widgetSelected(SelectionEvent arg0) {
338 mSkinSizeRadio = new Button(skinGroup, SWT.RADIO);
339 mSkinSizeRadio.setText("Resolution:");
341 mSkinSizeWidth = new Text(skinGroup, SWT.BORDER);
342 mSkinSizeWidth.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
343 mSkinSizeWidth.addVerifyListener(mDigitVerifier);
344 mSkinSizeWidth.addModifyListener(validateListener);
346 new Label(skinGroup, SWT.NONE).setText("x");
348 mSkinSizeHeight = new Text(skinGroup, SWT.BORDER);
349 mSkinSizeHeight.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
350 mSkinSizeHeight.addVerifyListener(mDigitVerifier);
351 mSkinSizeHeight.addModifyListener(validateListener);
353 mSkinListRadio.setSelection(true);
354 enableSkinWidgets(true);
356 // --- hardware group
357 label = new Label(parent, SWT.NONE);
358 label.setText("Hardware:");
359 label.setLayoutData(new GridData(GridData.BEGINNING, GridData.BEGINNING,
362 final Group hwGroup = new Group(parent, SWT.NONE);
363 hwGroup.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
364 hwGroup.setLayout(new GridLayout(2, false));
366 createHardwareTable(hwGroup);
368 // composite for the side buttons
369 Composite hwButtons = new Composite(hwGroup, SWT.NONE);
370 hwButtons.setLayoutData(new GridData(GridData.FILL_VERTICAL));
371 hwButtons.setLayout(gl = new GridLayout(1, false));
372 gl.marginHeight = gl.marginWidth = 0;
374 Button b = new Button(hwButtons, SWT.PUSH | SWT.FLAT);
376 b.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
377 b.addSelectionListener(new SelectionAdapter() {
379 public void widgetSelected(SelectionEvent event) {
380 HardwarePropertyChooser dialog = new HardwarePropertyChooser(parent.getShell(),
381 mHardwareMap, mProperties.keySet());
382 if (dialog.open() == Window.OK) {
383 HardwareProperty choice = dialog.getProperty();
384 if (choice != null) {
385 mProperties.put(choice.getName(), choice.getDefault());
386 mHardwareViewer.refresh();
391 mDeleteHardwareProp = new Button(hwButtons, SWT.PUSH | SWT.FLAT);
392 mDeleteHardwareProp.setText("Delete");
393 mDeleteHardwareProp.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
394 mDeleteHardwareProp.addSelectionListener(new SelectionAdapter() {
396 public void widgetSelected(SelectionEvent arg0) {
397 ISelection selection = mHardwareViewer.getSelection();
398 if (selection instanceof IStructuredSelection) {
399 String hwName = (String)((IStructuredSelection)selection).getFirstElement();
400 mProperties.remove(hwName);
401 mHardwareViewer.refresh();
405 mDeleteHardwareProp.setEnabled(false);
407 // --- end hardware group
409 mForceCreation = new Button(parent, SWT.CHECK);
410 mForceCreation.setText("Force create");
411 mForceCreation.setToolTipText("Select this to override any existing AVD");
412 mForceCreation.setLayoutData(new GridData(GridData.END, GridData.CENTER,
414 mForceCreation.setEnabled(false);
415 mForceCreation.addSelectionListener(validateListener);
417 // add a separator to separate from the ok/cancel button
418 label = new Label(parent, SWT.SEPARATOR | SWT.HORIZONTAL);
419 label.setLayoutData(new GridData(GridData.FILL, GridData.CENTER, true, false, 3, 1));
421 // add stuff for the error display
422 mStatusComposite = new Composite(parent, SWT.NONE);
423 mStatusComposite.setLayoutData(new GridData(GridData.FILL, GridData.CENTER,
425 mStatusComposite.setLayout(gl = new GridLayout(2, false));
426 gl.marginHeight = gl.marginWidth = 0;
428 mStatusIcon = new Label(mStatusComposite, SWT.NONE);
429 mStatusIcon.setLayoutData(new GridData(GridData.BEGINNING, GridData.BEGINNING,
431 mStatusLabel = new Label(mStatusComposite, SWT.NONE);
432 mStatusLabel.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
433 mStatusLabel.setText(" \n "); //$NON-NLS-1$
439 * Creates the UI for the hardware properties table.
440 * This creates the {@link Table}, and several viewers ({@link TableViewer},
441 * {@link TableViewerColumn}) and adds edit support for the 2nd column
443 private void createHardwareTable(Composite parent) {
444 final Table hardwareTable = new Table(parent, SWT.SINGLE | SWT.FULL_SELECTION);
445 GridData gd = new GridData(GridData.FILL_HORIZONTAL | GridData.FILL_VERTICAL);
448 hardwareTable.setLayoutData(gd);
449 hardwareTable.setHeaderVisible(true);
450 hardwareTable.setLinesVisible(true);
453 mHardwareViewer = new TableViewer(hardwareTable);
454 mHardwareViewer.addSelectionChangedListener(new ISelectionChangedListener() {
455 public void selectionChanged(SelectionChangedEvent event) {
456 // it's a single selection mode, we can just access the selection index
457 // from the table directly.
458 mDeleteHardwareProp.setEnabled(hardwareTable.getSelectionIndex() != -1);
462 // only a content provider. Use viewers per column below (for editing support)
463 mHardwareViewer.setContentProvider(new IStructuredContentProvider() {
464 public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
465 // we can just ignore this. we just use mProperties directly.
468 public Object[] getElements(Object arg0) {
469 return mProperties.keySet().toArray();
472 public void dispose() {
477 // -- column 1: prop abstract name
478 TableColumn col1 = new TableColumn(hardwareTable, SWT.LEFT);
479 col1.setText("Property");
481 TableViewerColumn tvc1 = new TableViewerColumn(mHardwareViewer, col1);
482 tvc1.setLabelProvider(new CellLabelProvider() {
484 public void update(ViewerCell cell) {
485 HardwareProperty prop = mHardwareMap.get(cell.getElement());
486 cell.setText(prop != null ? prop.getAbstract() : "");
490 // -- column 2: prop value
491 TableColumn col2 = new TableColumn(hardwareTable, SWT.LEFT);
492 col2.setText("Value");
494 TableViewerColumn tvc2 = new TableViewerColumn(mHardwareViewer, col2);
495 tvc2.setLabelProvider(new CellLabelProvider() {
497 public void update(ViewerCell cell) {
498 String value = mProperties.get(cell.getElement());
499 cell.setText(value != null ? value : "");
503 // add editing support to the 2nd column
504 tvc2.setEditingSupport(new EditingSupport(mHardwareViewer) {
506 protected void setValue(Object element, Object value) {
507 String hardwareName = (String)element;
508 HardwareProperty property = mHardwareMap.get(hardwareName);
509 switch (property.getType()) {
511 mProperties.put((String)element, (String)value);
514 if (HardwareProperties.DISKSIZE_PATTERN.matcher((String)value).matches()) {
515 mProperties.put((String)element, (String)value);
519 int index = (Integer)value;
520 mProperties.put((String)element, HardwareProperties.BOOLEAN_VALUES[index]);
523 mHardwareViewer.refresh(element);
527 protected Object getValue(Object element) {
528 String hardwareName = (String)element;
529 HardwareProperty property = mHardwareMap.get(hardwareName);
530 String value = mProperties.get(hardwareName);
531 switch (property.getType()) {
533 // intended fall-through.
537 return HardwareProperties.getBooleanValueIndex(value);
544 protected CellEditor getCellEditor(Object element) {
545 String hardwareName = (String)element;
546 HardwareProperty property = mHardwareMap.get(hardwareName);
547 switch (property.getType()) {
548 // TODO: custom TextCellEditor that restrict input.
550 // intended fall-through.
552 return new TextCellEditor(hardwareTable);
554 return new ComboBoxCellEditor(hardwareTable,
555 HardwareProperties.BOOLEAN_VALUES,
556 SWT.READ_ONLY | SWT.DROP_DOWN);
562 protected boolean canEdit(Object element) {
563 String hardwareName = (String)element;
564 HardwareProperty property = mHardwareMap.get(hardwareName);
565 return property != null;
570 mHardwareViewer.setInput(mProperties);
574 protected Button createButton(Composite parent, int id, String label, boolean defaultButton) {
575 if (id == IDialogConstants.OK_ID) {
576 label = "Create AVD";
579 return super.createButton(parent, id, label, defaultButton);
583 protected void okPressed() {
590 * Enable or disable the sd card widgets.
591 * @param sizeMode if true the size-based widgets are to be enabled, and the file-based ones
594 private void enableSdCardWidgets(boolean sizeMode) {
595 mSdCardSize.setEnabled(sizeMode);
596 mSdCardSizeCombo.setEnabled(sizeMode);
598 mSdCardFile.setEnabled(!sizeMode);
599 mBrowseSdCard.setEnabled(!sizeMode);
603 * Enable or disable the skin widgets.
604 * @param listMode if true the list-based widgets are to be enabled, and the size-based ones
607 private void enableSkinWidgets(boolean listMode) {
608 mSkinCombo.setEnabled(listMode);
610 mSkinSizeWidth.setEnabled(!listMode);
611 mSkinSizeHeight.setEnabled(!listMode);
615 private void onBrowseSdCard() {
616 FileDialog dlg = new FileDialog(getContents().getShell(), SWT.OPEN);
617 dlg.setText("Choose SD Card image file.");
619 String fileName = dlg.open();
620 if (fileName != null) {
621 mSdCardFile.setText(fileName);
625 private void reloadTargetCombo() {
626 String selected = null;
627 int index = mTargetCombo.getSelectionIndex();
629 selected = mTargetCombo.getItem(index);
632 mCurrentTargets.clear();
633 mTargetCombo.removeAll();
635 boolean found = false;
638 SdkManager sdkManager = mAvdManager.getSdkManager();
639 if (sdkManager != null) {
640 for (IAndroidTarget target : sdkManager.getTargets()) {
642 if (target.isPlatform()) {
643 name = String.format("%s - API Level %s",
645 target.getVersion().getApiString());
647 name = String.format("%s (%s) - API Level %s",
650 target.getVersion().getApiString());
652 mCurrentTargets.put(name, target);
653 mTargetCombo.add(name);
656 found = name.equals(selected);
661 mTargetCombo.setEnabled(mCurrentTargets.size() > 0);
664 mTargetCombo.select(index);
670 private void reloadSkinCombo() {
671 String selected = null;
672 int index = mSkinCombo.getSelectionIndex();
674 selected = mSkinCombo.getItem(index);
677 mSkinCombo.removeAll();
678 mSkinCombo.setEnabled(false);
680 index = mTargetCombo.getSelectionIndex();
683 String targetName = mTargetCombo.getItem(index);
685 boolean found = false;
686 IAndroidTarget target = mCurrentTargets.get(targetName);
687 if (target != null) {
688 mSkinCombo.add(String.format("Default (%s)", target.getDefaultSkin()));
691 for (String skin : target.getSkins()) {
692 mSkinCombo.add(skin);
695 found = skin.equals(selected);
699 mSkinCombo.setEnabled(true);
702 mSkinCombo.select(index);
704 mSkinCombo.select(0); // default
712 * Validates the fields, displays errors and warnings.
713 * Enables the finish button if there are no errors.
715 private void validatePage() {
719 String avdName = mAvdName.getText().trim();
720 boolean hasAvdName = avdName.length() > 0;
721 if (hasAvdName && !AvdManager.RE_AVD_NAME.matcher(avdName).matches()) {
722 error = String.format(
723 "AVD name '%1$s' contains invalid characters.\nAllowed characters are: %2$s",
724 avdName, AvdManager.CHARS_AVD_NAME);
728 if (hasAvdName && error == null && mTargetCombo.getSelectionIndex() < 0) {
729 error = "A target must be selected in order to create an AVD.";
732 // Validate SDCard path or value
734 // get the mode. We only need to check the file since the
735 // verifier on the size Text will prevent invalid input
736 boolean sdcardFileMode = mSdCardFileRadio.getSelection();
737 if (sdcardFileMode) {
738 String sdName = mSdCardFile.getText().trim();
739 if (sdName.length() > 0 && !new File(sdName).isFile()) {
740 error = "SD Card path isn't valid.";
743 String valueString = mSdCardSize.getText();
744 if (valueString.length() > 0) {
745 int value = Integer.parseInt(valueString); // verifier makes this
747 switch (mSdCardSizeCombo.getSelectionIndex()) {
752 value *= 1024 * 1024;
756 if (value < 9 * 1024 * 1024) {
757 error = "SD Card size must be at least 9MB";
765 // get the mode, we should only check if it's in size mode since
766 // the built-in list mode is always valid.
767 if (mSkinSizeRadio.getSelection()) {
768 // need both with and heigh to be non null
769 String width = mSkinSizeWidth.getText(); // no need for trim, since the verifier
770 String height = mSkinSizeHeight.getText(); // rejects non digit.
772 if (width.length() == 0 || height.length() == 0) {
773 error = "Skin size is incorrect.\nBoth dimensions must be > 0";
778 // Check for duplicate AVD name
779 if (hasAvdName && error == null) {
780 AvdInfo avdMatch = mAvdManager.getAvd(avdName, false /*validAvdOnly*/);
781 if (avdMatch != null && !mForceCreation.getSelection()) {
782 error = String.format(
783 "The AVD name '%s' is already used.\n" +
784 "Check \"Force create\" to override existing AVD.",
789 // Validate the create button
790 boolean can_create = hasAvdName && error == null;
792 can_create &= mTargetCombo.getSelectionIndex() >= 0;
794 mOkButton.setEnabled(can_create);
798 mStatusIcon.setImage(mImageFactory.getImageByName("reject_icon16.png"));
799 mStatusLabel.setText(error);
801 mStatusIcon.setImage(null);
802 mStatusLabel.setText(" \n "); //$NON-NLS-1$
805 mStatusComposite.pack(true);
808 private void loadSkin() {
809 int targetIndex = mTargetCombo.getSelectionIndex();
810 if (targetIndex < 0) {
814 // resolve the target.
815 String targetName = mTargetCombo.getItem(targetIndex);
816 IAndroidTarget target = mCurrentTargets.get(targetName);
817 if (target == null) {
822 String skinName = null;
823 int skinIndex = mSkinCombo.getSelectionIndex();
826 } else if (skinIndex == 0) { // default skin for the target
827 skinName = target.getDefaultSkin();
829 skinName = mSkinCombo.getItem(skinIndex);
832 // load the skin properties
833 String path = target.getPath(IAndroidTarget.SKINS);
834 File skin = new File(path, skinName);
835 if (skin.isDirectory() == false && target.isPlatform() == false) {
836 // it's possible the skin is in the parent target
837 path = target.getParent().getPath(IAndroidTarget.SKINS);
838 skin = new File(path, skinName);
841 if (skin.isDirectory() == false) {
845 // now get the hardware.ini from the add-on (if applicable) and from the skin
847 HashMap<String, String> hardwareValues = new HashMap<String, String>();
848 if (target.isPlatform() == false) {
849 File targetHardwareFile = new File(target.getLocation(), AvdManager.HARDWARE_INI);
850 if (targetHardwareFile.isFile()) {
851 Map<String, String> targetHardwareConfig = SdkManager.parsePropertyFile(
852 targetHardwareFile, null /*log*/);
853 if (targetHardwareConfig != null) {
854 hardwareValues.putAll(targetHardwareConfig);
860 File skinHardwareFile = new File(skin, AvdManager.HARDWARE_INI);
861 if (skinHardwareFile.isFile()) {
862 Map<String, String> skinHardwareConfig = SdkManager.parsePropertyFile(
863 skinHardwareFile, null /*log*/);
864 if (skinHardwareConfig != null) {
865 hardwareValues.putAll(skinHardwareConfig);
869 // now set those values in the list of properties for the AVD.
870 // We just check that none of those properties have been edited by the user yet.
871 for (Entry<String, String> entry : hardwareValues.entrySet()) {
872 if (mEditedProperties.contains(entry.getKey()) == false) {
873 mProperties.put(entry.getKey(), entry.getValue());
877 mHardwareViewer.refresh();
881 * Creates an AVD from the values in the UI. Called when the user presses the OK button.
883 private boolean createAvd() {
884 String avdName = mAvdName.getText().trim();
885 int targetIndex = mTargetCombo.getSelectionIndex();
887 // quick check on the name and the target selection
888 if (avdName.length() == 0 || targetIndex < 0) {
892 // resolve the target.
893 String targetName = mTargetCombo.getItem(targetIndex);
894 IAndroidTarget target = mCurrentTargets.get(targetName);
895 if (target == null) {
899 // get the SD card data from the UI.
900 String sdName = null;
901 if (mSdCardSizeRadio.getSelection()) {
903 String value = mSdCardSize.getText().trim();
904 if (value.length() > 0) {
907 switch (mSdCardSizeCombo.getSelectionIndex()) {
921 sdName = mSdCardFile.getText().trim();
924 // get the Skin data from the UI
925 String skinName = null;
926 if (mSkinListRadio.getSelection()) {
927 // built-in list provides the skin
928 int skinIndex = mSkinCombo.getSelectionIndex();
930 // index 0 is the default, we don't use it
931 skinName = mSkinCombo.getItem(skinIndex);
934 // size mode. get both size and writes it as a skin name
935 // thanks to validatePage() we know the content of the fields is correct
936 skinName = mSkinSizeWidth.getText() + "x" + mSkinSizeHeight.getText(); //$NON-NLS-1$
939 ISdkLog log = mSdkLog;
940 if (log == null || log instanceof MessageBoxLog) {
941 // If the current logger is a message box, we use our own (to make sure
942 // to display errors right away and customize the title).
943 log = new MessageBoxLog(
944 String.format("Result of creating AVD '%s':", avdName),
945 getContents().getDisplay(),
946 false /*logErrorsOnly*/);
949 File avdFolder = null;
951 avdFolder = new File(
952 AndroidLocation.getFolder() + AndroidLocation.FOLDER_AVD,
953 avdName + AvdManager.AVD_FOLDER_EXTENSION);
954 } catch (AndroidLocationException e) {
958 boolean force = mForceCreation.getSelection();
960 boolean success = false;
961 AvdInfo avdInfo = mAvdManager.createAvd(
971 success = avdInfo != null;
973 if (log instanceof MessageBoxLog) {
974 ((MessageBoxLog) log).displayResult(success);