ADT #1820114: Provide a quick UI to edit AVD.
This is temporary and will be replaced once we get the standalone AVD UI.
This commit is contained in:
BIN
tools/eclipse/plugins/com.android.ide.eclipse.adt/icons/avd_manager.png
Executable file
BIN
tools/eclipse/plugins/com.android.ide.eclipse.adt/icons/avd_manager.png
Executable file
Binary file not shown.
|
After Width: | Height: | Size: 135 B |
@@ -538,6 +538,22 @@
|
|||||||
label="Refactor">
|
label="Refactor">
|
||||||
</menu>
|
</menu>
|
||||||
</actionSet>
|
</actionSet>
|
||||||
|
<actionSet
|
||||||
|
description="Android AVD Manager"
|
||||||
|
id="adt.actionSet.avdManager"
|
||||||
|
label="Android AVD Manager"
|
||||||
|
visible="true">
|
||||||
|
<action
|
||||||
|
class="com.android.ide.eclipse.adt.wizards.actions.AvdManagerAction"
|
||||||
|
icon="icons/avd_manager.png"
|
||||||
|
id="com.android.ide.eclipse.adt.ui.avdmanager"
|
||||||
|
label="Android AVD Manager"
|
||||||
|
menubarPath="Window/additions"
|
||||||
|
style="push"
|
||||||
|
toolbarPath="android_project"
|
||||||
|
tooltip="Opens the Android Virtual Device (AVD) Manager">
|
||||||
|
</action>
|
||||||
|
</actionSet>
|
||||||
</extension>
|
</extension>
|
||||||
<extension
|
<extension
|
||||||
point="org.eclipse.debug.core.launchDelegates">
|
point="org.eclipse.debug.core.launchDelegates">
|
||||||
|
|||||||
@@ -1386,8 +1386,6 @@ public class AdtPlugin extends AbstractUIPlugin {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Pings the usage start server.
|
* Pings the usage start server.
|
||||||
* @param pluginName the name of the plugin to appear in the stats
|
|
||||||
* @param pluginVersion the {@link Version} of the plugin.
|
|
||||||
*/
|
*/
|
||||||
private void pingUsageServer() {
|
private void pingUsageServer() {
|
||||||
// get the version of the plugin
|
// get the version of the plugin
|
||||||
|
|||||||
@@ -0,0 +1,34 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2009 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.wizards.actions;
|
||||||
|
|
||||||
|
import com.android.ide.eclipse.adt.wizards.avdmanager.AvdManagerWizard;
|
||||||
|
|
||||||
|
import org.eclipse.jface.action.IAction;
|
||||||
|
import org.eclipse.ui.IWorkbenchWizard;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delegate for the toolbar/menu action "Android AVD Manager".
|
||||||
|
* It displays the Android AVD Manager.
|
||||||
|
*/
|
||||||
|
public class AvdManagerAction extends OpenWizardAction {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected IWorkbenchWizard instanciateWizard(IAction action) {
|
||||||
|
return new AvdManagerWizard();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,632 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2009 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.wizards.avdmanager;
|
||||||
|
|
||||||
|
import com.android.ide.eclipse.adt.AdtPlugin;
|
||||||
|
import com.android.ide.eclipse.adt.sdk.Sdk;
|
||||||
|
import com.android.ide.eclipse.adt.sdk.Sdk.ITargetChangeListener;
|
||||||
|
import com.android.prefs.AndroidLocation;
|
||||||
|
import com.android.prefs.AndroidLocation.AndroidLocationException;
|
||||||
|
import com.android.sdklib.IAndroidTarget;
|
||||||
|
import com.android.sdklib.ISdkLog;
|
||||||
|
import com.android.sdklib.avd.AvdManager;
|
||||||
|
import com.android.sdklib.avd.AvdManager.AvdInfo;
|
||||||
|
import com.android.sdkuilib.AvdSelector;
|
||||||
|
|
||||||
|
import org.eclipse.core.resources.IProject;
|
||||||
|
import org.eclipse.jface.wizard.WizardPage;
|
||||||
|
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.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;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.TreeMap;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is the single page of the {@link AvdManagerWizard} which provides the ability to display
|
||||||
|
* the AVDs and edit them quickly.
|
||||||
|
*/
|
||||||
|
class AvdManagerListPage extends WizardPage {
|
||||||
|
|
||||||
|
private AvdSelector mAvdSelector;
|
||||||
|
private Button mDeleteButton;
|
||||||
|
private Button mRefreshButton;
|
||||||
|
private Text mCreateName;
|
||||||
|
private Combo mCreateTargetCombo;
|
||||||
|
private Text mCreateSdCard;
|
||||||
|
private Combo mCreateSkinCombo;
|
||||||
|
private Button mCreateForce;
|
||||||
|
private Button mCreateButton;
|
||||||
|
private HashSet<String> mKnownAvdNames = new HashSet<String>();
|
||||||
|
private TreeMap<String, IAndroidTarget> mCurrentTargets = new TreeMap<String, IAndroidTarget>();
|
||||||
|
private ITargetChangeListener mSdkTargetChangeListener;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a new {@link AvdManagerListPage}.
|
||||||
|
* <p/>
|
||||||
|
* Called by {@link AvdManagerWizard#createMainPage()}.
|
||||||
|
*/
|
||||||
|
protected AvdManagerListPage(String pageName) {
|
||||||
|
super(pageName);
|
||||||
|
setPageComplete(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called by the parent Wizard to create the UI for this Wizard Page.
|
||||||
|
*
|
||||||
|
* {@inheritDoc}
|
||||||
|
*
|
||||||
|
* @see org.eclipse.jface.dialogs.IDialogPage#createControl(org.eclipse.swt.widgets.Composite)
|
||||||
|
*/
|
||||||
|
public void createControl(Composite parent) {
|
||||||
|
Composite composite = new Composite(parent, SWT.NULL);
|
||||||
|
composite.setFont(parent.getFont());
|
||||||
|
|
||||||
|
initializeDialogUnits(parent);
|
||||||
|
|
||||||
|
composite.setLayout(new GridLayout(1, false /*makeColumnsEqualWidth*/));
|
||||||
|
composite.setLayoutData(new GridData(GridData.FILL_BOTH));
|
||||||
|
|
||||||
|
createAvdGroup(composite);
|
||||||
|
createCreateGroup(composite);
|
||||||
|
registerSdkChangeListener();
|
||||||
|
|
||||||
|
// Show description the first time
|
||||||
|
setErrorMessage(null);
|
||||||
|
setMessage(null);
|
||||||
|
setControl(composite);
|
||||||
|
|
||||||
|
// Update state the first time
|
||||||
|
reloadAvdList();
|
||||||
|
reloadTargetCombo();
|
||||||
|
validatePage();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void registerSdkChangeListener() {
|
||||||
|
|
||||||
|
mSdkTargetChangeListener = new ITargetChangeListener() {
|
||||||
|
public void onProjectTargetChange(IProject changedProject) {
|
||||||
|
// Ignore
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onTargetsLoaded() {
|
||||||
|
// Update the AVD list, since the SDK change will influence the "good" avd list
|
||||||
|
reloadAvdList();
|
||||||
|
// Update the sdk target combo with the new targets
|
||||||
|
reloadTargetCombo();
|
||||||
|
validatePage();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
AdtPlugin.getDefault().addTargetListener(mSdkTargetChangeListener);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void dispose() {
|
||||||
|
if (mSdkTargetChangeListener != null) {
|
||||||
|
AdtPlugin.getDefault().removeTargetListener(mSdkTargetChangeListener);
|
||||||
|
mSdkTargetChangeListener = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- UI creation ---
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates the AVD selector and refresh & delete buttons.
|
||||||
|
*/
|
||||||
|
private void createAvdGroup(Composite parent) {
|
||||||
|
int col = 0;
|
||||||
|
|
||||||
|
final Composite grid2 = new Composite(parent, SWT.NONE);
|
||||||
|
grid2.setLayout(new GridLayout(2, false /*makeColumnsEqualWidth*/));
|
||||||
|
grid2.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
|
||||||
|
|
||||||
|
Label label = new Label(grid2, SWT.NONE);
|
||||||
|
label.setText("List of existing Android Virtual Devices:");
|
||||||
|
label.setLayoutData(new GridData(SWT.BEGINNING, SWT.CENTER, true, false));
|
||||||
|
|
||||||
|
mRefreshButton = new Button(grid2, SWT.PUSH);
|
||||||
|
mRefreshButton.setText("Refresh");
|
||||||
|
mRefreshButton.setLayoutData(new GridData(SWT.END, SWT.CENTER, false, false));
|
||||||
|
mRefreshButton.addSelectionListener(new SelectionAdapter() {
|
||||||
|
@Override
|
||||||
|
public void widgetSelected(SelectionEvent e) {
|
||||||
|
reloadAvdList();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
mAvdSelector = new AvdSelector(parent, null);
|
||||||
|
mAvdSelector.setSelectionListener(new SelectionAdapter() {
|
||||||
|
@Override
|
||||||
|
public void widgetSelected(SelectionEvent e) {
|
||||||
|
super.widgetSelected(e);
|
||||||
|
updateDeleteButton();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
mDeleteButton = new Button(parent, SWT.PUSH);
|
||||||
|
mDeleteButton.setLayoutData(new GridData(SWT.BEGINNING, SWT.CENTER, true, false));
|
||||||
|
mDeleteButton.addSelectionListener(new SelectionAdapter() {
|
||||||
|
@Override
|
||||||
|
public void widgetSelected(SelectionEvent e) {
|
||||||
|
onDelete();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
updateDeleteButton();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateDeleteButton() {
|
||||||
|
AvdInfo selected = mAvdSelector.getFirstSelected();
|
||||||
|
mDeleteButton.setText(String.format("Delete %s...",
|
||||||
|
selected == null ? "" : selected.getName())); //$NON-NLS-1$
|
||||||
|
mDeleteButton.pack();
|
||||||
|
mDeleteButton.setEnabled(selected != null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates the "Create" group
|
||||||
|
*/
|
||||||
|
private void createCreateGroup(Composite parent) {
|
||||||
|
|
||||||
|
Group grid = new Group(parent, SWT.SHADOW_ETCHED_IN);
|
||||||
|
grid.setLayout(new GridLayout(4, false /*makeColumnsEqualWidth*/));
|
||||||
|
grid.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
|
||||||
|
grid.setFont(parent.getFont());
|
||||||
|
grid.setText("Create AVD");
|
||||||
|
|
||||||
|
// first line
|
||||||
|
|
||||||
|
Label label = new Label(grid, SWT.NONE);
|
||||||
|
label.setText("Name");
|
||||||
|
|
||||||
|
mCreateName = new Text(grid, SWT.BORDER);
|
||||||
|
mCreateName.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
|
||||||
|
mCreateName.addModifyListener(new CreateNameModifyListener());
|
||||||
|
|
||||||
|
label = new Label(grid, SWT.NONE);
|
||||||
|
label.setText("Target");
|
||||||
|
|
||||||
|
mCreateTargetCombo = new Combo(grid, SWT.READ_ONLY | SWT.DROP_DOWN);
|
||||||
|
mCreateTargetCombo.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
|
||||||
|
mCreateTargetCombo.addSelectionListener(new SelectionAdapter() {
|
||||||
|
@Override
|
||||||
|
public void widgetSelected(SelectionEvent e) {
|
||||||
|
super.widgetSelected(e);
|
||||||
|
reloadSkinCombo();
|
||||||
|
validatePage();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// second line
|
||||||
|
|
||||||
|
label = new Label(grid, SWT.NONE);
|
||||||
|
label.setText("SDCard");
|
||||||
|
|
||||||
|
ValidateListener validateListener = new ValidateListener();
|
||||||
|
|
||||||
|
mCreateSdCard = new Text(grid, SWT.BORDER);
|
||||||
|
mCreateSdCard.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
|
||||||
|
mCreateSdCard.addModifyListener(validateListener);
|
||||||
|
|
||||||
|
label = new Label(grid, SWT.NONE);
|
||||||
|
label.setText("Skin");
|
||||||
|
|
||||||
|
mCreateSkinCombo = new Combo(grid, SWT.READ_ONLY | SWT.DROP_DOWN);
|
||||||
|
mCreateSkinCombo.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
|
||||||
|
|
||||||
|
// dummies for alignment
|
||||||
|
label = new Label(grid, SWT.NONE);
|
||||||
|
label = new Label(grid, SWT.NONE);
|
||||||
|
|
||||||
|
mCreateForce = new Button(grid, SWT.CHECK);
|
||||||
|
mCreateForce.setText("Force");
|
||||||
|
mCreateForce.setEnabled(false);
|
||||||
|
mCreateForce.addSelectionListener(validateListener);
|
||||||
|
|
||||||
|
mCreateButton = new Button(grid, SWT.PUSH);
|
||||||
|
mCreateButton.setText("Create AVD");
|
||||||
|
mCreateButton.setLayoutData(new GridData(SWT.END, SWT.CENTER, false, false));
|
||||||
|
mCreateButton.addSelectionListener(new SelectionAdapter() {
|
||||||
|
@Override
|
||||||
|
public void widgetSelected(SelectionEvent e) {
|
||||||
|
super.widgetSelected(e);
|
||||||
|
onCreate();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 = mCreateName.getText().trim();
|
||||||
|
if (mKnownAvdNames.contains(name)) {
|
||||||
|
mCreateForce.setEnabled(true);
|
||||||
|
} else {
|
||||||
|
mCreateForce.setEnabled(false);
|
||||||
|
mCreateForce.setSelection(false);
|
||||||
|
}
|
||||||
|
validatePage();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class ValidateListener extends SelectionAdapter implements ModifyListener {
|
||||||
|
|
||||||
|
public void modifyText(ModifyEvent e) {
|
||||||
|
validatePage();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void widgetSelected(SelectionEvent e) {
|
||||||
|
super.widgetSelected(e);
|
||||||
|
validatePage();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void reloadTargetCombo() {
|
||||||
|
|
||||||
|
String selected = null;
|
||||||
|
int index = mCreateTargetCombo.getSelectionIndex();
|
||||||
|
if (index >= 0) {
|
||||||
|
selected = mCreateTargetCombo.getItem(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
mCurrentTargets.clear();
|
||||||
|
mCreateTargetCombo.removeAll();
|
||||||
|
|
||||||
|
boolean found = false;
|
||||||
|
index = -1;
|
||||||
|
|
||||||
|
Sdk sdk = Sdk.getCurrent();
|
||||||
|
if (sdk != null) {
|
||||||
|
for (IAndroidTarget target : sdk.getTargets()) {
|
||||||
|
String name = String.format("%s - %s",
|
||||||
|
target.getName(),
|
||||||
|
target.getApiVersionName());
|
||||||
|
mCurrentTargets.put(name, target);
|
||||||
|
mCreateTargetCombo.add(name);
|
||||||
|
if (!found) {
|
||||||
|
index++;
|
||||||
|
found = name.equals(selected);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mCreateTargetCombo.setEnabled(mCurrentTargets.size() > 0);
|
||||||
|
|
||||||
|
if (found) {
|
||||||
|
mCreateTargetCombo.select(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
reloadSkinCombo();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void reloadSkinCombo() {
|
||||||
|
String selected = null;
|
||||||
|
int index = mCreateSkinCombo.getSelectionIndex();
|
||||||
|
if (index >= 0) {
|
||||||
|
selected = mCreateSkinCombo.getItem(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
mCreateSkinCombo.removeAll();
|
||||||
|
mCreateSkinCombo.setEnabled(false);
|
||||||
|
|
||||||
|
index = mCreateTargetCombo.getSelectionIndex();
|
||||||
|
if (index >= 0) {
|
||||||
|
|
||||||
|
String targetName = mCreateTargetCombo.getItem(index);
|
||||||
|
|
||||||
|
boolean found = false;
|
||||||
|
IAndroidTarget target = mCurrentTargets.get(targetName);
|
||||||
|
if (target != null) {
|
||||||
|
mCreateSkinCombo.add(String.format("Default (%s)", target.getDefaultSkin()));
|
||||||
|
|
||||||
|
index = -1;
|
||||||
|
for (String skin : target.getSkins()) {
|
||||||
|
mCreateSkinCombo.add(skin);
|
||||||
|
if (!found) {
|
||||||
|
index++;
|
||||||
|
found = skin.equals(selected);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mCreateSkinCombo.setEnabled(true);
|
||||||
|
|
||||||
|
if (found) {
|
||||||
|
mCreateSkinCombo.select(index);
|
||||||
|
} else {
|
||||||
|
mCreateSkinCombo.select(0); // default
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validates the fields, displays errors and warnings.
|
||||||
|
* Enables the finish button if there are no errors.
|
||||||
|
* <p/>
|
||||||
|
* Not really used here yet. Keep as a placeholder.
|
||||||
|
*/
|
||||||
|
private void validatePage() {
|
||||||
|
String error = null;
|
||||||
|
String warning = null;
|
||||||
|
|
||||||
|
|
||||||
|
// Validate AVD name
|
||||||
|
String avdName = mCreateName.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. Allowed characters are: %2$s",
|
||||||
|
avdName, AvdManager.CHARS_AVD_NAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate target
|
||||||
|
if (hasAvdName && error == null && mCreateTargetCombo.getSelectionIndex() < 0) {
|
||||||
|
error = "A target must be selected in order to create an AVD.";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate SDCard path or value
|
||||||
|
if (error == null) {
|
||||||
|
String sdName = mCreateSdCard.getText().trim();
|
||||||
|
|
||||||
|
if (sdName.length() > 0 &&
|
||||||
|
!new File(sdName).isFile() &&
|
||||||
|
!AvdManager.SDCARD_SIZE_PATTERN.matcher(sdName).matches()) {
|
||||||
|
error = "SD Card must be either a file path or a size such as 128K or 64M.";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for duplicate AVD name
|
||||||
|
if (hasAvdName && error == null) {
|
||||||
|
if (mKnownAvdNames.contains(avdName) && !mCreateForce.getSelection()) {
|
||||||
|
error = String.format(
|
||||||
|
"The AVD name '%s' is already used. " +
|
||||||
|
"Check \"Force\" if you really want to create a new AVD with that name and delete the previous one.",
|
||||||
|
avdName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate the create button
|
||||||
|
boolean can_create = hasAvdName && error == null;
|
||||||
|
if (can_create) {
|
||||||
|
can_create &= mCreateTargetCombo.getSelectionIndex() >= 0;
|
||||||
|
}
|
||||||
|
mCreateButton.setEnabled(can_create);
|
||||||
|
|
||||||
|
// -- update UI
|
||||||
|
setPageComplete(true);
|
||||||
|
if (error != null) {
|
||||||
|
setMessage(error, WizardPage.ERROR);
|
||||||
|
} else if (warning != null) {
|
||||||
|
setMessage(warning, WizardPage.WARNING);
|
||||||
|
} else {
|
||||||
|
setErrorMessage(null);
|
||||||
|
setMessage(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reloads the AVD list in the AVD selector.
|
||||||
|
* Tries to preserve the selection.
|
||||||
|
*/
|
||||||
|
private void reloadAvdList() {
|
||||||
|
AvdInfo selected = mAvdSelector.getFirstSelected();
|
||||||
|
|
||||||
|
AvdManager avdm = getAvdManager();
|
||||||
|
|
||||||
|
AvdInfo[] avds = avdm == null ? null : avdm.getValidAvds();
|
||||||
|
mAvdSelector.setAvds(avds, null /*filter*/);
|
||||||
|
|
||||||
|
// Keep the list of known AVD names to check if they exist quickly. however
|
||||||
|
// use the list of all AVDs, including broken ones (unless we don't know their
|
||||||
|
// name).
|
||||||
|
mKnownAvdNames.clear();
|
||||||
|
if (avdm != null) {
|
||||||
|
for (AvdInfo avd : avdm.getAllAvds()) {
|
||||||
|
String name = avd.getName();
|
||||||
|
if (name != null) {
|
||||||
|
mKnownAvdNames.add(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mAvdSelector.setSelection(selected);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Triggered when the user selects the "delete" button.
|
||||||
|
* Deletes the currently selected AVD, if any.
|
||||||
|
*/
|
||||||
|
private void onDelete() {
|
||||||
|
AvdInfo avdInfo = mAvdSelector.getFirstSelected();
|
||||||
|
AvdManager avdm = getAvdManager();
|
||||||
|
if (avdInfo == null || avdm == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Confirm you want to delete this AVD
|
||||||
|
if (!AdtPlugin.displayPrompt("Delete Android Virtual Device",
|
||||||
|
String.format("Please confirm that you want to delete the Android Virtual Device named '%s'. This operation cannot be reverted.",
|
||||||
|
avdInfo.getName()))) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
SdkLog log = new SdkLog(String.format("Result of deleting AVD '%s':", avdInfo.getName()));
|
||||||
|
|
||||||
|
boolean success = avdm.deleteAvd(avdInfo, log);
|
||||||
|
|
||||||
|
log.display(success);
|
||||||
|
reloadAvdList();
|
||||||
|
updateDeleteButton();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Triggered when the user selects the "create" button.
|
||||||
|
*/
|
||||||
|
private void onCreate() {
|
||||||
|
String avdName = mCreateName.getText().trim();
|
||||||
|
String sdName = mCreateSdCard.getText().trim();
|
||||||
|
int targetIndex = mCreateTargetCombo.getSelectionIndex();
|
||||||
|
int skinIndex = mCreateSkinCombo.getSelectionIndex();
|
||||||
|
boolean force = mCreateForce.getSelection();
|
||||||
|
AvdManager avdm = getAvdManager();
|
||||||
|
|
||||||
|
if (avdm == null ||
|
||||||
|
avdName.length() == 0 ||
|
||||||
|
targetIndex < 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
String targetName = mCreateTargetCombo.getItem(targetIndex);
|
||||||
|
IAndroidTarget target = mCurrentTargets.get(targetName);
|
||||||
|
if (target == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
String skinName = null;
|
||||||
|
if (skinIndex > 0) {
|
||||||
|
// index 0 is the default, we don't use it
|
||||||
|
skinName = mCreateSkinCombo.getItem(skinIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
SdkLog log = new SdkLog(String.format("Result of creating AVD '%s':", avdName));
|
||||||
|
|
||||||
|
File avdFolder;
|
||||||
|
try {
|
||||||
|
avdFolder = new File(
|
||||||
|
AndroidLocation.getFolder() + AndroidLocation.FOLDER_AVD,
|
||||||
|
avdName + AvdManager.AVD_FOLDER_EXTENSION);
|
||||||
|
} catch (AndroidLocationException e) {
|
||||||
|
AdtPlugin.logAndPrintError(e, null /*tag*/,
|
||||||
|
"AndroidLocation.getFolder failed"); //$NON-NLS-1$
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ISdkLog oldLog = null;
|
||||||
|
boolean success = false;
|
||||||
|
try {
|
||||||
|
// Temporarily change the AvdManager's logger for ours, since the API no longer
|
||||||
|
// takes a logger argument.
|
||||||
|
// TODO revisit this later. See comments in AvdManager#mSdkLog.
|
||||||
|
oldLog = avdm.setSdkLog(log);
|
||||||
|
|
||||||
|
AvdInfo avdInfo = avdm.createAvd(
|
||||||
|
avdFolder,
|
||||||
|
avdName,
|
||||||
|
target,
|
||||||
|
skinName,
|
||||||
|
sdName,
|
||||||
|
null, // hardwareConfig,
|
||||||
|
force);
|
||||||
|
|
||||||
|
success = avdInfo != null;
|
||||||
|
|
||||||
|
} finally {
|
||||||
|
avdm.setSdkLog(oldLog);
|
||||||
|
}
|
||||||
|
|
||||||
|
log.display(success);
|
||||||
|
|
||||||
|
if (success) {
|
||||||
|
// clear the name field on success
|
||||||
|
mCreateName.setText(""); //$NON-NLS-1$
|
||||||
|
}
|
||||||
|
|
||||||
|
reloadAvdList();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Collects all log from the AVD action and displays it in a dialog.
|
||||||
|
*/
|
||||||
|
private class SdkLog implements ISdkLog {
|
||||||
|
|
||||||
|
final ArrayList<String> logMessages = new ArrayList<String>();
|
||||||
|
private final String mMessage;
|
||||||
|
|
||||||
|
public SdkLog(String message) {
|
||||||
|
mMessage = message;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void error(Throwable throwable, String errorFormat, Object... arg) {
|
||||||
|
if (errorFormat != null) {
|
||||||
|
logMessages.add(String.format("Error: " + errorFormat, arg));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (throwable != null) {
|
||||||
|
logMessages.add(throwable.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void warning(String warningFormat, Object... arg) {
|
||||||
|
logMessages.add(String.format("Warning: " + warningFormat, arg));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void printf(String msgFormat, Object... arg) {
|
||||||
|
logMessages.add(String.format(msgFormat, arg));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Displays the log if anything was captured.
|
||||||
|
*/
|
||||||
|
public void display(boolean success) {
|
||||||
|
if (logMessages.size() > 0) {
|
||||||
|
StringBuilder sb = new StringBuilder(mMessage + "\n");
|
||||||
|
for (String msg : logMessages) {
|
||||||
|
sb.append('\n');
|
||||||
|
sb.append(msg);
|
||||||
|
}
|
||||||
|
if (success) {
|
||||||
|
AdtPlugin.displayWarning("Android Virtual Devices Manager", sb.toString());
|
||||||
|
} else {
|
||||||
|
AdtPlugin.displayError("Android Virtual Devices Manager", sb.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the current AVD Manager or null if none has been created yet.
|
||||||
|
* This can happen when the SDK hasn't finished loading or the manager failed to
|
||||||
|
* parse the AVD directory.
|
||||||
|
*/
|
||||||
|
private AvdManager getAvdManager() {
|
||||||
|
Sdk sdk = Sdk.getCurrent();
|
||||||
|
if (sdk != null) {
|
||||||
|
return sdk.getAvdManager();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,100 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2008 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.wizards.avdmanager;
|
||||||
|
|
||||||
|
import com.android.ide.eclipse.editors.IconFactory;
|
||||||
|
|
||||||
|
import org.eclipse.jface.resource.ImageDescriptor;
|
||||||
|
import org.eclipse.jface.viewers.IStructuredSelection;
|
||||||
|
import org.eclipse.jface.wizard.Wizard;
|
||||||
|
import org.eclipse.ui.INewWizard;
|
||||||
|
import org.eclipse.ui.IWorkbench;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The "AVD Manager Wizard" provides a quick way to edit AVDs.
|
||||||
|
* <p/>
|
||||||
|
* The wizard has one page, {@link AvdManagerListPage}, used to display and edit the AVDs.
|
||||||
|
* In fact the whole UI is not really a wizard. It has just been implemented that way
|
||||||
|
* to get something quick out of the door. We'll need to revisit this when we implement
|
||||||
|
* the final standalone AVD Manager UI and this Wizard will go away.
|
||||||
|
*/
|
||||||
|
public class AvdManagerWizard extends Wizard implements INewWizard {
|
||||||
|
|
||||||
|
private static final String PROJECT_LOGO_LARGE = "android_large"; //$NON-NLS-1$
|
||||||
|
|
||||||
|
protected static final String MAIN_PAGE_NAME = "avdManagerListPage"; //$NON-NLS-1$
|
||||||
|
|
||||||
|
private AvdManagerListPage mMainPage;
|
||||||
|
|
||||||
|
public void init(IWorkbench workbench, IStructuredSelection selection) {
|
||||||
|
setHelpAvailable(false); // TODO have help
|
||||||
|
setWindowTitle("Android Virtual Devices Manager");
|
||||||
|
setImageDescriptor();
|
||||||
|
|
||||||
|
mMainPage = createMainPage();
|
||||||
|
mMainPage.setTitle("Android Virtual Devices Manager");
|
||||||
|
mMainPage.setDescription("Displays existing Android Virtual Devices. Lets you create new ones or delete existing ones.");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates the wizard page.
|
||||||
|
* <p/>
|
||||||
|
* Please do NOT override this method.
|
||||||
|
* <p/>
|
||||||
|
* This is protected so that it can be overridden by unit tests.
|
||||||
|
* However the contract of this class is private and NO ATTEMPT will be made
|
||||||
|
* to maintain compatibility between different versions of the plugin.
|
||||||
|
*/
|
||||||
|
protected AvdManagerListPage createMainPage() {
|
||||||
|
return new AvdManagerListPage(MAIN_PAGE_NAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
// -- Methods inherited from org.eclipse.jface.wizard.Wizard --
|
||||||
|
//
|
||||||
|
// The Wizard class implements most defaults and boilerplate code needed by
|
||||||
|
// IWizard
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds pages to this wizard.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void addPages() {
|
||||||
|
addPage(mMainPage);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Performs any actions appropriate in response to the user having pressed
|
||||||
|
* the Finish button, or refuse if finishing now is not permitted: here, it does nothing.
|
||||||
|
*
|
||||||
|
* @return True
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean performFinish() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an image descriptor for the wizard logo.
|
||||||
|
*/
|
||||||
|
private void setImageDescriptor() {
|
||||||
|
ImageDescriptor desc = IconFactory.getInstance().getImageDescriptor(PROJECT_LOGO_LARGE);
|
||||||
|
setDefaultPageImageDescriptor(desc);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -463,7 +463,7 @@ public class UiClassAttributeNode extends UiTextAttributeNode {
|
|||||||
* Computes and return the {@link IPackageFragmentRoot}s corresponding to the source folders of
|
* Computes and return the {@link IPackageFragmentRoot}s corresponding to the source folders of
|
||||||
* the specified project.
|
* the specified project.
|
||||||
* @param project the project
|
* @param project the project
|
||||||
* @param b
|
* @param include_containers True to include containers
|
||||||
* @return an array of IPackageFragmentRoot.
|
* @return an array of IPackageFragmentRoot.
|
||||||
*/
|
*/
|
||||||
private IPackageFragmentRoot[] getPackageFragmentRoots(IProject project,
|
private IPackageFragmentRoot[] getPackageFragmentRoots(IProject project,
|
||||||
|
|||||||
@@ -35,7 +35,6 @@ import java.io.IOException;
|
|||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.regex.Pattern;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Main class for the 'android' application.
|
* Main class for the 'android' application.
|
||||||
@@ -50,11 +49,6 @@ class Main {
|
|||||||
|
|
||||||
private final static String[] BOOLEAN_YES_REPLIES = new String[] { "yes", "y" };
|
private final static String[] BOOLEAN_YES_REPLIES = new String[] { "yes", "y" };
|
||||||
private final static String[] BOOLEAN_NO_REPLIES = new String[] { "no", "n" };
|
private final static String[] BOOLEAN_NO_REPLIES = new String[] { "no", "n" };
|
||||||
|
|
||||||
/** Regex used to validate characters that compose an AVD name. */
|
|
||||||
private final static Pattern RE_AVD_NAME = Pattern.compile("[a-zA-Z0-9._-]+");
|
|
||||||
/** List of valid characters for an AVD name. Used for display purposes. */
|
|
||||||
private final static String CHARS_AVD_NAME = "a-z A-Z 0-9 . _ -";
|
|
||||||
|
|
||||||
|
|
||||||
/** Path to the SDK folder. This is the parent of {@link #TOOLSDIR}. */
|
/** Path to the SDK folder. This is the parent of {@link #TOOLSDIR}. */
|
||||||
@@ -515,10 +509,10 @@ class Main {
|
|||||||
|
|
||||||
String avdName = mSdkCommandLine.getParamName();
|
String avdName = mSdkCommandLine.getParamName();
|
||||||
|
|
||||||
if (!RE_AVD_NAME.matcher(avdName).matches()) {
|
if (!AvdManager.RE_AVD_NAME.matcher(avdName).matches()) {
|
||||||
errorAndExit(
|
errorAndExit(
|
||||||
"AVD name '%1$s' contains invalid characters.\nAllowed characters are: %2$s",
|
"AVD name '%1$s' contains invalid characters.\nAllowed characters are: %2$s",
|
||||||
avdName, CHARS_AVD_NAME);
|
avdName, AvdManager.CHARS_AVD_NAME);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -593,18 +587,6 @@ class Main {
|
|||||||
hardwareConfig,
|
hardwareConfig,
|
||||||
removePrevious);
|
removePrevious);
|
||||||
|
|
||||||
if (newAvdInfo != null &&
|
|
||||||
oldAvdInfo != null &&
|
|
||||||
!oldAvdInfo.getPath().equals(newAvdInfo.getPath())) {
|
|
||||||
mSdkLog.warning("Removing previous AVD directory at %s", oldAvdInfo.getPath());
|
|
||||||
// Remove the old data directory
|
|
||||||
File dir = new File(oldAvdInfo.getPath());
|
|
||||||
avdManager.recursiveDelete(dir);
|
|
||||||
dir.delete();
|
|
||||||
// Remove old AVD info from manager
|
|
||||||
avdManager.removeAvd(oldAvdInfo);
|
|
||||||
}
|
|
||||||
|
|
||||||
} catch (AndroidLocationException e) {
|
} catch (AndroidLocationException e) {
|
||||||
errorAndExit(e.getMessage());
|
errorAndExit(e.getMessage());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -125,7 +125,13 @@ public final class AvdManager {
|
|||||||
/**
|
/**
|
||||||
* Pattern for matching SD Card sizes, e.g. "4K" or "16M".
|
* Pattern for matching SD Card sizes, e.g. "4K" or "16M".
|
||||||
*/
|
*/
|
||||||
private final static Pattern SDCARD_SIZE_PATTERN = Pattern.compile("\\d+[MK]?");
|
public final static Pattern SDCARD_SIZE_PATTERN = Pattern.compile("\\d+[MK]");
|
||||||
|
|
||||||
|
/** Regex used to validate characters that compose an AVD name. */
|
||||||
|
public final static Pattern RE_AVD_NAME = Pattern.compile("[a-zA-Z0-9._-]+");
|
||||||
|
|
||||||
|
/** List of valid characters for an AVD name. Used for display purposes. */
|
||||||
|
public final static String CHARS_AVD_NAME = "a-z A-Z 0-9 . _ -";
|
||||||
|
|
||||||
/** An immutable structure describing an Android Virtual Device. */
|
/** An immutable structure describing an Android Virtual Device. */
|
||||||
public static final class AvdInfo {
|
public static final class AvdInfo {
|
||||||
@@ -301,15 +307,38 @@ public final class AvdManager {
|
|||||||
private final ArrayList<AvdInfo> mAllAvdList = new ArrayList<AvdInfo>();
|
private final ArrayList<AvdInfo> mAllAvdList = new ArrayList<AvdInfo>();
|
||||||
private AvdInfo[] mValidAvdList;
|
private AvdInfo[] mValidAvdList;
|
||||||
private AvdInfo[] mBrokenAvdList;
|
private AvdInfo[] mBrokenAvdList;
|
||||||
private ISdkLog mSdkLog;
|
|
||||||
private final SdkManager mSdk;
|
private final SdkManager mSdk;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO remove this field. Each caller should give its own logger to the methods
|
||||||
|
* here instead of relying on a global logger. Otherwise that means that each
|
||||||
|
* caller needs to re-instantiate this just to change the logger, which is plain
|
||||||
|
* ugly.
|
||||||
|
*
|
||||||
|
* We'll revisit this in the final AVD Manager UI for donut.
|
||||||
|
*/
|
||||||
|
private ISdkLog mSdkLog;
|
||||||
|
|
||||||
public AvdManager(SdkManager sdk, ISdkLog sdkLog) throws AndroidLocationException {
|
public AvdManager(SdkManager sdk, ISdkLog sdkLog) throws AndroidLocationException {
|
||||||
mSdk = sdk;
|
mSdk = sdk;
|
||||||
mSdkLog = sdkLog;
|
mSdkLog = sdkLog;
|
||||||
buildAvdList(mAllAvdList);
|
buildAvdList(mAllAvdList);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Changes the current {@link ISdkLog}.
|
||||||
|
*
|
||||||
|
* This method should not exist. See comments for {@link #mSdkLog}.
|
||||||
|
*
|
||||||
|
* @return The {@link ISdkLog} that was currently being used.
|
||||||
|
* @see #mSdkLog
|
||||||
|
*/
|
||||||
|
public ISdkLog setSdkLog(ISdkLog sdkLog) {
|
||||||
|
ISdkLog oldLogger = mSdkLog;
|
||||||
|
mSdkLog = sdkLog;
|
||||||
|
return oldLogger;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns all the existing AVDs.
|
* Returns all the existing AVDs.
|
||||||
* @return a newly allocated array containing all the AVDs.
|
* @return a newly allocated array containing all the AVDs.
|
||||||
@@ -405,14 +434,17 @@ public final class AvdManager {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new AVD. It is expected that there is no existing AVD with this name already.
|
* Creates a new AVD. It is expected that there is no existing AVD with this name already.
|
||||||
|
*
|
||||||
* @param avdFolder the data folder for the AVD. It will be created as needed.
|
* @param avdFolder the data folder for the AVD. It will be created as needed.
|
||||||
* @param name the name of the AVD
|
* @param name the name of the AVD
|
||||||
* @param target the target of the AVD
|
* @param target the target of the AVD
|
||||||
* @param skinName the name of the skin. Can be null. Must have been verified by caller.
|
* @param skinName the name of the skin. Can be null. Must have been verified by caller.
|
||||||
* @param sdcard the parameter value for the sdCard. Can be null. This is either a path to
|
* @param sdcard the parameter value for the sdCard. Can be null. This is either a path to
|
||||||
* an existing sdcard image or a sdcard size (\d+, \d+K, \dM).
|
* an existing sdcard image or a sdcard size (\d+, \d+K, \dM).
|
||||||
* @param hardwareConfig the hardware setup for the AVD
|
* @param hardwareConfig the hardware setup for the AVD. Can be null to use defaults.
|
||||||
* @param removePrevious If true remove any previous files.
|
* @param removePrevious If true remove any previous files.
|
||||||
|
* @return The new {@link AvdInfo} in case of success (which has just been added to the
|
||||||
|
* internal list) or null in case of failure.
|
||||||
*/
|
*/
|
||||||
public AvdInfo createAvd(File avdFolder, String name, IAndroidTarget target,
|
public AvdInfo createAvd(File avdFolder, String name, IAndroidTarget target,
|
||||||
String skinName, String sdcard, Map<String,String> hardwareConfig,
|
String skinName, String sdcard, Map<String,String> hardwareConfig,
|
||||||
@@ -482,7 +514,7 @@ public final class AvdManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Now the skin.
|
// Now the skin.
|
||||||
if (skinName == null) {
|
if (skinName == null || skinName.length() == 0) {
|
||||||
skinName = target.getDefaultSkin();
|
skinName = target.getDefaultSkin();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -505,7 +537,7 @@ public final class AvdManager {
|
|||||||
values.put(AVD_INI_SKIN_NAME, skinName);
|
values.put(AVD_INI_SKIN_NAME, skinName);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sdcard != null) {
|
if (sdcard != null && sdcard.length() > 0) {
|
||||||
File sdcardFile = new File(sdcard);
|
File sdcardFile = new File(sdcard);
|
||||||
if (sdcardFile.isFile()) {
|
if (sdcardFile.isFile()) {
|
||||||
// sdcard value is an external sdcard, so we put its path into the config.ini
|
// sdcard value is an external sdcard, so we put its path into the config.ini
|
||||||
@@ -571,15 +603,33 @@ public final class AvdManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// create the AvdInfo object, and add it to the list
|
// create the AvdInfo object, and add it to the list
|
||||||
AvdInfo avdInfo = new AvdInfo(name, avdFolder.getAbsolutePath(), target.hashString(),
|
AvdInfo newAvdInfo = new AvdInfo(name,
|
||||||
|
avdFolder.getAbsolutePath(),
|
||||||
|
target.hashString(),
|
||||||
target, values);
|
target, values);
|
||||||
|
|
||||||
|
AvdInfo oldAvdInfo = getAvd(name, false /*validAvdOnly*/);
|
||||||
|
|
||||||
synchronized (mAllAvdList) {
|
synchronized (mAllAvdList) {
|
||||||
mAllAvdList.add(avdInfo);
|
if (oldAvdInfo != null && removePrevious) {
|
||||||
|
mAllAvdList.remove(oldAvdInfo);
|
||||||
|
}
|
||||||
|
mAllAvdList.add(newAvdInfo);
|
||||||
mValidAvdList = mBrokenAvdList = null;
|
mValidAvdList = mBrokenAvdList = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return avdInfo;
|
if (removePrevious &&
|
||||||
|
newAvdInfo != null &&
|
||||||
|
oldAvdInfo != null &&
|
||||||
|
!oldAvdInfo.getPath().equals(newAvdInfo.getPath())) {
|
||||||
|
mSdkLog.warning("Removing previous AVD directory at %s", oldAvdInfo.getPath());
|
||||||
|
// Remove the old data directory
|
||||||
|
File dir = new File(oldAvdInfo.getPath());
|
||||||
|
recursiveDelete(dir);
|
||||||
|
dir.delete();
|
||||||
|
}
|
||||||
|
|
||||||
|
return newAvdInfo;
|
||||||
} catch (AndroidLocationException e) {
|
} catch (AndroidLocationException e) {
|
||||||
if (mSdkLog != null) {
|
if (mSdkLog != null) {
|
||||||
mSdkLog.error(e, null);
|
mSdkLog.error(e, null);
|
||||||
@@ -724,8 +774,9 @@ public final class AvdManager {
|
|||||||
* these operations fail.
|
* these operations fail.
|
||||||
*
|
*
|
||||||
* @param avdInfo the information on the AVD to delete
|
* @param avdInfo the information on the AVD to delete
|
||||||
|
* @return True if the AVD was deleted with no error.
|
||||||
*/
|
*/
|
||||||
public void deleteAvd(AvdInfo avdInfo, ISdkLog log) {
|
public boolean deleteAvd(AvdInfo avdInfo, ISdkLog log) {
|
||||||
try {
|
try {
|
||||||
boolean error = false;
|
boolean error = false;
|
||||||
|
|
||||||
@@ -758,6 +809,7 @@ public final class AvdManager {
|
|||||||
avdInfo.getName());
|
avdInfo.getName());
|
||||||
} else {
|
} else {
|
||||||
log.printf("AVD '%1$s' deleted.\n", avdInfo.getName());
|
log.printf("AVD '%1$s' deleted.\n", avdInfo.getName());
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (AndroidLocationException e) {
|
} catch (AndroidLocationException e) {
|
||||||
@@ -765,6 +817,7 @@ public final class AvdManager {
|
|||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
log.error(e, null);
|
log.error(e, null);
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -905,10 +958,8 @@ public final class AvdManager {
|
|||||||
* Parses an AVD .ini file to create an {@link AvdInfo}.
|
* Parses an AVD .ini file to create an {@link AvdInfo}.
|
||||||
*
|
*
|
||||||
* @param path The path to the AVD .ini file
|
* @param path The path to the AVD .ini file
|
||||||
* @param acceptError When false, an AVD that fails to load will be discarded and null will be
|
* @return A new {@link AvdInfo} with an {@link AvdStatus} indicating whether this AVD is
|
||||||
* returned. When true, such an AVD will be returned with an error description.
|
* valid or not.
|
||||||
* @return A new {@link AvdInfo} or null if the file is not valid or null if the AVD is not
|
|
||||||
* valid and acceptError is false.
|
|
||||||
*/
|
*/
|
||||||
private AvdInfo parseAvdInfo(File path) {
|
private AvdInfo parseAvdInfo(File path) {
|
||||||
Map<String, String> map = SdkManager.parsePropertyFile(path, mSdkLog);
|
Map<String, String> map = SdkManager.parsePropertyFile(path, mSdkLog);
|
||||||
@@ -1012,7 +1063,6 @@ public final class AvdManager {
|
|||||||
* @param toolLocation The path to the mksdcard tool.
|
* @param toolLocation The path to the mksdcard tool.
|
||||||
* @param size The size of the new SD Card, compatible with {@link #SDCARD_SIZE_PATTERN}.
|
* @param size The size of the new SD Card, compatible with {@link #SDCARD_SIZE_PATTERN}.
|
||||||
* @param location The path of the new sdcard image file to generate.
|
* @param location The path of the new sdcard image file to generate.
|
||||||
* @param log The logger object, to report errors.
|
|
||||||
* @return True if the sdcard could be created.
|
* @return True if the sdcard could be created.
|
||||||
*/
|
*/
|
||||||
private boolean createSdCard(String toolLocation, String size, String location) {
|
private boolean createSdCard(String toolLocation, String size, String location) {
|
||||||
|
|||||||
@@ -164,7 +164,7 @@ public final class AvdSelector {
|
|||||||
* If the selection is actually changed, this will invoke the selection listener
|
* If the selection is actually changed, this will invoke the selection listener
|
||||||
* (if any) with a null event.
|
* (if any) with a null event.
|
||||||
*
|
*
|
||||||
* @param target the target to be selection
|
* @param target the target to be selected. Use null to deselect everything.
|
||||||
* @return true if the target could be selected, false otherwise.
|
* @return true if the target could be selected, false otherwise.
|
||||||
*/
|
*/
|
||||||
public boolean setSelection(AvdInfo target) {
|
public boolean setSelection(AvdInfo target) {
|
||||||
|
|||||||
Reference in New Issue
Block a user