AvdManagerpublic final class AvdManager extends Object Android Virtual Device Manager to manage AVDs. |
Fields Summary |
---|
public static final String | AVD_FOLDER_EXTENSION | public static final String | AVD_INFO_PATH | public static final String | AVD_INFO_TARGET | public static final String | AVD_INI_SKIN_PATHAVD/config.ini key name representing the SDK-relative path of the skin folder, if any,
or a 320x480 like constant for a numeric skin size. | public static final String | AVD_INI_SKIN_NAMEAVD/config.ini key name representing an UI name for the skin.
This config key is ignored by the emulator. It is only used by the SDK manager or
tools to give a friendlier name to the skin.
If missing, use the {@link #AVD_INI_SKIN_PATH} key instead. | public static final String | AVD_INI_SDCARD_PATHAVD/config.ini key name representing the path to the sdcard file.
If missing, the default name "sdcard.img" will be used for the sdcard, if there's such
a file. | public static final String | AVD_INI_SDCARD_SIZEAVD/config.ini key name representing the size of the SD card.
This property is for UI purposes only. It is not used by the emulator. | public static final String | AVD_INI_IMAGES_1AVD/config.ini key name representing the first path where the emulator looks
for system images. Typically this is the path to the add-on system image or
the path to the platform system image if there's no add-on.
The emulator looks at {@link #AVD_INI_IMAGES_1} before {@link #AVD_INI_IMAGES_2}. | public static final String | AVD_INI_IMAGES_2AVD/config.ini key name representing the second path where the emulator looks
for system images. Typically this is the path to the platform system image. | public static final Pattern | NUMERIC_SKIN_SIZEPattern to match pixel-sized skin "names", e.g. "320x480". | private static final String | USERDATA_IMG | private static final String | CONFIG_INI | private static final String | SDCARD_IMG | private static final String | INI_EXTENSION | private static final Pattern | INI_NAME_PATTERN | private static final Pattern | IMAGE_NAME_PATTERN | private static final Pattern | SDCARD_SIZE_PATTERNPattern for matching SD Card sizes, e.g. "4K" or "16M". | private final ArrayList | mAllAvdList | private AvdInfo[] | mValidAvdList | private AvdInfo[] | mBrokenAvdList | private com.android.sdklib.ISdkLog | mSdkLog | private final com.android.sdklib.SdkManager | mSdk |
Methods Summary |
---|
private java.io.File[] | buildAvdFilesList()Returns a list of files that are potential AVD ini files.
This lists the $HOME/.android/avd/.ini files.
Such files are properties file than then indicate where the AVD folder is located.
// get the Android prefs location.
String avdRoot = AndroidLocation.getFolder() + AndroidLocation.FOLDER_AVD;
// ensure folder validity.
File folder = new File(avdRoot);
if (folder.isFile()) {
throw new AndroidLocationException(
String.format("%1$s is not a valid folder.", avdRoot));
} else if (folder.exists() == false) {
// folder is not there, we create it and return
folder.mkdirs();
return null;
}
File[] avds = folder.listFiles(new FilenameFilter() {
public boolean accept(File parent, String name) {
if (INI_NAME_PATTERN.matcher(name).matches()) {
// check it's a file and not a folder
boolean isFile = new File(parent, name).isFile();
return isFile;
}
return false;
}
});
return avds;
| private void | buildAvdList(java.util.ArrayList allList)Computes the internal list of available AVDs
File[] avds = buildAvdFilesList();
if (avds != null) {
for (File avd : avds) {
AvdInfo info = parseAvdInfo(avd);
if (info != null) {
allList.add(info);
}
}
}
| public com.android.sdklib.avd.AvdManager$AvdInfo | createAvd(java.io.File avdFolder, java.lang.String name, com.android.sdklib.IAndroidTarget target, java.lang.String skinName, java.lang.String sdcard, java.util.Map hardwareConfig, boolean removePrevious)Creates a new AVD. It is expected that there is no existing AVD with this name already.
File iniFile = null;
boolean needCleanup = false;
try {
if (avdFolder.exists()) {
if (removePrevious) {
// AVD already exists and removePrevious is set, try to remove the
// directory's content first (but not the directory itself).
recursiveDelete(avdFolder);
} else {
// AVD shouldn't already exist if removePrevious is false.
if (mSdkLog != null) {
mSdkLog.error(null,
"Folder %1$s is in the way. Use --force if you want to overwrite.",
avdFolder.getAbsolutePath());
}
return null;
}
} else {
// create the AVD folder.
avdFolder.mkdir();
}
// actually write the ini file
iniFile = createAvdIniFile(name, avdFolder, target);
// writes the userdata.img in it.
String imagePath = target.getPath(IAndroidTarget.IMAGES);
File userdataSrc = new File(imagePath, USERDATA_IMG);
if (userdataSrc.exists() == false && target.isPlatform() == false) {
imagePath = target.getParent().getPath(IAndroidTarget.IMAGES);
userdataSrc = new File(imagePath, USERDATA_IMG);
}
if (userdataSrc.exists() == false) {
mSdkLog.error(null, "Unable to find a '%1$s' file to copy into the AVD folder.",
USERDATA_IMG);
needCleanup = true;
return null;
}
FileInputStream fis = new FileInputStream(userdataSrc);
File userdataDest = new File(avdFolder, USERDATA_IMG);
FileOutputStream fos = new FileOutputStream(userdataDest);
byte[] buffer = new byte[4096];
int count;
while ((count = fis.read(buffer)) != -1) {
fos.write(buffer, 0, count);
}
fos.close();
fis.close();
// Config file.
HashMap<String, String> values = new HashMap<String, String>();
if (setImagePathProperties(target, values) == false) {
needCleanup = true;
return null;
}
// Now the skin.
if (skinName == null) {
skinName = target.getDefaultSkin();
}
if (NUMERIC_SKIN_SIZE.matcher(skinName).matches()) {
// Skin name is an actual screen resolution.
// Set skin.name for display purposes in the AVD manager and
// set skin.path for use by the emulator.
values.put(AVD_INI_SKIN_NAME, skinName);
values.put(AVD_INI_SKIN_PATH, skinName);
} else {
// get the path of the skin (relative to the SDK)
// assume skin name is valid
String skinPath = getSkinRelativePath(skinName, target);
if (skinPath == null) {
needCleanup = true;
return null;
}
values.put(AVD_INI_SKIN_PATH, skinPath);
values.put(AVD_INI_SKIN_NAME, skinName);
}
if (sdcard != null) {
File sdcardFile = new File(sdcard);
if (sdcardFile.isFile()) {
// sdcard value is an external sdcard, so we put its path into the config.ini
values.put(AVD_INI_SDCARD_PATH, sdcard);
} else {
// Sdcard is possibly a size. In that case we create a file called 'sdcard.img'
// in the AVD folder, and do not put any value in config.ini.
// First, check that it matches the pattern for sdcard size
Matcher m = SDCARD_SIZE_PATTERN.matcher(sdcard);
if (m.matches()) {
// create the sdcard.
sdcardFile = new File(avdFolder, SDCARD_IMG);
String path = sdcardFile.getAbsolutePath();
// execute mksdcard with the proper parameters.
File toolsFolder = new File(mSdk.getLocation(), SdkConstants.FD_TOOLS);
File mkSdCard = new File(toolsFolder, SdkConstants.mkSdCardCmdName());
if (mkSdCard.isFile() == false) {
mSdkLog.error(null, "'%1$s' is missing from the SDK tools folder.",
mkSdCard.getName());
needCleanup = true;
return null;
}
if (createSdCard(mkSdCard.getAbsolutePath(), sdcard, path) == false) {
needCleanup = true;
return null; // mksdcard output has already been displayed, no need to
// output anything else.
}
// add a property containing the size of the sdcard for display purpose
// only when the dev does 'android list avd'
values.put(AVD_INI_SDCARD_SIZE, sdcard);
} else {
mSdkLog.error(null,
"'%1$s' is not recognized as a valid sdcard value.\n" +
"Value should be:\n" +
"1. path to an sdcard.\n" +
"2. size of the sdcard to create: <size>[K|M]",
sdcard);
needCleanup = true;
return null;
}
}
}
if (hardwareConfig != null) {
values.putAll(hardwareConfig);
}
File configIniFile = new File(avdFolder, CONFIG_INI);
writeIniFile(configIniFile, values);
if (mSdkLog != null) {
if (target.isPlatform()) {
mSdkLog.printf("Created AVD '%1$s' based on %2$s\n", name, target.getName());
} else {
mSdkLog.printf("Created AVD '%1$s' based on %2$s (%3$s)\n", name, target.getName(),
target.getVendor());
}
}
// create the AvdInfo object, and add it to the list
AvdInfo avdInfo = new AvdInfo(name, avdFolder.getAbsolutePath(), target.hashString(),
target, values);
synchronized (mAllAvdList) {
mAllAvdList.add(avdInfo);
mValidAvdList = mBrokenAvdList = null;
}
return avdInfo;
} catch (AndroidLocationException e) {
if (mSdkLog != null) {
mSdkLog.error(e, null);
}
} catch (IOException e) {
if (mSdkLog != null) {
mSdkLog.error(e, null);
}
} finally {
if (needCleanup) {
if (iniFile != null && iniFile.exists()) {
iniFile.delete();
}
recursiveDelete(avdFolder);
avdFolder.delete();
}
}
return null;
| private java.io.File | createAvdIniFile(java.lang.String name, java.io.File avdFolder, com.android.sdklib.IAndroidTarget target)Creates the ini file for an AVD.
HashMap<String, String> values = new HashMap<String, String>();
File iniFile = AvdInfo.getIniFile(name);
values.put(AVD_INFO_PATH, avdFolder.getAbsolutePath());
values.put(AVD_INFO_TARGET, target.hashString());
writeIniFile(iniFile, values);
return iniFile;
| private java.io.File | createAvdIniFile(com.android.sdklib.avd.AvdManager$AvdInfo info)Creates the ini file for an AVD.
return createAvdIniFile(info.getName(), new File(info.getPath()), info.getTarget());
| private boolean | createSdCard(java.lang.String toolLocation, java.lang.String size, java.lang.String location)Invokes the tool to create a new SD card image file.
try {
String[] command = new String[3];
command[0] = toolLocation;
command[1] = size;
command[2] = location;
Process process = Runtime.getRuntime().exec(command);
ArrayList<String> errorOutput = new ArrayList<String>();
ArrayList<String> stdOutput = new ArrayList<String>();
int status = grabProcessOutput(process, errorOutput, stdOutput,
true /* waitForReaders */);
if (status == 0) {
return true;
} else {
for (String error : errorOutput) {
mSdkLog.error(null, error);
}
}
} catch (InterruptedException e) {
// pass, print error below
} catch (IOException e) {
// pass, print error below
}
mSdkLog.error(null, "Failed to create the SD card.");
return false;
| public void | deleteAvd(com.android.sdklib.avd.AvdManager$AvdInfo avdInfo, com.android.sdklib.ISdkLog log)Actually deletes the files of an existing AVD.
This also remove it from the manager's list, The caller does not need to
call {@link #removeAvd(AvdInfo)} afterwards.
This method is designed to somehow work with an unavailable AVD, that is an AVD that
could not be loaded due to some error. That means this method still tries to remove
the AVD ini file or its folder if it can be found. An error will be output if any of
these operations fail.
try {
boolean error = false;
File f = avdInfo.getIniFile();
if (f != null && f.exists()) {
log.warning("Deleting file %1$s", f.getCanonicalPath());
if (!f.delete()) {
log.error(null, "Failed to delete %1$s", f.getCanonicalPath());
error = true;
}
}
String path = avdInfo.getPath();
if (path != null) {
f = new File(path);
if (f.exists()) {
log.warning("Deleting folder %1$s", f.getCanonicalPath());
recursiveDelete(f);
if (!f.delete()) {
log.error(null, "Failed to delete %1$s", f.getCanonicalPath());
error = true;
}
}
}
removeAvd(avdInfo);
if (error) {
log.printf("AVD '%1$s' deleted with errors. See warnings above.\n",
avdInfo.getName());
} else {
log.printf("AVD '%1$s' deleted.\n", avdInfo.getName());
}
} catch (AndroidLocationException e) {
log.error(e, null);
} catch (IOException e) {
log.error(e, null);
}
| public com.android.sdklib.avd.AvdManager$AvdInfo[] | getAllAvds()Returns all the existing AVDs.
synchronized (mAllAvdList) {
return mAllAvdList.toArray(new AvdInfo[mAllAvdList.size()]);
}
| public com.android.sdklib.avd.AvdManager$AvdInfo | getAvd(java.lang.String name, boolean validAvdOnly)Returns the {@link AvdInfo} matching the given name.
if (validAvdOnly) {
for (AvdInfo info : getValidAvds()) {
if (info.getName().equals(name)) {
return info;
}
}
} else {
synchronized (mAllAvdList) {
for (AvdInfo info : getValidAvds()) {
if (info.getName().equals(name)) {
return info;
}
}
}
}
return null;
| public com.android.sdklib.avd.AvdManager$AvdInfo[] | getBrokenAvds()Returns all the broken AVDs.
synchronized (mAllAvdList) {
if (mBrokenAvdList == null) {
ArrayList<AvdInfo> list = new ArrayList<AvdInfo>();
for (AvdInfo avd : mAllAvdList) {
if (avd.getStatus() != AvdStatus.OK) {
list.add(avd);
}
}
mBrokenAvdList = list.toArray(new AvdInfo[list.size()]);
}
return mBrokenAvdList;
}
| private java.lang.String | getImageRelativePath(com.android.sdklib.IAndroidTarget target)Returns the path to the target images folder as a relative path to the SDK, if the folder
is not empty. If the image folder is empty or does not exist, null is returned.
String imageFullPath = target.getPath(IAndroidTarget.IMAGES);
// make this path relative to the SDK location
String sdkLocation = mSdk.getLocation();
if (imageFullPath.startsWith(sdkLocation) == false) {
// this really really should not happen.
assert false;
throw new InvalidTargetPathException("Target location is not inside the SDK.");
}
File folder = new File(imageFullPath);
if (folder.isDirectory()) {
String[] list = folder.list(new FilenameFilter() {
public boolean accept(File dir, String name) {
return IMAGE_NAME_PATTERN.matcher(name).matches();
}
});
if (list.length > 0) {
imageFullPath = imageFullPath.substring(sdkLocation.length());
if (imageFullPath.charAt(0) == File.separatorChar) {
imageFullPath = imageFullPath.substring(1);
}
return imageFullPath;
}
}
return null;
| private java.lang.String | getSkinRelativePath(java.lang.String skinName, com.android.sdklib.IAndroidTarget target)Returns the path to the skin, as a relative path to the SDK.
// first look to see if the skin is in the target
String path = target.getPath(IAndroidTarget.SKINS);
File skin = new File(path, skinName);
if (skin.exists() == false && target.isPlatform() == false) {
target = target.getParent();
path = target.getPath(IAndroidTarget.SKINS);
skin = new File(path, skinName);
}
// skin really does not exist!
if (skin.exists() == false) {
mSdkLog.error(null, "Skin '%1$s' does not exist.", skinName);
return null;
}
// get the skin path
path = skin.getAbsolutePath();
// make this path relative to the SDK location
String sdkLocation = mSdk.getLocation();
if (path.startsWith(sdkLocation) == false) {
// this really really should not happen.
mSdkLog.error(null, "Target location is not inside the SDK.");
assert false;
return null;
}
path = path.substring(sdkLocation.length());
if (path.charAt(0) == File.separatorChar) {
path = path.substring(1);
}
return path;
| public com.android.sdklib.avd.AvdManager$AvdInfo[] | getValidAvds()Returns all the valid AVDs.
synchronized (mAllAvdList) {
if (mValidAvdList == null) {
ArrayList<AvdInfo> list = new ArrayList<AvdInfo>();
for (AvdInfo avd : mAllAvdList) {
if (avd.getStatus() == AvdStatus.OK) {
list.add(avd);
}
}
mValidAvdList = list.toArray(new AvdInfo[list.size()]);
}
return mValidAvdList;
}
| private int | grabProcessOutput(java.lang.Process process, java.util.ArrayList errorOutput, java.util.ArrayList stdOutput, boolean waitforReaders)Gets the stderr/stdout outputs of a process and returns when the process is done.
Both must be read or the process will block on windows.
assert errorOutput != null;
assert stdOutput != null;
// read the lines as they come. if null is returned, it's
// because the process finished
Thread t1 = new Thread("") { //$NON-NLS-1$
@Override
public void run() {
// create a buffer to read the stderr output
InputStreamReader is = new InputStreamReader(process.getErrorStream());
BufferedReader errReader = new BufferedReader(is);
try {
while (true) {
String line = errReader.readLine();
if (line != null) {
errorOutput.add(line);
} else {
break;
}
}
} catch (IOException e) {
// do nothing.
}
}
};
Thread t2 = new Thread("") { //$NON-NLS-1$
@Override
public void run() {
InputStreamReader is = new InputStreamReader(process.getInputStream());
BufferedReader outReader = new BufferedReader(is);
try {
while (true) {
String line = outReader.readLine();
if (line != null) {
stdOutput.add(line);
} else {
break;
}
}
} catch (IOException e) {
// do nothing.
}
}
};
t1.start();
t2.start();
// it looks like on windows process#waitFor() can return
// before the thread have filled the arrays, so we wait for both threads and the
// process itself.
if (waitforReaders) {
try {
t1.join();
} catch (InterruptedException e) {
}
try {
t2.join();
} catch (InterruptedException e) {
}
}
// get the return code from the process
return process.waitFor();
| public boolean | moveAvd(com.android.sdklib.avd.AvdManager$AvdInfo avdInfo, java.lang.String newName, java.lang.String paramFolderPath, com.android.sdklib.ISdkLog log)Moves and/or rename an existing AVD and its files.
This also change it in the manager's list.
The caller should make sure the name or path given are valid, do not exist and are
actually different than current values.
try {
if (paramFolderPath != null) {
File f = new File(avdInfo.getPath());
log.warning("Moving '%1$s' to '%2$s'.", avdInfo.getPath(), paramFolderPath);
if (!f.renameTo(new File(paramFolderPath))) {
log.error(null, "Failed to move '%1$s' to '%2$s'.",
avdInfo.getPath(), paramFolderPath);
return false;
}
// update AVD info
AvdInfo info = new AvdInfo(avdInfo.getName(), paramFolderPath,
avdInfo.getTargetHash(), avdInfo.getTarget(), avdInfo.getProperties());
replaceAvd(avdInfo, info);
// update the ini file
createAvdIniFile(avdInfo);
}
if (newName != null) {
File oldIniFile = avdInfo.getIniFile();
File newIniFile = AvdInfo.getIniFile(newName);
log.warning("Moving '%1$s' to '%2$s'.", oldIniFile.getPath(), newIniFile.getPath());
if (!oldIniFile.renameTo(newIniFile)) {
log.error(null, "Failed to move '%1$s' to '%2$s'.",
oldIniFile.getPath(), newIniFile.getPath());
return false;
}
// update AVD info
AvdInfo info = new AvdInfo(newName, avdInfo.getPath(),
avdInfo.getTargetHash(), avdInfo.getTarget(), avdInfo.getProperties());
replaceAvd(avdInfo, info);
}
log.printf("AVD '%1$s' moved.\n", avdInfo.getName());
} catch (AndroidLocationException e) {
log.error(e, null);
} catch (IOException e) {
log.error(e, null);
}
// nothing to do or succeeded
return true;
| private com.android.sdklib.avd.AvdManager$AvdInfo | parseAvdInfo(java.io.File path)Parses an AVD .ini file to create an {@link AvdInfo}.
Map<String, String> map = SdkManager.parsePropertyFile(path, mSdkLog);
String avdPath = map.get(AVD_INFO_PATH);
String targetHash = map.get(AVD_INFO_TARGET);
IAndroidTarget target = null;
File configIniFile = null;
Map<String, String> properties = null;
if (targetHash != null) {
target = mSdk.getTargetFromHashString(targetHash);
}
// load the AVD properties.
if (avdPath != null) {
configIniFile = new File(avdPath, CONFIG_INI);
}
if (configIniFile != null) {
properties = SdkManager.parsePropertyFile(configIniFile, mSdkLog);
}
// get name
String name = path.getName();
Matcher matcher = INI_NAME_PATTERN.matcher(path.getName());
if (matcher.matches()) {
name = matcher.group(1);
}
// check the image.sysdir are valid
boolean validImageSysdir = true;
if (properties != null) {
String imageSysDir = properties.get(AVD_INI_IMAGES_1);
if (imageSysDir != null) {
File f = new File(mSdk.getLocation() + File.separator + imageSysDir);
if (f.isDirectory() == false) {
validImageSysdir = false;
} else {
imageSysDir = properties.get(AVD_INI_IMAGES_2);
if (imageSysDir != null) {
f = new File(mSdk.getLocation() + File.separator + imageSysDir);
if (f.isDirectory() == false) {
validImageSysdir = false;
}
}
}
}
}
AvdStatus status;
if (avdPath == null) {
status = AvdStatus.ERROR_PATH;
} else if (configIniFile == null) {
status = AvdStatus.ERROR_CONFIG;
} else if (targetHash == null) {
status = AvdStatus.ERROR_TARGET_HASH;
} else if (target == null) {
status = AvdStatus.ERROR_TARGET;
} else if (properties == null) {
status = AvdStatus.ERROR_PROPERTIES;
} else if (validImageSysdir == false) {
status = AvdStatus.ERROR_IMAGE_DIR;
} else {
status = AvdStatus.OK;
}
AvdInfo info = new AvdInfo(
name,
avdPath,
targetHash,
target,
properties,
status);
return info;
| public void | recursiveDelete(java.io.File folder)Helper method to recursively delete a folder's content (but not the folder itself).
for (File f : folder.listFiles()) {
if (f.isDirectory()) {
recursiveDelete(folder);
}
f.delete();
}
| public void | reloadAvds()Reloads the AVD list.
// build the list in a temp list first, in case the method throws an exception.
// It's better than deleting the whole list before reading the new one.
ArrayList<AvdInfo> allList = new ArrayList<AvdInfo>();
buildAvdList(allList);
synchronized (mAllAvdList) {
mAllAvdList.clear();
mAllAvdList.addAll(allList);
mValidAvdList = mBrokenAvdList = null;
}
| public boolean | removeAvd(com.android.sdklib.avd.AvdManager$AvdInfo avdInfo)Removes an {@link AvdInfo} from the internal list.
synchronized (mAllAvdList) {
if (mAllAvdList.remove(avdInfo)) {
mValidAvdList = mBrokenAvdList = null;
return true;
}
}
return false;
| private void | replaceAvd(com.android.sdklib.avd.AvdManager$AvdInfo oldAvd, com.android.sdklib.avd.AvdManager$AvdInfo newAvd)Replaces an old {@link AvdInfo} with a new one in the lists storing them.
synchronized (mAllAvdList) {
mAllAvdList.remove(oldAvd);
mAllAvdList.add(newAvd);
mValidAvdList = mBrokenAvdList = null;
}
| private boolean | setImagePathProperties(com.android.sdklib.IAndroidTarget target, java.util.Map properties)Sets the paths to the system images in a properties map.
properties.remove(AVD_INI_IMAGES_1);
properties.remove(AVD_INI_IMAGES_2);
try {
String property = AVD_INI_IMAGES_1;
// First the image folders of the target itself
String imagePath = getImageRelativePath(target);
if (imagePath != null) {
properties.put(property, imagePath);
property = AVD_INI_IMAGES_2;
}
// If the target is an add-on we need to add the Platform image as a backup.
IAndroidTarget parent = target.getParent();
if (parent != null) {
imagePath = getImageRelativePath(parent);
if (imagePath != null) {
properties.put(property, imagePath);
}
}
// we need at least one path!
return properties.containsKey(AVD_INI_IMAGES_1);
} catch (InvalidTargetPathException e) {
mSdkLog.error(e, e.getMessage());
}
return false;
| public void | updateAvd(java.lang.String name)Updates an AVD with new path to the system image folders.
// find the AVD to update. It should be be in the broken list.
AvdInfo avd = null;
synchronized (mAllAvdList) {
for (AvdInfo info : mAllAvdList) {
if (info.getName().equals(name)) {
avd = info;
break;
}
}
}
if (avd == null) {
// not in the broken list, just return.
mSdkLog.error(null, "There is no Android Virtual Device named '%s'.", name);
return;
}
// get the properties. This is a unmodifiable Map.
Map<String, String> oldProperties = avd.getProperties();
// create a new map
Map<String, String> properties = new HashMap<String, String>();
properties.putAll(oldProperties);
AvdStatus status;
// create the path to the new system images.
if (setImagePathProperties(avd.getTarget(), properties)) {
if (properties.containsKey(AVD_INI_IMAGES_1)) {
mSdkLog.printf("Updated '%1$s' with value '%2$s'\n", AVD_INI_IMAGES_1,
properties.get(AVD_INI_IMAGES_1));
}
if (properties.containsKey(AVD_INI_IMAGES_2)) {
mSdkLog.printf("Updated '%1$s' with value '%2$s'\n", AVD_INI_IMAGES_2,
properties.get(AVD_INI_IMAGES_2));
}
status = AvdStatus.OK;
} else {
mSdkLog.error(null, "Unable to find non empty system images folders for %1$s", name);
//FIXME: display paths to empty image folders?
status = AvdStatus.ERROR_IMAGE_DIR;
}
// now write the config file
File configIniFile = new File(avd.getPath(), CONFIG_INI);
writeIniFile(configIniFile, properties);
// finally create a new AvdInfo for this unbroken avd and add it to the list.
// instead of creating the AvdInfo object directly we reparse it, to detect other possible
// errors
// FIXME: We may want to create this AvdInfo by reparsing the AVD instead. This could detect other errors.
AvdInfo newAvd = new AvdInfo(
name,
avd.getPath(),
avd.getTargetHash(),
avd.getTarget(),
properties,
status);
replaceAvd(avd, newAvd);
| private static void | writeIniFile(java.io.File iniFile, java.util.Map values)Writes a .ini file from a set of properties.
FileWriter writer = new FileWriter(iniFile);
for (Entry<String, String> entry : values.entrySet()) {
writer.write(String.format("%1$s=%2$s\n", entry.getKey(), entry.getValue()));
}
writer.close();
|
|