aboutsummaryrefslogtreecommitdiffstats
path: root/sdkmanager/libs/sdklib/src/com/android
diff options
context:
space:
mode:
Diffstat (limited to 'sdkmanager/libs/sdklib/src/com/android')
-rw-r--r--sdkmanager/libs/sdklib/src/com/android/sdklib/AddOnTarget.java35
-rw-r--r--sdkmanager/libs/sdklib/src/com/android/sdklib/IAndroidTarget.java12
-rw-r--r--sdkmanager/libs/sdklib/src/com/android/sdklib/PlatformTarget.java42
-rw-r--r--sdkmanager/libs/sdklib/src/com/android/sdklib/SdkConstants.java44
-rw-r--r--sdkmanager/libs/sdklib/src/com/android/sdklib/SdkManager.java77
-rwxr-xr-xsdkmanager/libs/sdklib/src/com/android/sdklib/internal/avd/AvdInfo.java334
-rw-r--r--sdkmanager/libs/sdklib/src/com/android/sdklib/internal/avd/AvdManager.java734
-rw-r--r--sdkmanager/libs/sdklib/src/com/android/sdklib/internal/build/DebugKeyProvider.java38
-rw-r--r--sdkmanager/libs/sdklib/src/com/android/sdklib/internal/export/MultiApkExportHelper.java6
-rw-r--r--sdkmanager/libs/sdklib/src/com/android/sdklib/internal/project/ProjectCreator.java5
-rw-r--r--sdkmanager/libs/sdklib/src/com/android/sdklib/internal/project/ProjectProperties.java8
-rw-r--r--sdkmanager/libs/sdklib/src/com/android/sdklib/internal/project/ProjectPropertiesWorkingCopy.java6
-rwxr-xr-xsdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/AdbWrapper.java22
-rwxr-xr-xsdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/AddonPackage.java17
-rwxr-xr-xsdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/AddonsListFetcher.java10
-rwxr-xr-xsdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/ArchiveInstaller.java51
-rwxr-xr-xsdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/BrokenPackage.java14
-rwxr-xr-xsdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/DocPackage.java28
-rwxr-xr-xsdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/ExtraPackage.java53
-rwxr-xr-xsdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/ITaskMonitor.java34
-rwxr-xr-xsdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/LocalSdkParser.java6
-rwxr-xr-xsdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/OsHelper.java56
-rwxr-xr-xsdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/Package.java11
-rwxr-xr-xsdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/PlatformPackage.java30
-rwxr-xr-xsdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/PlatformToolPackage.java15
-rwxr-xr-xsdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/SamplePackage.java18
-rwxr-xr-xsdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/SdkSource.java33
-rwxr-xr-xsdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/SdkSources.java2
-rwxr-xr-xsdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/ToolPackage.java25
-rw-r--r--sdkmanager/libs/sdklib/src/com/android/sdklib/io/FileWrapper.java147
-rw-r--r--sdkmanager/libs/sdklib/src/com/android/sdklib/io/FolderWrapper.java154
-rw-r--r--sdkmanager/libs/sdklib/src/com/android/sdklib/io/IAbstractFile.java53
-rw-r--r--sdkmanager/libs/sdklib/src/com/android/sdklib/io/IAbstractFolder.java77
-rw-r--r--sdkmanager/libs/sdklib/src/com/android/sdklib/io/IAbstractResource.java45
-rw-r--r--sdkmanager/libs/sdklib/src/com/android/sdklib/io/StreamException.java28
-rw-r--r--sdkmanager/libs/sdklib/src/com/android/sdklib/xml/AndroidManifest.java7
-rw-r--r--sdkmanager/libs/sdklib/src/com/android/sdklib/xml/AndroidManifestParser.java6
37 files changed, 1245 insertions, 1038 deletions
diff --git a/sdkmanager/libs/sdklib/src/com/android/sdklib/AddOnTarget.java b/sdkmanager/libs/sdklib/src/com/android/sdklib/AddOnTarget.java
index f3da39c..866d5b6 100644
--- a/sdkmanager/libs/sdklib/src/com/android/sdklib/AddOnTarget.java
+++ b/sdkmanager/libs/sdklib/src/com/android/sdklib/AddOnTarget.java
@@ -22,6 +22,7 @@ import java.util.Arrays;
import java.util.HashSet;
import java.util.Map;
import java.util.Map.Entry;
+import java.util.ArrayList;
/**
* Represents an add-on target in the SDK.
@@ -67,6 +68,7 @@ final class AddOnTarget implements IAndroidTarget {
private final String mLocation;
private final PlatformTarget mBasePlatform;
private final String mName;
+ private String[] mAbis;
private final String mVendor;
private final int mRevision;
private final String mDescription;
@@ -74,6 +76,7 @@ final class AddOnTarget implements IAndroidTarget {
private String mDefaultSkin;
private IOptionalLibrary[] mLibraries;
private int mVendorId = NO_USB_ID;
+ private boolean mAbiCompatibilityMode;
/**
* Creates a new add-on
@@ -82,12 +85,13 @@ final class AddOnTarget implements IAndroidTarget {
* @param vendor the vendor name of the add-on
* @param revision the revision of the add-on
* @param description the add-on description
+ * @param abis list of supported abis
* @param libMap A map containing the optional libraries. The map key is the fully-qualified
* library name. The value is a 2 string array with the .jar filename, and the description.
* @param basePlatform the platform the add-on is extending.
*/
AddOnTarget(String location, String name, String vendor, int revision, String description,
- Map<String, String[]> libMap, PlatformTarget basePlatform) {
+ String[] abis, Map<String, String[]> libMap, PlatformTarget basePlatform) {
if (location.endsWith(File.separator) == false) {
location = location + File.separator;
}
@@ -99,6 +103,14 @@ final class AddOnTarget implements IAndroidTarget {
mDescription = description;
mBasePlatform = basePlatform;
+ //set compatibility mode
+ if (abis.length > 0) {
+ mAbis = abis;
+ } else {
+ mAbiCompatibilityMode = true;
+ mAbis = new String[] { SdkConstants.ABI_ARMEABI };
+ }
+
// handle the optional libraries.
if (libMap != null) {
mLibraries = new IOptionalLibrary[libMap.size()];
@@ -121,6 +133,25 @@ final class AddOnTarget implements IAndroidTarget {
return mName;
}
+ /**
+ * Return the full path for images
+ * @param abiType type of the abi
+ * @return complete path where the image files are located
+ */
+ public String getImagePath(String abiType) {
+
+ if (mAbiCompatibilityMode) {
+ // Use legacy directory structure if only arm
+ return mLocation + SdkConstants.OS_IMAGES_FOLDER;
+ } else {
+ return mLocation + SdkConstants.OS_IMAGES_FOLDER + abiType + File.separator;
+ }
+ }
+
+ public String[] getAbiList() {
+ return mAbis;
+ }
+
public String getVendor() {
return mVendor;
}
@@ -160,8 +191,6 @@ final class AddOnTarget implements IAndroidTarget {
public String getPath(int pathId) {
switch (pathId) {
- case IMAGES:
- return mLocation + SdkConstants.OS_IMAGES_FOLDER;
case SKINS:
return mLocation + SdkConstants.OS_SKINS_FOLDER;
case DOCS:
diff --git a/sdkmanager/libs/sdklib/src/com/android/sdklib/IAndroidTarget.java b/sdkmanager/libs/sdklib/src/com/android/sdklib/IAndroidTarget.java
index c0dcaa7..2ca7763 100644
--- a/sdkmanager/libs/sdklib/src/com/android/sdklib/IAndroidTarget.java
+++ b/sdkmanager/libs/sdklib/src/com/android/sdklib/IAndroidTarget.java
@@ -29,8 +29,6 @@ public interface IAndroidTarget extends Comparable<IAndroidTarget> {
public final static int ANDROID_JAR = 1;
/** OS Path to the "framework.aidl" file. */
public final static int ANDROID_AIDL = 2;
- /** OS Path to "images" folder which contains the emulator system images. */
- public final static int IMAGES = 3;
/** OS Path to the "samples" folder which contains sample projects. */
public final static int SAMPLES = 4;
/** OS Path to the "skins" folder which contains the emulator skins. */
@@ -227,6 +225,16 @@ public interface IAndroidTarget extends Comparable<IAndroidTarget> {
int getUsbVendorId();
/**
+ * Returns array of permitted processor architectures
+ */
+ public String[] getAbiList();
+
+ /**
+ * Returns string to append to images directory for current ProcessorType
+ */
+ public String getImagePath(String abiType);
+
+ /**
* Returns whether the given target is compatible with the receiver.
* <p/>
* This means that a project using the receiver's target can run on the given target.
diff --git a/sdkmanager/libs/sdklib/src/com/android/sdklib/PlatformTarget.java b/sdkmanager/libs/sdklib/src/com/android/sdklib/PlatformTarget.java
index 6aeeade..62720e7 100644
--- a/sdkmanager/libs/sdklib/src/com/android/sdklib/PlatformTarget.java
+++ b/sdkmanager/libs/sdklib/src/com/android/sdklib/PlatformTarget.java
@@ -21,6 +21,7 @@ import com.android.sdklib.util.SparseArray;
import java.io.File;
import java.util.Collections;
import java.util.Map;
+import java.util.ArrayList;
/**
* Represents a platform target in the SDK.
@@ -43,21 +44,25 @@ final class PlatformTarget implements IAndroidTarget {
private final Map<String, String> mProperties;
private final SparseArray<String> mPaths = new SparseArray<String>();
private String[] mSkins;
+ private String[] mAbis;
+ private boolean mAbiCompatibilityMode;
/**
* Creates a Platform target.
* @param sdkOsPath the root folder of the SDK
* @param platformOSPath the root folder of the platform component
- * @param properties the platform properties
* @param apiLevel the API Level
* @param codeName the codename. can be null.
* @param versionName the version name of the platform.
* @param revision the revision of the platform component.
+ * @param abis the list of supported abis
+ * @param properties the platform properties
*/
@SuppressWarnings("deprecation")
- PlatformTarget(String sdkOsPath, String platformOSPath, Map<String, String> properties,
- int apiLevel, String codeName, String versionName, int revision) {
+ PlatformTarget(String sdkOsPath, String platformOSPath, int apiLevel,
+ String codeName, String versionName, int revision, String[] abis,
+ Map<String, String> properties) {
if (platformOSPath.endsWith(File.separator) == false) {
platformOSPath = platformOSPath + File.separator;
}
@@ -79,7 +84,6 @@ final class PlatformTarget implements IAndroidTarget {
mPaths.put(ANDROID_AIDL, mRootFolderOsPath + SdkConstants.FN_FRAMEWORK_AIDL);
mPaths.put(ANDROID_RS, mRootFolderOsPath + SdkConstants.OS_FRAMEWORK_RS);
mPaths.put(ANDROID_RS_CLANG, mRootFolderOsPath + SdkConstants.OS_FRAMEWORK_RS_CLANG);
- mPaths.put(IMAGES, mRootFolderOsPath + SdkConstants.OS_IMAGES_FOLDER);
mPaths.put(SAMPLES, mRootFolderOsPath + SdkConstants.OS_PLATFORM_SAMPLES_FOLDER);
mPaths.put(SKINS, mRootFolderOsPath + SdkConstants.OS_SKINS_FOLDER);
mPaths.put(TEMPLATES, mRootFolderOsPath + SdkConstants.OS_PLATFORM_TEMPLATES_FOLDER);
@@ -112,6 +116,36 @@ final class PlatformTarget implements IAndroidTarget {
SdkConstants.FN_DX);
mPaths.put(DX_JAR, sdkOsPath + SdkConstants.OS_SDK_PLATFORM_TOOLS_LIB_FOLDER +
SdkConstants.FN_DX_JAR);
+
+ //set compatibility mode, abis length would be 0 for older APIs
+ if (abis.length > 0) {
+ mAbis = abis;
+ } else {
+ mAbiCompatibilityMode = true;
+ mAbis = new String[] { SdkConstants.ABI_ARMEABI };
+ }
+
+ }
+
+ /**
+ * Return the full path for images
+ * @param abiType type of the abi
+ * @return complete path where the image files are located
+ */
+ public String getImagePath(String abiType) {
+ if (mAbiCompatibilityMode) {
+ // Use legacy directory structure if only arm is supported
+ return mRootFolderOsPath + SdkConstants.OS_IMAGES_FOLDER;
+ } else {
+ return mRootFolderOsPath + SdkConstants.OS_IMAGES_FOLDER + abiType + File.separator;
+ }
+ }
+
+ /**
+ * Retrieve and return the list of abis
+ */
+ public String[] getAbiList() {
+ return mAbis;
}
public String getLocation() {
diff --git a/sdkmanager/libs/sdklib/src/com/android/sdklib/SdkConstants.java b/sdkmanager/libs/sdklib/src/com/android/sdklib/SdkConstants.java
index 37265b1..f75d3a9 100644
--- a/sdkmanager/libs/sdklib/src/com/android/sdklib/SdkConstants.java
+++ b/sdkmanager/libs/sdklib/src/com/android/sdklib/SdkConstants.java
@@ -16,6 +16,8 @@
package com.android.sdklib;
+import com.android.AndroidConstants;
+
import java.io.File;
/**
@@ -130,9 +132,13 @@ public final class SdkConstants {
public final static String FN_ADB = (CURRENT_PLATFORM == PLATFORM_WINDOWS) ?
"adb.exe" : "adb"; //$NON-NLS-1$ //$NON-NLS-2$
- /** emulator executable (with extension for the current OS) */
- public final static String FN_EMULATOR = (CURRENT_PLATFORM == PLATFORM_WINDOWS) ?
- "emulator.exe" : "emulator"; //$NON-NLS-1$ //$NON-NLS-2$
+ /** emulator executable (_WITHOUT_ extension for the current OS) */
+ public final static String FN_EMULATOR =
+ "emulator"; //$NON-NLS-1$ //$NON-NLS-2$
+
+ /** emulator executable extension for the current OS */
+ public final static String FN_EMULATOR_EXTENSION = (CURRENT_PLATFORM == PLATFORM_WINDOWS) ?
+ ".exe" : ""; //$NON-NLS-1$ //$NON-NLS-2$
/** zipalign executable (with extension for the current OS) */
public final static String FN_ZIPALIGN = (CURRENT_PLATFORM == PLATFORM_WINDOWS) ?
@@ -180,28 +186,6 @@ public final class SdkConstants {
public final static String FD_APK_NATIVE_LIBS = "lib"; //$NON-NLS-1$
/** Default output folder name, i.e. "bin" */
public final static String FD_OUTPUT = "bin"; //$NON-NLS-1$
- /** Default anim resource folder name, i.e. "anim" */
- public final static String FD_ANIM = "anim"; //$NON-NLS-1$
- /** Default animator resource folder name, i.e. "animator" */
- public final static String FD_ANIMATOR = "animator"; //$NON-NLS-1$
- /** Default color resource folder name, i.e. "color" */
- public final static String FD_COLOR = "color"; //$NON-NLS-1$
- /** Default drawable resource folder name, i.e. "drawable" */
- public final static String FD_DRAWABLE = "drawable"; //$NON-NLS-1$
- /** Default interpolator resource folder name, i.e. "interpolator" */
- public final static String FD_INTERPOLATOR = "interpolator"; //$NON-NLS-1$
- /** Default layout resource folder name, i.e. "layout" */
- public final static String FD_LAYOUT = "layout"; //$NON-NLS-1$
- /** Default menu resource folder name, i.e. "menu" */
- public final static String FD_MENU = "menu"; //$NON-NLS-1$
- /** Default menu resource folder name, i.e. "mipmap" */
- public final static String FD_MIPMAP = "mipmap"; //$NON-NLS-1$
- /** Default values resource folder name, i.e. "values" */
- public final static String FD_VALUES = "values"; //$NON-NLS-1$
- /** Default xml resource folder name, i.e. "xml" */
- public final static String FD_XML = "xml"; //$NON-NLS-1$
- /** Default raw resource folder name, i.e. "raw" */
- public final static String FD_RAW = "raw"; //$NON-NLS-1$
/** proguard output folder for mapping, etc.. files */
public final static String FD_PROGUARD = "proguard"; //$NON-NLS-1$
@@ -223,6 +207,10 @@ public final class SdkConstants {
public static final String FD_DOCS_REFERENCE = "reference";
/** Name of the SDK images folder. */
public final static String FD_IMAGES = "images";
+ /** Name of the processors to support. */
+ public final static String ABI_ARMEABI = "armeabi";
+ public final static String ABI_INTEL_ATOM = "x86";
+
/** Name of the SDK skins folder. */
public final static String FD_SKINS = "skins";
/** Name of the SDK samples folder. */
@@ -336,11 +324,13 @@ public final class SdkConstants {
/** Path of the attrs.xml file relative to a platform folder. */
public final static String OS_PLATFORM_ATTRS_XML =
- OS_PLATFORM_RESOURCES_FOLDER + FD_VALUES + File.separator + FN_ATTRS_XML;
+ OS_PLATFORM_RESOURCES_FOLDER + AndroidConstants.FD_RES_VALUES + File.separator +
+ FN_ATTRS_XML;
/** Path of the attrs_manifest.xml file relative to a platform folder. */
public final static String OS_PLATFORM_ATTRS_MANIFEST_XML =
- OS_PLATFORM_RESOURCES_FOLDER + FD_VALUES + File.separator + FN_ATTRS_MANIFEST_XML;
+ OS_PLATFORM_RESOURCES_FOLDER + AndroidConstants.FD_RES_VALUES + File.separator +
+ FN_ATTRS_MANIFEST_XML;
/** Path of the layoutlib.jar file relative to a platform folder. */
public final static String OS_PLATFORM_LAYOUTLIB_JAR =
diff --git a/sdkmanager/libs/sdklib/src/com/android/sdklib/SdkManager.java b/sdkmanager/libs/sdklib/src/com/android/sdklib/SdkManager.java
index 3e6e23e..d924d3d 100644
--- a/sdkmanager/libs/sdklib/src/com/android/sdklib/SdkManager.java
+++ b/sdkmanager/libs/sdklib/src/com/android/sdklib/SdkManager.java
@@ -18,11 +18,11 @@ package com.android.sdklib;
import com.android.annotations.VisibleForTesting;
import com.android.annotations.VisibleForTesting.Visibility;
+import com.android.io.FileWrapper;
import com.android.prefs.AndroidLocation;
import com.android.prefs.AndroidLocation.AndroidLocationException;
import com.android.sdklib.AndroidVersion.AndroidVersionException;
import com.android.sdklib.internal.project.ProjectProperties;
-import com.android.sdklib.io.FileWrapper;
import com.android.util.Pair;
import java.io.File;
@@ -233,13 +233,17 @@ public class SdkManager {
/**
* Loads the Platforms from the SDK.
+ * Creates the "platforms" folder if necessary.
+ *
* @param sdkOsPath Location of the SDK
* @param list the list to fill with the platforms.
* @param log the ISdkLog object receiving warning/error from the parsing. Cannot be null.
+ * @throws RuntimeException when the "platforms" folder is missing and cannot be created.
*/
private static void loadPlatforms(String sdkOsPath, ArrayList<IAndroidTarget> list,
ISdkLog log) {
File platformFolder = new File(sdkOsPath, SdkConstants.FD_PLATFORMS);
+
if (platformFolder.isDirectory()) {
File[] platforms = platformFolder.listFiles();
@@ -257,15 +261,18 @@ public class SdkManager {
return;
}
- String message = null;
- if (platformFolder.exists() == false) {
- message = "%s is missing.";
+ // Try to create it or complain if something else is in the way.
+ if (!platformFolder.exists()) {
+ if (!platformFolder.mkdir()) {
+ throw new RuntimeException(
+ String.format("Failed to create %1$s.",
+ platformFolder.getAbsolutePath()));
+ }
} else {
- message = "%s is not a folder.";
+ throw new RuntimeException(
+ String.format("%1$s is not a folder.",
+ platformFolder.getAbsolutePath()));
}
-
- throw new IllegalArgumentException(String.format(message,
- platformFolder.getAbsolutePath()));
}
/**
@@ -355,15 +362,17 @@ public class SdkManager {
return null;
}
+ String[] abiList = getAbiList(platformFolder.getAbsolutePath());
// create the target.
PlatformTarget target = new PlatformTarget(
sdkOsPath,
platformFolder.getAbsolutePath(),
- map,
apiNumber,
apiCodename,
apiName,
- revision);
+ revision,
+ abiList,
+ map);
// need to parse the skins.
String[] skins = parseSkinFolder(target.getPath(IAndroidTarget.SKINS));
@@ -380,15 +389,43 @@ public class SdkManager {
return null;
}
+ /**
+ * Get all the abi types supported for a given target
+ * @param path Path where the images folder for a target is located
+ * @return an array of strings containing all the abi names for the target
+ */
+ private static String[] getAbiList(String path) {
+ ArrayList<String> list = new ArrayList<String>();
+
+ File imagesFolder = new File(path + File.separator + SdkConstants.OS_IMAGES_FOLDER);
+ File[] files = imagesFolder.listFiles();
+
+ if (files != null) {
+ // Loop through Images directory. If subdirectories exist, set multiprocessor mode
+ for (File file : files) {
+ if (file.isDirectory()) {
+ list.add(file.getName());
+ }
+ }
+ }
+ String[] abis = new String[list.size()];
+ list.toArray(abis);
+
+ return abis;
+ }
/**
* Loads the Add-on from the SDK.
+ * Creates the "add-ons" folder if necessary.
+ *
* @param osSdkPath Location of the SDK
* @param list the list to fill with the add-ons.
* @param log the ISdkLog object receiving warning/error from the parsing. Cannot be null.
+ * @throws RuntimeException when the "add-ons" folder is missing and cannot be created.
*/
private static void loadAddOns(String osSdkPath, ArrayList<IAndroidTarget> list, ISdkLog log) {
File addonFolder = new File(osSdkPath, SdkConstants.FD_ADDONS);
+
if (addonFolder.isDirectory()) {
File[] addons = addonFolder.listFiles();
@@ -407,15 +444,18 @@ public class SdkManager {
return;
}
- String message = null;
- if (addonFolder.exists() == false) {
- message = "%s is missing.";
+ // Try to create it or complain if something else is in the way.
+ if (!addonFolder.exists()) {
+ if (!addonFolder.mkdir()) {
+ throw new RuntimeException(
+ String.format("Failed to create %1$s.",
+ addonFolder.getAbsolutePath()));
+ }
} else {
- message = "%s is not a folder.";
+ throw new RuntimeException(
+ String.format("%1$s is not a folder.",
+ addonFolder.getAbsolutePath()));
}
-
- throw new IllegalArgumentException(String.format(message,
- addonFolder.getAbsolutePath()));
}
/**
@@ -514,8 +554,9 @@ public class SdkManager {
}
}
+ String[] abiList = getAbiList(addonDir.getAbsolutePath());
AddOnTarget target = new AddOnTarget(addonDir.getAbsolutePath(), name, vendor,
- revisionValue, description, libMap, baseTarget);
+ revisionValue, description, abiList, libMap, baseTarget);
// need to parse the skins.
String[] skins = parseSkinFolder(target.getPath(IAndroidTarget.SKINS));
diff --git a/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/avd/AvdInfo.java b/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/avd/AvdInfo.java
new file mode 100755
index 0000000..81ffa5d
--- /dev/null
+++ b/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/avd/AvdInfo.java
@@ -0,0 +1,334 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.sdklib.internal.avd;
+
+import com.android.prefs.AndroidLocation.AndroidLocationException;
+import com.android.sdklib.IAndroidTarget;
+import com.android.sdklib.SdkConstants;
+
+import java.io.File;
+import java.util.Collections;
+import java.util.Map;
+
+/**
+ * An immutable structure describing an Android Virtual Device.
+ */
+public final class AvdInfo implements Comparable<AvdInfo> {
+
+ /**
+ * Status for an {@link AvdInfo}. Indicates whether or not this AVD is valid.
+ */
+ public static enum AvdStatus {
+ /** No error */
+ OK,
+ /** Missing 'path' property in the ini file */
+ ERROR_PATH,
+ /** Missing config.ini file in the AVD data folder */
+ ERROR_CONFIG,
+ /** Missing 'target' property in the ini file */
+ ERROR_TARGET_HASH,
+ /** Target was not resolved from its hash */
+ ERROR_TARGET,
+ /** Unable to parse config.ini */
+ ERROR_PROPERTIES,
+ /** System Image folder in config.ini doesn't exist */
+ ERROR_IMAGE_DIR;
+ }
+
+ private final String mName;
+ private final File mIniFile;
+ private final String mFolderPath;
+ private final String mTargetHash;
+ private final IAndroidTarget mTarget;
+ private final String mAbiType;
+ private final Map<String, String> mProperties;
+ private final AvdStatus mStatus;
+
+ /**
+ * Creates a new valid AVD info. Values are immutable.
+ * <p/>
+ * Such an AVD is available and can be used.
+ * The error string is set to null.
+ *
+ * @param name The name of the AVD (for display or reference)
+ * @param iniFile The path to the config.ini file
+ * @param folderPath The path to the data directory
+ * @param targetHash the target hash
+ * @param target The target. Can be null, if the target was not resolved.
+ * @param abiType Name of the abi.
+ * @param properties The property map. Cannot be null.
+ */
+ public AvdInfo(String name,
+ File iniFile,
+ String folderPath,
+ String targetHash,
+ IAndroidTarget target,
+ String abiType,
+ Map<String, String> properties) {
+ this(name, iniFile, folderPath, targetHash, target, abiType, properties, AvdStatus.OK);
+ }
+
+ /**
+ * Creates a new <em>invalid</em> AVD info. Values are immutable.
+ * <p/>
+ * Such an AVD is not complete and cannot be used.
+ * The error string must be non-null.
+ *
+ * @param name The name of the AVD (for display or reference)
+ * @param iniFile The path to the config.ini file
+ * @param folderPath The path to the data directory
+ * @param targetHash the target hash
+ * @param target The target. Can be null, if the target was not resolved.
+ * @param abiType Name of the abi.
+ * @param properties The property map. Can be null.
+ * @param status The {@link AvdStatus} of this AVD. Cannot be null.
+ */
+ public AvdInfo(String name,
+ File iniFile,
+ String folderPath,
+ String targetHash,
+ IAndroidTarget target,
+ String abiType,
+ Map<String, String> properties,
+ AvdStatus status) {
+ mName = name;
+ mIniFile = iniFile;
+ mFolderPath = folderPath;
+ mTargetHash = targetHash;
+ mTarget = target;
+ mAbiType = abiType;
+ mProperties = properties == null ? null : Collections.unmodifiableMap(properties);
+ mStatus = status;
+ }
+
+ /** Returns the name of the AVD. */
+ public String getName() {
+ return mName;
+ }
+
+ /** Returns the path of the AVD data directory. */
+ public String getDataFolderPath() {
+ return mFolderPath;
+ }
+
+ /** Returns the processor type of the AVD. */
+ public String getAbiType() {
+ return mAbiType;
+ }
+
+ /** Convenience function to return a more user friendly name of the abi type. */
+ public static String getPrettyAbiType(String raw) {
+ String s = null;
+ if (raw.equalsIgnoreCase(SdkConstants.ABI_ARMEABI)) {
+ s = "ARM (" + SdkConstants.ABI_ARMEABI + ")";
+ }
+ else if (raw.equalsIgnoreCase(SdkConstants.ABI_INTEL_ATOM)) {
+ s = "Intel Atom (" + SdkConstants.ABI_INTEL_ATOM + ")";
+ }
+ else {
+ s = raw + " (" + raw + ")";
+ }
+ return s;
+ }
+
+ /**
+ * Returns the emulator executable path
+ * @param sdkPath path of the sdk
+ * @return path of the emulator executable
+ */
+ public String getEmulatorPath(String sdkPath) {
+ String path = sdkPath + SdkConstants.OS_SDK_TOOLS_FOLDER;
+
+ // Start with base name of the emulator
+ path = path + SdkConstants.FN_EMULATOR;
+
+ // If not using ARM, add processor type to emulator command line
+ boolean useAbi = !getAbiType().equalsIgnoreCase(SdkConstants.ABI_ARMEABI);
+
+ if (useAbi) {
+ path = path + "-" + getAbiType(); //$NON-NLS-1$
+ }
+ // Add OS appropriate emulator extension (e.g., .exe on windows)
+ path = path + SdkConstants.FN_EMULATOR_EXTENSION;
+
+ // HACK: The AVD manager should look for "emulator" or for "emulator-abi" (if not arm).
+ // However this is a transition period and we don't have that unified "emulator" binary
+ // in AOSP so if we can't find the generic one, look for an abi-specific one with the
+ // special case that the armeabi one is actually named emulator-arm.
+ // TODO remove this kludge once no longer necessary.
+ if (!useAbi && !(new File(path).isFile())) {
+ path = sdkPath + SdkConstants.OS_SDK_TOOLS_FOLDER;
+ path = path + SdkConstants.FN_EMULATOR;
+ path = path + "-" //$NON-NLS-1$
+ + getAbiType().replace(SdkConstants.ABI_ARMEABI, "arm"); //$NON-NLS-1$
+ path = path + SdkConstants.FN_EMULATOR_EXTENSION;
+ }
+
+ return path;
+ }
+
+ /**
+ * Returns the target hash string.
+ */
+ public String getTargetHash() {
+ return mTargetHash;
+ }
+
+ /** Returns the target of the AVD, or <code>null</code> if it has not been resolved. */
+ public IAndroidTarget getTarget() {
+ return mTarget;
+ }
+
+ /** Returns the {@link AvdStatus} of the receiver. */
+ public AvdStatus getStatus() {
+ return mStatus;
+ }
+
+ /**
+ * Helper method that returns the default AVD folder that would be used for a given
+ * AVD name <em>if and only if</em> the AVD was created with the default choice.
+ * <p/>
+ * Callers must NOT use this to "guess" the actual folder from an actual AVD since
+ * the purpose of the AVD .ini file is to be able to change this folder. Callers
+ * should however use this to create a new {@link AvdInfo} to setup its data folder
+ * to the default.
+ * <p/>
+ * The default is {@code getDefaultAvdFolder()/avdname.avd/}.
+ * <p/>
+ * For an actual existing AVD, callers must use {@link #getDataFolderPath()} instead.
+ *
+ * @param manager The AVD Manager, used to get the AVD storage path.
+ * @param avdName The name of the desired AVD.
+ * @throws AndroidLocationException if there's a problem getting android root directory.
+ */
+ public static File getDefaultAvdFolder(AvdManager manager, String avdName)
+ throws AndroidLocationException {
+ return new File(manager.getBaseAvdFolder(),
+ avdName + AvdManager.AVD_FOLDER_EXTENSION);
+ }
+
+ /**
+ * Helper method that returns the .ini {@link File} for a given AVD name.
+ * <p/>
+ * The default is {@code getDefaultAvdFolder()/avdname.ini}.
+ *
+ * @param manager The AVD Manager, used to get the AVD storage path.
+ * @param avdName The name of the desired AVD.
+ * @throws AndroidLocationException if there's a problem getting android root directory.
+ */
+ public static File getDefaultIniFile(AvdManager manager, String avdName)
+ throws AndroidLocationException {
+ String avdRoot = manager.getBaseAvdFolder();
+ return new File(avdRoot, avdName + AvdManager.INI_EXTENSION);
+ }
+
+ /**
+ * Returns the .ini {@link File} for this AVD.
+ */
+ public File getIniFile() {
+ return mIniFile;
+ }
+
+ /**
+ * Helper method that returns the Config {@link File} for a given AVD name.
+ */
+ public static File getConfigFile(String path) {
+ return new File(path, AvdManager.CONFIG_INI);
+ }
+
+ /**
+ * Returns the Config {@link File} for this AVD.
+ */
+ public File getConfigFile() {
+ return getConfigFile(mFolderPath);
+ }
+
+ /**
+ * Returns an unmodifiable map of properties for the AVD. This can be null.
+ */
+ public Map<String, String> getProperties() {
+ return mProperties;
+ }
+
+ /**
+ * Returns the error message for the AVD or <code>null</code> if {@link #getStatus()}
+ * returns {@link AvdStatus#OK}
+ */
+ public String getErrorMessage() {
+ switch (mStatus) {
+ case ERROR_PATH:
+ return String.format("Missing AVD 'path' property in %1$s", getIniFile());
+ case ERROR_CONFIG:
+ return String.format("Missing config.ini file in %1$s", mFolderPath);
+ case ERROR_TARGET_HASH:
+ return String.format("Missing 'target' property in %1$s", getIniFile());
+ case ERROR_TARGET:
+ return String.format("Unknown target '%1$s' in %2$s",
+ mTargetHash, getIniFile());
+ case ERROR_PROPERTIES:
+ return String.format("Failed to parse properties from %1$s",
+ getConfigFile());
+ case ERROR_IMAGE_DIR:
+ return String.format(
+ "Invalid value in image.sysdir. Run 'android update avd -n %1$s'",
+ mName);
+ case OK:
+ assert false;
+ return null;
+ }
+
+ return null;
+ }
+
+ /**
+ * Returns whether an emulator is currently running the AVD.
+ */
+ public boolean isRunning() {
+ File f = new File(mFolderPath, "userdata-qemu.img.lock"); //$NON-NLS-1$
+ return f.isFile();
+ }
+
+ /**
+ * Compares this object with the specified object for order. Returns a
+ * negative integer, zero, or a positive integer as this object is less
+ * than, equal to, or greater than the specified object.
+ *
+ * @param o the Object to be compared.
+ * @return a negative integer, zero, or a positive integer as this object is
+ * less than, equal to, or greater than the specified object.
+ */
+ public int compareTo(AvdInfo o) {
+ // first handle possible missing targets (if the AVD failed to load for unresolved targets)
+ if (mTarget == null && o != null && o.mTarget == null) {
+ return 0;
+ } if (mTarget == null) {
+ return +1;
+ } else if (o == null || o.mTarget == null) {
+ return -1;
+ }
+
+ // then compare the targets
+ int targetDiff = mTarget.compareTo(o.mTarget);
+
+ if (targetDiff == 0) {
+ // same target? compare on the avd name
+ return mName.compareTo(o.mName);
+ }
+
+ return targetDiff;
+ }
+}
diff --git a/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/avd/AvdManager.java b/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/avd/AvdManager.java
index eba8e07..c9a3561 100644
--- a/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/avd/AvdManager.java
+++ b/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/avd/AvdManager.java
@@ -16,15 +16,16 @@
package com.android.sdklib.internal.avd;
+import com.android.io.FileWrapper;
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.SdkConstants;
import com.android.sdklib.SdkManager;
-import com.android.sdklib.internal.avd.AvdManager.AvdInfo.AvdStatus;
+import com.android.sdklib.internal.avd.AvdInfo.AvdStatus;
import com.android.sdklib.internal.project.ProjectProperties;
-import com.android.sdklib.io.FileWrapper;
+import com.android.util.Pair;
import java.io.BufferedReader;
import java.io.File;
@@ -37,7 +38,6 @@ import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.util.ArrayList;
-import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
@@ -47,7 +47,7 @@ import java.util.regex.Pattern;
/**
* Android Virtual Device Manager to manage AVDs.
*/
-public final class AvdManager {
+public class AvdManager {
/**
* Exception thrown when something is wrong with a target path.
@@ -66,6 +66,13 @@ public final class AvdManager {
public final static String AVD_INFO_TARGET = "target"; //$NON-NLS-1$
/**
+ * AVD/config.ini key name representing the abi type of the specific avd
+ *
+ */
+ public final static String AVD_INI_ABI_TYPE = "abi.type"; //$NON-NLS-1$
+
+
+ /**
* AVD/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.
*
@@ -92,6 +99,7 @@ public final class AvdManager {
* This property is for UI purposes only. It is not used by the emulator.
*
* @see #SDCARD_SIZE_PATTERN
+ * @see #parseSdcardSize(String, String[])
*/
public final static String AVD_INI_SDCARD_SIZE = "sdcard.size"; //$NON-NLS-1$
/**
@@ -123,11 +131,11 @@ public final class AvdManager {
public final static Pattern NUMERIC_SKIN_SIZE = Pattern.compile("([0-9]{2,})x([0-9]{2,})"); //$NON-NLS-1$
private final static String USERDATA_IMG = "userdata.img"; //$NON-NLS-1$
- private final static String CONFIG_INI = "config.ini"; //$NON-NLS-1$
+ final static String CONFIG_INI = "config.ini"; //$NON-NLS-1$
private final static String SDCARD_IMG = "sdcard.img"; //$NON-NLS-1$
private final static String SNAPSHOTS_IMG = "snapshots.img"; //$NON-NLS-1$
- private final static String INI_EXTENSION = ".ini"; //$NON-NLS-1$
+ final static String INI_EXTENSION = ".ini"; //$NON-NLS-1$
private final static Pattern INI_NAME_PATTERN = Pattern.compile("(.+)\\" + //$NON-NLS-1$
INI_EXTENSION + "$", //$NON-NLS-1$
Pattern.CASE_INSENSITIVE);
@@ -137,8 +145,26 @@ public final class AvdManager {
/**
* Pattern for matching SD Card sizes, e.g. "4K" or "16M".
+ * Callers should use {@link #parseSdcardSize(String, String[])} instead of using this directly.
+ */
+ private final static Pattern SDCARD_SIZE_PATTERN = Pattern.compile("(\\d+)([KMG])"); //$NON-NLS-1$
+
+ /**
+ * Minimal size of an SDCard image file in bytes. Currently 9 MiB.
+ */
+
+ public static final long SDCARD_MIN_BYTE_SIZE = 9<<20;
+ /**
+ * Maximal size of an SDCard image file in bytes. Currently 1023 GiB.
*/
- public final static Pattern SDCARD_SIZE_PATTERN = Pattern.compile("(\\d+)([MK])"); //$NON-NLS-1$
+ public static final long SDCARD_MAX_BYTE_SIZE = 1023L<<30;
+
+ /** The sdcard string represents a valid number but the size is outside of the allowed range. */
+ public final static int SDCARD_SIZE_NOT_IN_RANGE = 0;
+ /** The sdcard string looks like a size number+suffix but the number failed to decode. */
+ public final static int SDCARD_SIZE_INVALID = -1;
+ /** The sdcard string doesn't look like a size, it might be a path instead. */
+ public final static int SDCARD_NOT_SIZE_PATTERN = -2;
/** Regex used to validate characters that compose an AVD name. */
public final static Pattern RE_AVD_NAME = Pattern.compile("[a-zA-Z0-9._-]+"); //$NON-NLS-1$
@@ -148,212 +174,21 @@ public final class AvdManager {
public final static String HARDWARE_INI = "hardware.ini"; //$NON-NLS-1$
- /** An immutable structure describing an Android Virtual Device. */
- public static final class AvdInfo implements Comparable<AvdInfo> {
-
- /**
- * Status for an {@link AvdInfo}. Indicates whether or not this AVD is valid.
- */
- public static enum AvdStatus {
- /** No error */
- OK,
- /** Missing 'path' property in the ini file */
- ERROR_PATH,
- /** Missing config.ini file in the AVD data folder */
- ERROR_CONFIG,
- /** Missing 'target' property in the ini file */
- ERROR_TARGET_HASH,
- /** Target was not resolved from its hash */
- ERROR_TARGET,
- /** Unable to parse config.ini */
- ERROR_PROPERTIES,
- /** System Image folder in config.ini doesn't exist */
- ERROR_IMAGE_DIR;
- }
-
- private final String mName;
- private final String mPath;
- private final String mTargetHash;
- private final IAndroidTarget mTarget;
- private final Map<String, String> mProperties;
- private final AvdStatus mStatus;
-
- /**
- * Creates a new valid AVD info. Values are immutable.
- * <p/>
- * Such an AVD is available and can be used.
- * The error string is set to null.
- *
- * @param name The name of the AVD (for display or reference)
- * @param path The path to the config.ini file
- * @param targetHash the target hash
- * @param target The target. Can be null, if the target was not resolved.
- * @param properties The property map. Cannot be null.
- */
- public AvdInfo(String name, String path, String targetHash, IAndroidTarget target,
- Map<String, String> properties) {
- this(name, path, targetHash, target, properties, AvdStatus.OK);
- }
-
- /**
- * Creates a new <em>invalid</em> AVD info. Values are immutable.
- * <p/>
- * Such an AVD is not complete and cannot be used.
- * The error string must be non-null.
- *
- * @param name The name of the AVD (for display or reference)
- * @param path The path to the config.ini file
- * @param targetHash the target hash
- * @param target The target. Can be null, if the target was not resolved.
- * @param properties The property map. Can be null.
- * @param status The {@link AvdStatus} of this AVD. Cannot be null.
- */
- public AvdInfo(String name, String path, String targetHash, IAndroidTarget target,
- Map<String, String> properties, AvdStatus status) {
- mName = name;
- mPath = path;
- mTargetHash = targetHash;
- mTarget = target;
- mProperties = properties == null ? null : Collections.unmodifiableMap(properties);
- mStatus = status;
- }
-
- /** Returns the name of the AVD. */
- public String getName() {
- return mName;
- }
-
- /** Returns the path of the AVD data directory. */
- public String getPath() {
- return mPath;
- }
-
- /**
- * Returns the target hash string.
- */
- public String getTargetHash() {
- return mTargetHash;
- }
-
- /** Returns the target of the AVD, or <code>null</code> if it has not been resolved. */
- public IAndroidTarget getTarget() {
- return mTarget;
- }
-
- /** Returns the {@link AvdStatus} of the receiver. */
- public AvdStatus getStatus() {
- return mStatus;
- }
-
- /**
- * Helper method that returns the .ini {@link File} for a given AVD name.
- * @throws AndroidLocationException if there's a problem getting android root directory.
- */
- public static File getIniFile(String name) throws AndroidLocationException {
- String avdRoot;
- avdRoot = getBaseAvdFolder();
- return new File(avdRoot, name + INI_EXTENSION);
- }
-
- /**
- * Returns the .ini {@link File} for this AVD.
- * @throws AndroidLocationException if there's a problem getting android root directory.
- */
- public File getIniFile() throws AndroidLocationException {
- return getIniFile(mName);
- }
-
- /**
- * Helper method that returns the Config {@link File} for a given AVD name.
- */
- public static File getConfigFile(String path) {
- return new File(path, CONFIG_INI);
- }
-
- /**
- * Returns the Config {@link File} for this AVD.
- */
- public File getConfigFile() {
- return getConfigFile(mPath);
- }
-
- /**
- * Returns an unmodifiable map of properties for the AVD. This can be null.
- */
- public Map<String, String> getProperties() {
- return mProperties;
- }
-
- /**
- * Returns the error message for the AVD or <code>null</code> if {@link #getStatus()}
- * returns {@link AvdStatus#OK}
- */
- public String getErrorMessage() {
- try {
- switch (mStatus) {
- case ERROR_PATH:
- return String.format("Missing AVD 'path' property in %1$s", getIniFile());
- case ERROR_CONFIG:
- return String.format("Missing config.ini file in %1$s", mPath);
- case ERROR_TARGET_HASH:
- return String.format("Missing 'target' property in %1$s", getIniFile());
- case ERROR_TARGET:
- return String.format("Unknown target '%1$s' in %2$s",
- mTargetHash, getIniFile());
- case ERROR_PROPERTIES:
- return String.format("Failed to parse properties from %1$s",
- getConfigFile());
- case ERROR_IMAGE_DIR:
- return String.format(
- "Invalid value in image.sysdir. Run 'android update avd -n %1$s'",
- mName);
- case OK:
- assert false;
- return null;
- }
- } catch (AndroidLocationException e) {
- return "Unable to get HOME folder.";
- }
-
- return null;
- }
-
- /**
- * Returns whether an emulator is currently running the AVD.
- */
- public boolean isRunning() {
- File f = new File(mPath, "userdata-qemu.img.lock");
- return f.isFile();
- }
-
+ /**
+ * Status returned by {@link AvdManager#isAvdNameConflicting(String)}.
+ */
+ public static enum AvdConflict {
+ /** There is no known conflict for the given AVD name. */
+ NO_CONFLICT,
+ /** The AVD name conflicts with an existing valid AVD. */
+ CONFLICT_EXISTING_AVD,
+ /** The AVD name conflicts with an existing invalid AVD. */
+ CONFLICT_INVALID_AVD,
/**
- * Compares this object with the specified object for order. Returns a
- * negative integer, zero, or a positive integer as this object is less
- * than, equal to, or greater than the specified object.
- *
- * @param o the Object to be compared.
- * @return a negative integer, zero, or a positive integer as this object is
- * less than, equal to, or greater than the specified object.
+ * The AVD name does not conflict with any known AVD however there are
+ * files or directory that would cause a conflict if this were to be created.
*/
- public int compareTo(AvdInfo o) {
- // first handle possible missing targets (if the AVD failed to load for
- // unresolved targets.
- if (mTarget == null) {
- return +1;
- } else if (o.mTarget == null) {
- return -1;
- }
-
- // then compare the targets
- int targetDiff = mTarget.compareTo(o.mTarget);
-
- if (targetDiff == 0) {
- // same target? compare on the avd name
- return mName.compareTo(o.mName);
- }
-
- return targetDiff;
- }
+ CONFLICT_EXISTING_PATH,
}
private final ArrayList<AvdInfo> mAllAvdList = new ArrayList<AvdInfo>();
@@ -362,15 +197,6 @@ public final class AvdManager {
private final SdkManager mSdkManager;
/**
- * Returns the base folder where AVDs are created.
- *
- * @throws AndroidLocationException
- */
- public static String getBaseAvdFolder() throws AndroidLocationException {
- return AndroidLocation.getFolder() + AndroidLocation.FOLDER_AVD;
- }
-
- /**
* Creates an AVD Manager for a given SDK represented by a {@link SdkManager}.
* @param sdkManager The SDK.
* @param log The log object to receive the log of the initial loading of the AVDs.
@@ -386,6 +212,16 @@ public final class AvdManager {
}
/**
+ * Returns the base folder where AVDs are created.
+ *
+ * @throws AndroidLocationException
+ */
+ public String getBaseAvdFolder() throws AndroidLocationException {
+ assert AndroidLocation.getFolder().endsWith(File.separator);
+ return AndroidLocation.getFolder() + AndroidLocation.FOLDER_AVD;
+ }
+
+ /**
* Returns the {@link SdkManager} associated with the {@link AvdManager}.
*/
public SdkManager getSdkManager() {
@@ -393,6 +229,71 @@ public final class AvdManager {
}
/**
+ * Parse the sdcard string to decode the size.
+ * Returns:
+ * <ul>
+ * <li> The size in bytes > 0 if the sdcard string is a valid size in the allowed range.
+ * <li> {@link #SDCARD_SIZE_NOT_IN_RANGE} (0)
+ * if the sdcard string is a valid size NOT in the allowed range.
+ * <li> {@link #SDCARD_SIZE_INVALID} (-1)
+ * if the sdcard string is number that fails to parse correctly.
+ * <li> {@link #SDCARD_NOT_SIZE_PATTERN} (-2)
+ * if the sdcard string is not a number, in which case it's probably a file path.
+ * </ul>
+ *
+ * @param sdcard The sdcard string, which can be a file path, a size string or something else.
+ * @param parsedStrings If non-null, an array of 2 strings. The first string will be
+ * filled with the parsed numeric size and the second one will be filled with the
+ * parsed suffix. This is filled even if the returned size is deemed out of range or
+ * failed to parse. The values are null if the sdcard is not a size pattern.
+ * @return A size in byte if > 0, or {@link #SDCARD_SIZE_NOT_IN_RANGE},
+ * {@link #SDCARD_SIZE_INVALID} or {@link #SDCARD_NOT_SIZE_PATTERN} as error codes.
+ */
+ public static long parseSdcardSize(String sdcard, String[] parsedStrings) {
+
+ if (parsedStrings != null) {
+ assert parsedStrings.length == 2;
+ parsedStrings[0] = null;
+ parsedStrings[1] = null;
+ }
+
+ Matcher m = SDCARD_SIZE_PATTERN.matcher(sdcard);
+ if (m.matches()) {
+ if (parsedStrings != null) {
+ assert parsedStrings.length == 2;
+ parsedStrings[0] = m.group(1);
+ parsedStrings[1] = m.group(2);
+ }
+
+ // get the sdcard values for checks
+ try {
+ long sdcardSize = Long.parseLong(m.group(1));
+
+ String sdcardSizeModifier = m.group(2);
+ if ("K".equals(sdcardSizeModifier)) { //$NON-NLS-1$
+ sdcardSize <<= 10;
+ } else if ("M".equals(sdcardSizeModifier)) { //$NON-NLS-1$
+ sdcardSize <<= 20;
+ } else if ("G".equals(sdcardSizeModifier)) { //$NON-NLS-1$
+ sdcardSize <<= 30;
+ }
+
+ if (sdcardSize < SDCARD_MIN_BYTE_SIZE ||
+ sdcardSize > SDCARD_MAX_BYTE_SIZE) {
+ return SDCARD_SIZE_NOT_IN_RANGE;
+ }
+
+ return sdcardSize;
+ } catch (NumberFormatException e) {
+ // This could happen if the number is too large to fit in a long.
+ return SDCARD_SIZE_INVALID;
+ }
+ }
+
+ return SDCARD_NOT_SIZE_PATTERN;
+ }
+
+ /**
* Returns all the existing AVDs.
* @return a newly allocated array containing all the AVDs.
*/
@@ -476,6 +377,53 @@ public final class AvdManager {
}
/**
+ * Returns whether this AVD name would generate a conflict.
+ *
+ * @param name the name of the AVD to return
+ * @return A pair of {@link AvdConflict} and the path or AVD name that conflicts.
+ */
+ public Pair<AvdConflict, String> isAvdNameConflicting(String name) {
+
+ boolean ignoreCase = SdkConstants.currentPlatform() == SdkConstants.PLATFORM_WINDOWS;
+
+ // Check whether we have a conflict with an existing or invalid AVD
+ // known to the manager.
+ synchronized (mAllAvdList) {
+ for (AvdInfo info : mAllAvdList) {
+ String name2 = info.getName();
+ if (name2.equals(name) || (ignoreCase && name2.equalsIgnoreCase(name))) {
+ if (info.getStatus() == AvdStatus.OK) {
+ return Pair.of(AvdConflict.CONFLICT_EXISTING_AVD, name2);
+ } else {
+ return Pair.of(AvdConflict.CONFLICT_INVALID_AVD, name2);
+ }
+ }
+ }
+ }
+
+ // No conflict with known AVDs.
+ // Are some existing files/folders in the way of creating this AVD?
+
+ try {
+ File file = AvdInfo.getDefaultIniFile(this, name);
+ if (file.exists()) {
+ return Pair.of(AvdConflict.CONFLICT_EXISTING_PATH, file.getPath());
+ }
+
+ file = AvdInfo.getDefaultAvdFolder(this, name);
+ if (file.exists()) {
+ return Pair.of(AvdConflict.CONFLICT_EXISTING_PATH, file.getPath());
+ }
+
+ } catch (AndroidLocationException e) {
+ // ignore
+ }
+
+
+ return Pair.of(AvdConflict.NO_CONFLICT, null);
+ }
+
+ /**
* Reloads the AVD list.
* @param log the log object to receive action logs. Cannot be null.
* @throws AndroidLocationException if there was an error finding the location of the
@@ -495,37 +443,38 @@ public final class AvdManager {
}
/**
- * Creates a new AVD, but with no snapshot.
- *
- * See {@link #createAvd(File, String, IAndroidTarget, String, String, Map, boolean, boolean, ISdkLog)}
- **/
- @Deprecated
- public AvdInfo createAvd(File avdFolder, String name, IAndroidTarget target, String skinName,
- String sdcard, Map<String, String> hardwareConfig, boolean removePrevious,
- ISdkLog log) {
- return createAvd(avdFolder, name, target, skinName, sdcard, hardwareConfig, removePrevious,
- false, log);
- }
-
- /**
* 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 name the name of the AVD
+ * Unless you want to locate it in a specific directory, the ideal default is
+ * {@code AvdManager.AvdInfo.getAvdFolder}.
+ * @param avdName the name of the AVD
* @param target the target of the AVD
+ * @param abiType the abi type of the AVD
* @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
* an existing sdcard image or a sdcard size (\d+, \d+K, \dM).
* @param hardwareConfig the hardware setup for the AVD. Can be null to use defaults.
- * @param removePrevious If true remove any previous files.
* @param createSnapshot If true copy a blank snapshot image into the AVD.
+ * @param removePrevious If true remove any previous files.
+ * @param editExisting If true, edit an existing AVD, changing only the minimum required.
+ * This won't remove files unless required or unless {@code removePrevious} is set.
* @param log the log object to receive action logs. Cannot be null.
* @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,
- String skinName, String sdcard, Map<String,String> hardwareConfig,
- boolean removePrevious, boolean createSnapshot, ISdkLog log) {
+ public AvdInfo createAvd(
+ File avdFolder,
+ String avdName,
+ IAndroidTarget target,
+ String abiType,
+ String skinName,
+ String sdcard,
+ Map<String,String> hardwareConfig,
+ boolean createSnapshot,
+ boolean removePrevious,
+ boolean editExisting,
+ ISdkLog log) {
if (log == null) {
throw new IllegalArgumentException("log cannot be null");
}
@@ -542,8 +491,9 @@ public final class AvdManager {
} catch (SecurityException e) {
log.error(e, "Failed to delete %1$s", avdFolder.getAbsolutePath());
}
- } else {
- // AVD shouldn't already exist if removePrevious is false.
+ } else if (!editExisting) {
+ // AVD shouldn't already exist if removePrevious is false and
+ // we're not editing an existing AVD.
log.error(null,
"Folder %1$s is in the way. Use --force if you want to overwrite.",
avdFolder.getAbsolutePath());
@@ -552,23 +502,28 @@ public final class AvdManager {
} else {
// create the AVD folder.
avdFolder.mkdir();
+ // We're not editing an existing AVD.
+ editExisting = false;
}
// actually write the ini file
- iniFile = createAvdIniFile(name, avdFolder, target);
+ iniFile = createAvdIniFile(avdName, avdFolder, target, removePrevious);
// writes the userdata.img in it.
- String imagePath = target.getPath(IAndroidTarget.IMAGES);
+ String imagePath = target.getImagePath(abiType);
+
File userdataSrc = new File(imagePath, USERDATA_IMG);
if (userdataSrc.exists() == false && target.isPlatform() == false) {
- imagePath = target.getParent().getPath(IAndroidTarget.IMAGES);
+ imagePath =
+ target.getParent().getImagePath(abiType);
userdataSrc = new File(imagePath, USERDATA_IMG);
}
if (userdataSrc.exists() == false) {
- log.error(null, "Unable to find a '%1$s' file to copy into the AVD folder.",
- USERDATA_IMG);
+ log.error(null,
+ "Unable to find a '%1$s' file of '%2$s' to copy into the AVD folder.",
+ USERDATA_IMG, imagePath);
needCleanup = true;
return null;
}
@@ -576,30 +531,48 @@ public final class AvdManager {
copyImageFile(userdataSrc, userdataDest);
+ if (userdataDest.exists() == false) {
+ log.error(null, "Unable to create '%1$s' file in the AVD folder.",
+ userdataDest);
+ needCleanup = true;
+ return null;
+ }
+
// Config file.
HashMap<String, String> values = new HashMap<String, String>();
- if (setImagePathProperties(target, values, log) == false) {
- needCleanup = true;
- return null;
+ if (setImagePathProperties(target, abiType, values, log) == false) {
+ log.error(null, "Failed to set image path properties in the AVD folder.");
+ needCleanup = true;
+ return null;
}
// Create the snapshot file
if (createSnapshot) {
- String toolsLib = mSdkManager.getLocation() + File.separator
- + SdkConstants.OS_SDK_TOOLS_LIB_EMULATOR_FOLDER;
- File snapshotBlank = new File(toolsLib, SNAPSHOTS_IMG);
- if (snapshotBlank.exists() == false) {
- log.error(null, "Unable to find a '%2$s%1$s' file to copy into the AVD folder.",
- SNAPSHOTS_IMG, toolsLib);
- needCleanup = true;
- return null;
- }
File snapshotDest = new File(avdFolder, SNAPSHOTS_IMG);
- copyImageFile(snapshotBlank, snapshotDest);
+ if (snapshotDest.isFile() && editExisting) {
+ log.printf("Snapshot image already present, was not changed.");
+
+ } else {
+ String toolsLib = mSdkManager.getLocation() + File.separator
+ + SdkConstants.OS_SDK_TOOLS_LIB_EMULATOR_FOLDER;
+ File snapshotBlank = new File(toolsLib, SNAPSHOTS_IMG);
+ if (snapshotBlank.exists() == false) {
+ log.error(null,
+ "Unable to find a '%2$s%1$s' file to copy into the AVD folder.",
+ SNAPSHOTS_IMG, toolsLib);
+ needCleanup = true;
+ return null;
+ }
+
+ copyImageFile(snapshotBlank, snapshotDest);
+ }
values.put(AVD_INI_SNAPSHOT_PRESENT, "true");
}
+ // Now the abi type
+ values.put(AVD_INI_ABI_TYPE, abiType);
+
// Now the skin.
if (skinName == null || skinName.length() == 0) {
skinName = target.getDefaultSkin();
@@ -616,6 +589,7 @@ public final class AvdManager {
// assume skin name is valid
String skinPath = getSkinRelativePath(skinName, target, log);
if (skinPath == null) {
+ log.error(null, "Missing skinpath in the AVD folder.");
needCleanup = true;
return null;
}
@@ -625,54 +599,48 @@ public final class AvdManager {
}
if (sdcard != null && sdcard.length() > 0) {
- 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);
+ // 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.
+
+ long sdcardSize = parseSdcardSize(sdcard, null/*parsedStrings*/);
+
+ if (sdcardSize == SDCARD_SIZE_NOT_IN_RANGE) {
+ log.error(null, "SD Card size must be in the range 9 MiB..1023 GiB.");
+ needCleanup = true;
+ return null;
+
+ } else if (sdcardSize == SDCARD_SIZE_INVALID) {
+ log.error(null, "Unable to parse SD Card size");
+ needCleanup = true;
+ return null;
+
+ } else if (sdcardSize == SDCARD_NOT_SIZE_PATTERN) {
+ 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 {
+ log.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;
+ }
} 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()) {
- // get the sdcard values for checks
- try {
- long sdcardSize = Long.parseLong(m.group(1));
-
- // prevent overflow: no more than 999GB
- // 10 digit for MiB, 13 for KiB
- int digitCount = m.group(1).length();
-
- String sdcardSizeModifier = m.group(2);
- if ("K".equals(sdcardSizeModifier)) {
- sdcardSize *= 1024L;
- } else { // must be "M" per the pattern
- sdcardSize *= 1024L * 1024L;
- digitCount += 3; // convert the number of digit into "KiB"
- }
-
- if (digitCount >= 13) {
- log.error(null, "SD Card size is too big!");
- needCleanup = true;
- return null;
- }
-
- if (sdcardSize < 9 * 1024 * 1024) {
- log.error(null, "SD Card size must be at least 9MB");
- needCleanup = true;
- return null;
- }
- } catch (NumberFormatException e) {
- // this should never happen since the string is validated
- // by the regexp
- log.error(null, "Unable to parse SD Card size");
- needCleanup = true;
- return null;
+ // create the sdcard.
+ File sdcardFile = new File(avdFolder, SDCARD_IMG);
+
+ boolean runMkSdcard = true;
+ if (sdcardFile.exists()) {
+ if (sdcardFile.length() == sdcardSize && editExisting) {
+ // There's already an sdcard file with the right size and we're
+ // not overriding it... so don't remove it.
+ runMkSdcard = false;
+ log.printf("SD Card already present with same size, was not changed.");
}
+ }
- // create the sdcard.
- sdcardFile = new File(avdFolder, SDCARD_IMG);
+ if (runMkSdcard) {
String path = sdcardFile.getAbsolutePath();
// execute mksdcard with the proper parameters.
@@ -688,21 +656,16 @@ public final class AvdManager {
}
if (createSdCard(mkSdCard.getAbsolutePath(), sdcard, path, log) == false) {
+ log.error(null, "Failed to create sdcard in the AVD folder.");
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 {
- log.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;
}
+
+ // 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);
}
}
@@ -757,12 +720,23 @@ public final class AvdManager {
StringBuilder report = new StringBuilder();
if (target.isPlatform()) {
- report.append(String.format("Created AVD '%1$s' based on %2$s",
- name, target.getName()));
+ if (editExisting) {
+ report.append(String.format("Updated AVD '%1$s' based on %2$s",
+ avdName, target.getName()));
+ } else {
+ report.append(String.format("Created AVD '%1$s' based on %2$s",
+ avdName, target.getName()));
+ }
} else {
- report.append(String.format("Created AVD '%1$s' based on %2$s (%3$s)", name,
- target.getName(), target.getVendor()));
+ if (editExisting) {
+ report.append(String.format("Updated AVD '%1$s' based on %2$s (%3$s)", avdName,
+ target.getName(), target.getVendor()));
+ } else {
+ report.append(String.format("Created AVD '%1$s' based on %2$s (%3$s)", avdName,
+ target.getName(), target.getVendor()));
+ }
}
+ report.append(String.format(", %s processor", AvdInfo.getPrettyAbiType(abiType)));
// display the chosen hardware config
if (finalHardwareValues.size() > 0) {
@@ -777,28 +751,31 @@ public final class AvdManager {
log.printf(report.toString());
// create the AvdInfo object, and add it to the list
- AvdInfo newAvdInfo = new AvdInfo(name,
+ AvdInfo newAvdInfo = new AvdInfo(
+ avdName,
+ iniFile,
avdFolder.getAbsolutePath(),
target.hashString(),
- target, values);
+ target, abiType, values);
- AvdInfo oldAvdInfo = getAvd(name, false /*validAvdOnly*/);
+ AvdInfo oldAvdInfo = getAvd(avdName, false /*validAvdOnly*/);
synchronized (mAllAvdList) {
- if (oldAvdInfo != null && removePrevious) {
+ if (oldAvdInfo != null && (removePrevious || editExisting)) {
mAllAvdList.remove(oldAvdInfo);
}
mAllAvdList.add(newAvdInfo);
mValidAvdList = mBrokenAvdList = null;
}
- if (removePrevious &&
+ if ((removePrevious || editExisting) &&
newAvdInfo != null &&
oldAvdInfo != null &&
- !oldAvdInfo.getPath().equals(newAvdInfo.getPath())) {
- log.warning("Removing previous AVD directory at %s", oldAvdInfo.getPath());
+ !oldAvdInfo.getDataFolderPath().equals(newAvdInfo.getDataFolderPath())) {
+ log.warning("Removing previous AVD directory at %s",
+ oldAvdInfo.getDataFolderPath());
// Remove the old data directory
- File dir = new File(oldAvdInfo.getPath());
+ File dir = new File(oldAvdInfo.getDataFolderPath());
try {
deleteContentOf(dir);
dir.delete();
@@ -859,9 +836,9 @@ public final class AvdManager {
* is not empty. If the image folder is empty or does not exist, <code>null</code> is returned.
* @throws InvalidTargetPathException if the target image folder is not in the current SDK.
*/
- private String getImageRelativePath(IAndroidTarget target)
+ private String getImageRelativePath(IAndroidTarget target, String abiType)
throws InvalidTargetPathException {
- String imageFullPath = target.getPath(IAndroidTarget.IMAGES);
+ String imageFullPath = target.getImagePath(abiType);
// make this path relative to the SDK location
String sdkLocation = mSdkManager.getLocation();
@@ -957,13 +934,27 @@ public final class AvdManager {
* @param name of the AVD.
* @param avdFolder path for the data folder of the AVD.
* @param target of the AVD.
+ * @param removePrevious True if an existing ini file should be removed.
* @throws AndroidLocationException if there's a problem getting android root directory.
* @throws IOException if {@link File#getAbsolutePath()} fails.
*/
- private File createAvdIniFile(String name, File avdFolder, IAndroidTarget target)
+ private File createAvdIniFile(String name,
+ File avdFolder,
+ IAndroidTarget target,
+ boolean removePrevious)
throws AndroidLocationException, IOException {
+ File iniFile = AvdInfo.getDefaultIniFile(this, name);
+
+ if (removePrevious) {
+ if (iniFile.isFile()) {
+ iniFile.delete();
+ } else if (iniFile.isDirectory()) {
+ deleteContentOf(iniFile);
+ iniFile.delete();
+ }
+ }
+
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);
@@ -979,7 +970,10 @@ public final class AvdManager {
* @throws IOException if {@link File#getAbsolutePath()} fails.
*/
private File createAvdIniFile(AvdInfo info) throws AndroidLocationException, IOException {
- return createAvdIniFile(info.getName(), new File(info.getPath()), info.getTarget());
+ return createAvdIniFile(info.getName(),
+ new File(info.getDataFolderPath()),
+ info.getTarget(),
+ false /*removePrevious*/);
}
/**
@@ -1010,7 +1004,7 @@ public final class AvdManager {
}
}
- String path = avdInfo.getPath();
+ String path = avdInfo.getDataFolderPath();
if (path != null) {
f = new File(path);
if (f.exists()) {
@@ -1032,8 +1026,6 @@ public final class AvdManager {
return true;
}
- } catch (AndroidLocationException e) {
- log.error(e, null);
} catch (IOException e) {
log.error(e, null);
} catch (SecurityException e) {
@@ -1060,17 +1052,25 @@ public final class AvdManager {
try {
if (paramFolderPath != null) {
- File f = new File(avdInfo.getPath());
- log.warning("Moving '%1$s' to '%2$s'.", avdInfo.getPath(), paramFolderPath);
+ File f = new File(avdInfo.getDataFolderPath());
+ log.warning("Moving '%1$s' to '%2$s'.",
+ avdInfo.getDataFolderPath(),
+ paramFolderPath);
if (!f.renameTo(new File(paramFolderPath))) {
log.error(null, "Failed to move '%1$s' to '%2$s'.",
- avdInfo.getPath(), paramFolderPath);
+ avdInfo.getDataFolderPath(), paramFolderPath);
return false;
}
// update AVD info
- AvdInfo info = new AvdInfo(avdInfo.getName(), paramFolderPath,
- avdInfo.getTargetHash(), avdInfo.getTarget(), avdInfo.getProperties());
+ AvdInfo info = new AvdInfo(
+ avdInfo.getName(),
+ avdInfo.getIniFile(),
+ paramFolderPath,
+ avdInfo.getTargetHash(),
+ avdInfo.getTarget(),
+ avdInfo.getAbiType(),
+ avdInfo.getProperties());
replaceAvd(avdInfo, info);
// update the ini file
@@ -1079,7 +1079,7 @@ public final class AvdManager {
if (newName != null) {
File oldIniFile = avdInfo.getIniFile();
- File newIniFile = AvdInfo.getIniFile(newName);
+ File newIniFile = AvdInfo.getDefaultIniFile(this, newName);
log.warning("Moving '%1$s' to '%2$s'.", oldIniFile.getPath(), newIniFile.getPath());
if (!oldIniFile.renameTo(newIniFile)) {
@@ -1089,8 +1089,14 @@ public final class AvdManager {
}
// update AVD info
- AvdInfo info = new AvdInfo(newName, avdInfo.getPath(),
- avdInfo.getTargetHash(), avdInfo.getTarget(), avdInfo.getProperties());
+ AvdInfo info = new AvdInfo(
+ newName,
+ avdInfo.getIniFile(),
+ avdInfo.getDataFolderPath(),
+ avdInfo.getTargetHash(),
+ avdInfo.getTarget(),
+ avdInfo.getAbiType(),
+ avdInfo.getProperties());
replaceAvd(avdInfo, info);
}
@@ -1135,19 +1141,20 @@ public final class AvdManager {
* <p/>
* This lists the $HOME/.android/avd/<name>.ini files.
* Such files are properties file than then indicate where the AVD folder is located.
+ * <p/>
+ * Note: the method is to be considered private. It is made protected so that
+ * unit tests can easily override the AVD root.
*
* @return A new {@link File} array or null. The array might be empty.
* @throws AndroidLocationException if there's a problem getting android root directory.
*/
private File[] buildAvdFilesList() throws AndroidLocationException {
- // get the Android prefs location.
- String avdRoot = AvdManager.getBaseAvdFolder();
+ File folder = new File(getBaseAvdFolder());
// ensure folder validity.
- File folder = new File(avdRoot);
if (folder.isFile()) {
throw new AndroidLocationException(
- String.format("%1$s is not a valid folder.", avdRoot));
+ String.format("%1$s is not a valid folder.", folder.getAbsolutePath()));
} else if (folder.exists() == false) {
// folder is not there, we create it and return
folder.mkdirs();
@@ -1192,14 +1199,14 @@ public final class AvdManager {
/**
* Parses an AVD .ini file to create an {@link AvdInfo}.
*
- * @param path The path to the AVD .ini file
+ * @param iniPath The path to the AVD .ini file
* @param log the log object to receive action logs. Cannot be null.
* @return A new {@link AvdInfo} with an {@link AvdStatus} indicating whether this AVD is
* valid or not.
*/
- private AvdInfo parseAvdInfo(File path, ISdkLog log) {
+ private AvdInfo parseAvdInfo(File iniPath, ISdkLog log) {
Map<String, String> map = ProjectProperties.parsePropertyFile(
- new FileWrapper(path),
+ new FileWrapper(iniPath),
log);
String avdPath = map.get(AVD_INFO_PATH);
@@ -1227,12 +1234,20 @@ public final class AvdManager {
}
// get name
- String name = path.getName();
- Matcher matcher = INI_NAME_PATTERN.matcher(path.getName());
+ String name = iniPath.getName();
+ Matcher matcher = INI_NAME_PATTERN.matcher(iniPath.getName());
if (matcher.matches()) {
name = matcher.group(1);
}
+ // get abi type
+ String abiType = properties == null ? null : properties.get(AVD_INI_ABI_TYPE);
+ // for the avds created previously without enhancement, i.e. They are created based
+ // on previous API Levels. They are supposed to have ARM processor type
+ if (abiType == null) {
+ abiType = SdkConstants.ABI_ARMEABI;
+ }
+
// check the image.sysdir are valid
boolean validImageSysdir = true;
if (properties != null) {
@@ -1275,9 +1290,11 @@ public final class AvdManager {
AvdInfo info = new AvdInfo(
name,
+ iniPath,
avdPath,
targetHash,
target,
+ abiType,
properties,
status);
@@ -1489,7 +1506,7 @@ public final class AvdManager {
AvdStatus status;
// create the path to the new system images.
- if (setImagePathProperties(avd.getTarget(), properties, log)) {
+ if (setImagePathProperties(avd.getTarget(), avd.getAbiType(), properties, log)) {
if (properties.containsKey(AVD_INI_IMAGES_1)) {
log.printf("Updated '%1$s' with value '%2$s'\n", AVD_INI_IMAGES_1,
properties.get(AVD_INI_IMAGES_1));
@@ -1509,7 +1526,7 @@ public final class AvdManager {
}
// now write the config file
- File configIniFile = new File(avd.getPath(), CONFIG_INI);
+ File configIniFile = new File(avd.getDataFolderPath(), CONFIG_INI);
writeIniFile(configIniFile, properties);
// finally create a new AvdInfo for this unbroken avd and add it to the list.
@@ -1518,9 +1535,11 @@ public final class AvdManager {
// FIXME: We may want to create this AvdInfo by reparsing the AVD instead. This could detect other errors.
AvdInfo newAvd = new AvdInfo(
avd.getName(),
- avd.getPath(),
+ avd.getIniFile(),
+ avd.getDataFolderPath(),
avd.getTargetHash(),
avd.getTarget(),
+ avd.getAbiType(),
properties,
status);
@@ -1530,13 +1549,14 @@ public final class AvdManager {
/**
* Sets the paths to the system images in a properties map.
* @param target the target in which to find the system images.
+ * @param abiType the abi type of the avd to find
+ * the architecture-dependent system images.
* @param properties the properties in which to set the paths.
* @param log the log object to receive action logs. Cannot be null.
* @return true if success, false if some path are missing.
*/
private boolean setImagePathProperties(IAndroidTarget target,
- Map<String, String> properties,
- ISdkLog log) {
+ String abiType, Map<String, String> properties, ISdkLog log) {
properties.remove(AVD_INI_IMAGES_1);
properties.remove(AVD_INI_IMAGES_2);
@@ -1544,7 +1564,7 @@ public final class AvdManager {
String property = AVD_INI_IMAGES_1;
// First the image folders of the target itself
- String imagePath = getImageRelativePath(target);
+ String imagePath = getImageRelativePath(target, abiType);
if (imagePath != null) {
properties.put(property, imagePath);
property = AVD_INI_IMAGES_2;
@@ -1554,7 +1574,7 @@ public final class AvdManager {
// 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);
+ imagePath = getImageRelativePath(parent, abiType);
if (imagePath != null) {
properties.put(property, imagePath);
}
diff --git a/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/build/DebugKeyProvider.java b/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/build/DebugKeyProvider.java
index bef7ccf..d31414c 100644
--- a/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/build/DebugKeyProvider.java
+++ b/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/build/DebugKeyProvider.java
@@ -36,49 +36,49 @@ import java.security.cert.CertificateException;
* <p/>This provider uses a custom keystore to create and store a key with a known password.
*/
public class DebugKeyProvider {
-
+
public interface IKeyGenOutput {
public void out(String message);
public void err(String message);
}
-
+
private static final String PASSWORD_STRING = "android";
private static final char[] PASSWORD_CHAR = PASSWORD_STRING.toCharArray();
private static final String DEBUG_ALIAS = "AndroidDebugKey";
-
+
// Certificate CN value. This is a hard-coded value for the debug key.
// Android Market checks against this value in order to refuse applications signed with
// debug keys.
private static final String CERTIFICATE_DESC = "CN=Android Debug,O=Android,C=US";
-
+
private KeyStore.PrivateKeyEntry mEntry;
-
+
public static class KeytoolException extends Exception {
/** default serial uid */
private static final long serialVersionUID = 1L;
private String mJavaHome = null;
private String mCommandLine = null;
-
+
KeytoolException(String message) {
super(message);
}
KeytoolException(String message, String javaHome, String commandLine) {
super(message);
-
+
mJavaHome = javaHome;
mCommandLine = commandLine;
}
-
+
public String getJavaHome() {
return mJavaHome;
}
-
+
public String getCommandLine() {
return mCommandLine;
}
}
-
+
/**
* Creates a provider using a keystore at the given location.
* <p/>The keystore, and a new random android debug key are created if they do not yet exist.
@@ -91,16 +91,16 @@ public class DebugKeyProvider {
* @param output an optional {@link IKeyGenOutput} object to get the stdout and stderr
* of the keytool process call.
* @throws KeytoolException If the creation of the debug key failed.
- * @throws AndroidLocationException
+ * @throws AndroidLocationException
*/
public DebugKeyProvider(String osKeyStorePath, String storeType, IKeyGenOutput output)
throws KeyStoreException, NoSuchAlgorithmException, CertificateException,
UnrecoverableEntryException, IOException, KeytoolException, AndroidLocationException {
-
+
if (osKeyStorePath == null) {
osKeyStorePath = getDefaultKeyStoreOsPath();
}
-
+
if (loadKeyEntry(osKeyStorePath, storeType) == false) {
// create the store with the key
createNewStore(osKeyStorePath, storeType, output);
@@ -109,7 +109,7 @@ public class DebugKeyProvider {
/**
* Returns the OS path to the default debug keystore.
- *
+ *
* @return The OS path to the default debug keystore.
* @throws KeytoolException
* @throws AndroidLocationException
@@ -134,7 +134,7 @@ public class DebugKeyProvider {
if (mEntry != null) {
return mEntry.getPrivateKey();
}
-
+
return null;
}
@@ -150,7 +150,7 @@ public class DebugKeyProvider {
return null;
}
-
+
/**
* Loads the debug key from the keystore.
* @param osKeyStorePath the OS path to the keystore.
@@ -172,7 +172,7 @@ public class DebugKeyProvider {
} catch (FileNotFoundException e) {
return false;
}
-
+
return true;
}
@@ -193,9 +193,9 @@ public class DebugKeyProvider {
private void createNewStore(String osKeyStorePath, String storeType, IKeyGenOutput output)
throws KeyStoreException, NoSuchAlgorithmException, CertificateException,
UnrecoverableEntryException, IOException, KeytoolException {
-
+
if (KeystoreHelper.createNewStore(osKeyStorePath, storeType, PASSWORD_STRING, DEBUG_ALIAS,
- PASSWORD_STRING, CERTIFICATE_DESC, 1 /* validity*/, output)) {
+ PASSWORD_STRING, CERTIFICATE_DESC, 30 /* validity*/, output)) {
loadKeyEntry(osKeyStorePath, storeType);
}
}
diff --git a/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/export/MultiApkExportHelper.java b/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/export/MultiApkExportHelper.java
index ee2a5a6..f05e9a6 100644
--- a/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/export/MultiApkExportHelper.java
+++ b/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/export/MultiApkExportHelper.java
@@ -16,10 +16,10 @@
package com.android.sdklib.internal.export;
+import com.android.io.FileWrapper;
+import com.android.io.IAbstractFile;
+import com.android.io.StreamException;
import com.android.sdklib.SdkConstants;
-import com.android.sdklib.io.FileWrapper;
-import com.android.sdklib.io.IAbstractFile;
-import com.android.sdklib.io.StreamException;
import com.android.sdklib.xml.AndroidManifestParser;
import com.android.sdklib.xml.ManifestData;
import com.android.sdklib.xml.ManifestData.SupportsScreens;
diff --git a/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/project/ProjectCreator.java b/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/project/ProjectCreator.java
index 16dd8eb..7840b91 100644
--- a/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/project/ProjectCreator.java
+++ b/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/project/ProjectCreator.java
@@ -16,6 +16,7 @@
package com.android.sdklib.internal.project;
+import com.android.AndroidConstants;
import com.android.sdklib.IAndroidTarget;
import com.android.sdklib.ISdkLog;
import com.android.sdklib.SdkConstants;
@@ -325,11 +326,11 @@ public class ProjectCreator {
if (isTestProject == false) {
/* Make res files only for non test projects */
- File valueFolder = createDirs(resourceFolder, SdkConstants.FD_VALUES);
+ File valueFolder = createDirs(resourceFolder, AndroidConstants.FD_RES_VALUES);
installTargetTemplate("strings.template", new File(valueFolder, "strings.xml"),
keywords, target);
- File layoutFolder = createDirs(resourceFolder, SdkConstants.FD_LAYOUT);
+ File layoutFolder = createDirs(resourceFolder, AndroidConstants.FD_RES_LAYOUT);
installTargetTemplate("layout.template", new File(layoutFolder, "main.xml"),
keywords, target);
diff --git a/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/project/ProjectProperties.java b/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/project/ProjectProperties.java
index 19cad00..11cd277 100644
--- a/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/project/ProjectProperties.java
+++ b/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/project/ProjectProperties.java
@@ -16,12 +16,12 @@
package com.android.sdklib.internal.project;
+import com.android.io.FolderWrapper;
+import com.android.io.IAbstractFile;
+import com.android.io.IAbstractFolder;
+import com.android.io.StreamException;
import com.android.sdklib.ISdkLog;
import com.android.sdklib.SdkConstants;
-import com.android.sdklib.io.FolderWrapper;
-import com.android.sdklib.io.IAbstractFile;
-import com.android.sdklib.io.IAbstractFolder;
-import com.android.sdklib.io.StreamException;
import java.io.BufferedReader;
import java.io.FileNotFoundException;
diff --git a/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/project/ProjectPropertiesWorkingCopy.java b/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/project/ProjectPropertiesWorkingCopy.java
index 23cdd09..14cac2a 100644
--- a/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/project/ProjectPropertiesWorkingCopy.java
+++ b/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/project/ProjectPropertiesWorkingCopy.java
@@ -16,11 +16,11 @@
package com.android.sdklib.internal.project;
+import com.android.io.IAbstractFile;
+import com.android.io.IAbstractFolder;
+import com.android.io.StreamException;
import com.android.sdklib.SdkConstants;
import com.android.sdklib.internal.project.ProjectProperties.PropertyType;
-import com.android.sdklib.io.IAbstractFile;
-import com.android.sdklib.io.IAbstractFolder;
-import com.android.sdklib.io.StreamException;
import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
diff --git a/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/AdbWrapper.java b/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/AdbWrapper.java
index 3fab9ce..ba2d501 100755
--- a/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/AdbWrapper.java
+++ b/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/AdbWrapper.java
@@ -54,7 +54,11 @@ public class AdbWrapper {
}
private void display(String format, Object...args) {
- mMonitor.setResult(format, args);
+ mMonitor.log(format, args);
+ }
+
+ private void displayError(String format, Object...args) {
+ mMonitor.logError(format, args);
}
/**
@@ -63,7 +67,7 @@ public class AdbWrapper {
*/
public synchronized boolean startAdb() {
if (mAdbOsLocation == null) {
- display("Error: missing path to ADB."); //$NON-NLS-1$
+ displayError("Error: missing path to ADB."); //$NON-NLS-1$
return false;
}
@@ -82,15 +86,15 @@ public class AdbWrapper {
false /* waitForReaders */);
} catch (IOException ioe) {
- display("Unable to run 'adb': %1$s.", ioe.getMessage()); //$NON-NLS-1$
+ displayError("Unable to run 'adb': %1$s.", ioe.getMessage()); //$NON-NLS-1$
// we'll return false;
} catch (InterruptedException ie) {
- display("Unable to run 'adb': %1$s.", ie.getMessage()); //$NON-NLS-1$
+ displayError("Unable to run 'adb': %1$s.", ie.getMessage()); //$NON-NLS-1$
// we'll return false;
}
if (status != 0) {
- display("'adb start-server' failed."); //$NON-NLS-1$
+ displayError("'adb start-server' failed."); //$NON-NLS-1$
return false;
}
@@ -105,7 +109,7 @@ public class AdbWrapper {
*/
public synchronized boolean stopAdb() {
if (mAdbOsLocation == null) {
- display("Error: missing path to ADB."); //$NON-NLS-1$
+ displayError("Error: missing path to ADB."); //$NON-NLS-1$
return false;
}
@@ -127,7 +131,7 @@ public class AdbWrapper {
}
if (status != 0) {
- display("'adb kill-server' failed -- run manually if necessary."); //$NON-NLS-1$
+ displayError("'adb kill-server' failed -- run manually if necessary."); //$NON-NLS-1$
return false;
}
@@ -163,7 +167,7 @@ public class AdbWrapper {
while (true) {
String line = errReader.readLine();
if (line != null) {
- display("ADB Error: %1$s", line);
+ displayError("ADB Error: %1$s", line);
errorOutput.add(line);
} else {
break;
@@ -185,7 +189,7 @@ public class AdbWrapper {
while (true) {
String line = outReader.readLine();
if (line != null) {
- display("ADB: %1$s", line);
+ displayError("ADB: %1$s", line);
stdOutput.add(line);
} else {
break;
diff --git a/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/AddonPackage.java b/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/AddonPackage.java
index bed9174..526bfcb 100755
--- a/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/AddonPackage.java
+++ b/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/AddonPackage.java
@@ -247,7 +247,22 @@ public class AddonPackage extends Package
return mLibs;
}
- /** Returns a short description for an {@link IDescription}. */
+ /**
+ * Returns a description of this package that is suitable for a list display.
+ * <p/>
+ * {@inheritDoc}
+ */
+ @Override
+ public String getListDescription() {
+ return String.format("%1$s by %2$s%3$s",
+ getName(),
+ getVendor(),
+ isObsolete() ? " (Obsolete)" : "");
+ }
+
+ /**
+ * Returns a short description for an {@link IDescription}.
+ */
@Override
public String getShortDescription() {
return String.format("%1$s by %2$s, Android API %3$s, revision %4$s%5$s",
diff --git a/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/AddonsListFetcher.java b/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/AddonsListFetcher.java
index 9b8d808..c0b7041 100755
--- a/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/AddonsListFetcher.java
+++ b/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/AddonsListFetcher.java
@@ -142,11 +142,11 @@ public class AddonsListFetcher {
reason = String.format("Unknown (%1$s)", exception[0].getClass().getName());
}
- monitor.setResult("Failed to fetch URL %1$s, reason: %2$s", url, reason);
+ monitor.logError("Failed to fetch URL %1$s, reason: %2$s", url, reason);
}
if (validationError[0] != null) {
- monitor.setResult("%s", validationError[0]); //$NON-NLS-1$
+ monitor.logError("%s", validationError[0]); //$NON-NLS-1$
}
// Stop here if we failed to validate the XML. We don't want to load it.
@@ -409,13 +409,13 @@ public class AddonsListFetcher {
return doc;
} catch (ParserConfigurationException e) {
- monitor.setResult("Failed to create XML document builder");
+ monitor.logError("Failed to create XML document builder");
} catch (SAXException e) {
- monitor.setResult("Failed to parse XML document");
+ monitor.logError("Failed to parse XML document");
} catch (IOException e) {
- monitor.setResult("Failed to read XML document");
+ monitor.logError("Failed to read XML document");
}
return null;
diff --git a/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/ArchiveInstaller.java b/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/ArchiveInstaller.java
index f3fd347..5807ca3 100755
--- a/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/ArchiveInstaller.java
+++ b/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/ArchiveInstaller.java
@@ -63,7 +63,7 @@ public class ArchiveInstaller {
String name = pkg.getShortDescription();
if (pkg instanceof ExtraPackage && !((ExtraPackage) pkg).isPathValid()) {
- monitor.setResult("Skipping %1$s: %2$s is not a valid install path.",
+ monitor.log("Skipping %1$s: %2$s is not a valid install path.",
name,
((ExtraPackage) pkg).getPath());
return false;
@@ -71,14 +71,14 @@ public class ArchiveInstaller {
if (archive.isLocal()) {
// This should never happen.
- monitor.setResult("Skipping already installed archive: %1$s for %2$s",
+ monitor.log("Skipping already installed archive: %1$s for %2$s",
name,
archive.getOsDescription());
return false;
}
if (!archive.isCompatible()) {
- monitor.setResult("Skipping incompatible archive: %1$s for %2$s",
+ monitor.log("Skipping incompatible archive: %1$s for %2$s",
name,
archive.getOsDescription());
return false;
@@ -88,7 +88,7 @@ public class ArchiveInstaller {
if (archiveFile != null) {
// Unarchive calls the pre/postInstallHook methods.
if (unarchive(archive, osSdkRoot, archiveFile, sdkManager, monitor)) {
- monitor.setResult("Installed %1$s", name);
+ monitor.log("Installed %1$s", name);
// Delete the temp archive if it exists, only on success
OsHelper.deleteFileOrFolder(archiveFile);
return true;
@@ -110,7 +110,7 @@ public class ArchiveInstaller {
String name = archive.getParentPackage().getShortDescription();
String desc = String.format("Downloading %1$s", name);
monitor.setDescription(desc);
- monitor.setResult(desc);
+ monitor.log(desc);
String link = archive.getUrl();
if (!link.startsWith("http://") //$NON-NLS-1$
@@ -120,7 +120,7 @@ public class ArchiveInstaller {
Package pkg = archive.getParentPackage();
SdkSource src = pkg.getParentSource();
if (src == null) {
- monitor.setResult("Internal error: no source for archive %1$s", name);
+ monitor.logError("Internal error: no source for archive %1$s", name);
return null;
}
@@ -152,7 +152,7 @@ public class ArchiveInstaller {
OsHelper.deleteFileOrFolder(tmpFolder);
}
if (!tmpFolder.mkdirs()) {
- monitor.setResult("Failed to create directory %1$s", tmpFolder.getPath());
+ monitor.logError("Failed to create directory %1$s", tmpFolder.getPath());
return null;
}
}
@@ -161,7 +161,7 @@ public class ArchiveInstaller {
// if the file exists, check its checksum & size. Use it if complete
if (tmpFile.exists()) {
if (tmpFile.length() == archive.getSize()) {
- String chksum = "";
+ String chksum = ""; //$NON-NLS-1$
try {
chksum = fileChecksum(archive.getChecksumType().getMessageDigest(),
tmpFile,
@@ -214,10 +214,10 @@ public class ArchiveInstaller {
} catch (FileNotFoundException e) {
// The FNF message is just the URL. Make it a bit more useful.
- monitor.setResult("File not found: %1$s", e.getMessage());
+ monitor.logError("File not found: %1$s", e.getMessage());
} catch (Exception e) {
- monitor.setResult(e.getMessage());
+ monitor.logError(e.getMessage());
} finally {
if (is != null) {
@@ -327,14 +327,15 @@ public class ArchiveInstaller {
}
if (monitor.isCancelRequested()) {
- monitor.setResult("Download aborted by user at %1$d bytes.", total);
+ monitor.log("Download aborted by user at %1$d bytes.", total);
return false;
}
}
if (total != size) {
- monitor.setResult("Download finished with wrong size. Expected %1$d bytes, got %2$d bytes.",
+ monitor.logError(
+ "Download finished with wrong size. Expected %1$d bytes, got %2$d bytes.",
size, total);
return false;
}
@@ -343,7 +344,7 @@ public class ArchiveInstaller {
String actual = getDigestChecksum(digester);
String expected = archive.getChecksum();
if (!actual.equalsIgnoreCase(expected)) {
- monitor.setResult("Download finished with wrong checksum. Expected %1$s, got %2$s.",
+ monitor.logError("Download finished with wrong checksum. Expected %1$s, got %2$s.",
expected, actual);
return false;
}
@@ -352,10 +353,10 @@ public class ArchiveInstaller {
} catch (FileNotFoundException e) {
// The FNF message is just the URL. Make it a bit more useful.
- monitor.setResult("File not found: %1$s", e.getMessage());
+ monitor.logError("File not found: %1$s", e.getMessage());
} catch (Exception e) {
- monitor.setResult(e.getMessage());
+ monitor.logError(e.getMessage());
} finally {
if (os != null) {
@@ -391,7 +392,7 @@ public class ArchiveInstaller {
String pkgName = pkg.getShortDescription();
String pkgDesc = String.format("Installing %1$s", pkgName);
monitor.setDescription(pkgDesc);
- monitor.setResult(pkgDesc);
+ monitor.log(pkgDesc);
// Ideally we want to always unzip in a temp folder which name depends on the package
// type (e.g. addon, tools, etc.) and then move the folder to the destination folder.
@@ -432,12 +433,12 @@ public class ArchiveInstaller {
if (destFolder == null) {
// this should not seriously happen.
- monitor.setResult("Failed to compute installation directory for %1$s.", pkgName);
+ monitor.log("Failed to compute installation directory for %1$s.", pkgName);
return false;
}
if (!pkg.preInstallHook(archive, monitor, osSdkRoot, destFolder)) {
- monitor.setResult("Skipping archive: %1$s", pkgName);
+ monitor.log("Skipping archive: %1$s", pkgName);
return false;
}
@@ -450,14 +451,14 @@ public class ArchiveInstaller {
}
if (oldDestFolder == null) {
// this should not seriously happen.
- monitor.setResult("Failed to find a temp directory in %1$s.", osSdkRoot);
+ monitor.logError("Failed to find a temp directory in %1$s.", osSdkRoot);
return false;
}
// Try to move the current dest dir to the temp/old one. Tell the user if it failed.
while(true) {
if (!moveFolder(destFolder, oldDestFolder)) {
- monitor.setResult("Failed to rename directory %1$s to %2$s.",
+ monitor.logError("Failed to rename directory %1$s to %2$s.",
destFolder.getPath(), oldDestFolder.getPath());
if (SdkConstants.CURRENT_PLATFORM == SdkConstants.PLATFORM_WINDOWS) {
@@ -489,7 +490,7 @@ public class ArchiveInstaller {
// -2- Unzip new content directly in place.
if (!destFolder.mkdirs()) {
- monitor.setResult("Failed to create directory %1$s", destFolder.getPath());
+ monitor.logError("Failed to create directory %1$s", destFolder.getPath());
return false;
}
@@ -498,7 +499,7 @@ public class ArchiveInstaller {
}
if (!generateSourceProperties(archive, destFolder)) {
- monitor.setResult("Failed to generate source.properties in directory %1$s",
+ monitor.logError("Failed to generate source.properties in directory %1$s",
destFolder.getPath());
return false;
}
@@ -627,7 +628,7 @@ public class ArchiveInstaller {
// Create directory if it doesn't exist yet. This allows us to create
// empty directories.
if (!destFile.isDirectory() && !destFile.mkdirs()) {
- monitor.setResult("Failed to create temp directory %1$s",
+ monitor.logError("Failed to create temp directory %1$s",
destFile.getPath());
return false;
}
@@ -638,7 +639,7 @@ public class ArchiveInstaller {
File parentDir = destFile.getParentFile();
if (!parentDir.isDirectory()) {
if (!parentDir.mkdirs()) {
- monitor.setResult("Failed to create temp directory %1$s",
+ monitor.logError("Failed to create temp directory %1$s",
parentDir.getPath());
return false;
}
@@ -689,7 +690,7 @@ public class ArchiveInstaller {
return true;
} catch (IOException e) {
- monitor.setResult("Unzip failed: %1$s", e.getMessage());
+ monitor.logError("Unzip failed: %1$s", e.getMessage());
} finally {
if (zipFile != null) {
diff --git a/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/BrokenPackage.java b/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/BrokenPackage.java
index 1629045..ca6f463 100755
--- a/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/BrokenPackage.java
+++ b/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/BrokenPackage.java
@@ -99,7 +99,19 @@ public class BrokenPackage extends Package
return mExactApiLevel;
}
- /** Returns a short description for an {@link IDescription}. */
+ /**
+ * Returns a description of this package that is suitable for a list display.
+ * <p/>
+ * {@inheritDoc}
+ */
+ @Override
+ public String getListDescription() {
+ return mShortDescription;
+ }
+
+ /**
+ * Returns a short description for an {@link IDescription}.
+ */
@Override
public String getShortDescription() {
return mShortDescription;
diff --git a/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/DocPackage.java b/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/DocPackage.java
index 8a4c19d..5171454 100755
--- a/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/DocPackage.java
+++ b/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/DocPackage.java
@@ -117,13 +117,35 @@ public class DocPackage extends Package implements IPackageVersion {
mVersion.saveProperties(props);
}
- /** Returns the version, for platform, add-on and doc packages.
- * Can be 0 if this is a local package of unknown api-level. */
+ /**
+ * Returns the version, for platform, add-on and doc packages.
+ * Can be 0 if this is a local package of unknown api-level.
+ */
public AndroidVersion getVersion() {
return mVersion;
}
- /** Returns a short description for an {@link IDescription}. */
+ /**
+ * Returns a description of this package that is suitable for a list display.
+ * <p/>
+ * {@inheritDoc}
+ */
+ @Override
+ public String getListDescription() {
+ if (mVersion.isPreview()) {
+ return String.format("Documentation for Android '%1$s' Preview SDK%2$s",
+ mVersion.getCodename(),
+ isObsolete() ? " (Obsolete)" : "");
+ } else {
+ return String.format("Documentation for Android SDK%2$s",
+ mVersion.getApiLevel(),
+ isObsolete() ? " (Obsolete)" : "");
+ }
+ }
+
+ /**
+ * Returns a short description for an {@link IDescription}.
+ */
@Override
public String getShortDescription() {
if (mVersion.isPreview()) {
diff --git a/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/ExtraPackage.java b/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/ExtraPackage.java
index 49236dc..bdf2805 100755
--- a/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/ExtraPackage.java
+++ b/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/ExtraPackage.java
@@ -253,9 +253,7 @@ public class ExtraPackage extends MinToolsPackage
return ""; //$NON-NLS-1$
}
- /** Returns a short description for an {@link IDescription}. */
- @Override
- public String getShortDescription() {
+ private String getPrettyName() {
String name = mPath;
// In the past, we used to save the extras in a folder vendor-path,
@@ -299,8 +297,31 @@ public class ExtraPackage extends MinToolsPackage
name = name.replaceAll(" Usb ", " USB "); //$NON-NLS-1$
name = name.replaceAll(" Api ", " API "); //$NON-NLS-1$
+ return name;
+ }
+
+ /**
+ * Returns a description of this package that is suitable for a list display.
+ * <p/>
+ * {@inheritDoc}
+ */
+ @Override
+ public String getListDescription() {
+ String s = String.format("%1$s package%2$s",
+ getPrettyName(),
+ isObsolete() ? " (Obsolete)" : ""); //$NON-NLS-2$
+
+ return s;
+ }
+
+ /**
+ * Returns a short description for an {@link IDescription}.
+ */
+ @Override
+ public String getShortDescription() {
+
String s = String.format("%1$s package, revision %2$d%3$s",
- name,
+ getPrettyName(),
getRevision(),
isObsolete() ? " (Obsolete)" : ""); //$NON-NLS-2$
@@ -394,19 +415,33 @@ public class ExtraPackage extends MinToolsPackage
ExtraPackage ep = (ExtraPackage) pkg;
// To be backward compatible, we need to support the old vendor-path form
- if (ep.mPath != null && (ep.mVendor == null || ep.mVendor.length() == 0) &&
- mPath != null && mVendor != null) {
- if (ep.mPath.equals(mVendor + "-" + mPath)) { //$NON-NLS-1$
+ // in either the current or the remote package.
+ //
+ // The vendor test below needs to account for an old installed package
+ // (e.g. with an install path of vendor-name) that has then beeen updated
+ // in-place and thus when reloaded contains the vendor name in both the
+ // path and the vendor attributes.
+ if (ep.mPath != null && mPath != null && mVendor != null) {
+ if (ep.mPath.equals(mVendor + "-" + mPath) && //$NON-NLS-1$
+ (ep.mVendor == null || ep.mVendor.length() == 0
+ || ep.mVendor.equals(mVendor))) {
+ return true;
+ }
+ }
+ if (mPath != null && ep.mPath != null && ep.mVendor != null) {
+ if (mPath.equals(ep.mVendor + "-" + ep.mPath) && //$NON-NLS-1$
+ (mVendor == null || mVendor.length() == 0 || mVendor.equals(ep.mVendor))) {
return true;
}
}
+
if (!mPath.equals(ep.mPath)) {
return false;
}
if ((mVendor == null && ep.mVendor == null) ||
- (mVendor != null && !mVendor.equals(ep.mVendor))) {
- return false;
+ (mVendor != null && mVendor.equals(ep.mVendor))) {
+ return true;
}
}
diff --git a/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/ITaskMonitor.java b/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/ITaskMonitor.java
index e08e27c..40f1ddb 100755
--- a/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/ITaskMonitor.java
+++ b/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/ITaskMonitor.java
@@ -27,6 +27,21 @@ package com.android.sdklib.internal.repository;
* If the task runs in a non-UI worker thread, the task factory implementation
* will take care of the update the UI in the correct thread. The task itself
* must not have to deal with it.
+ * <p/>
+ * A monitor typically has 3 levels of text displayed: <br/>
+ * - A <b>title</b> <em>may</em> be present on a task dialog, typically when a task
+ * dialog is created. This is not covered by this monitor interface. <br/>
+ * - A <b>description</b> displays prominent information on what the task
+ * is currently doing. This is expected to vary over time, typically changing
+ * with each sub-monitor, and typically only the last description is visible.
+ * For example an updater would typically have descriptions such as "downloading",
+ * "installing" and finally "done". This is set using {@link #setDescription}. <br/>
+ * - A <b>verbose</b> optional log that can provide more information than the summary
+ * description and is typically displayed in some kind of scrollable multi-line
+ * text field so that the user can keep track of what happened. 3 levels are
+ * provided: error, normal and verbose. An UI may hide the log till an error is
+ * logged and/or might hide the verbose text unless a flag is checked by the user.
+ * This is set using {@link #log}, {@link #logError} and {@link #logVerbose}.
*/
public interface ITaskMonitor {
@@ -34,13 +49,26 @@ public interface ITaskMonitor {
* Sets the description in the current task dialog.
* This method can be invoked from a non-UI thread.
*/
- public void setDescription(String descriptionFormat, Object...args);
+ public void setDescription(String format, Object...args);
+
+ /**
+ * Logs a "normal" information line.
+ * This method can be invoked from a non-UI thread.
+ */
+ public void log(String format, Object...args);
+
+ /**
+ * Logs an "error" information line.
+ * This method can be invoked from a non-UI thread.
+ */
+ public void logError(String format, Object...args);
/**
- * Sets the result text in the current task dialog.
+ * Logs a "verbose" information line, that is extra details which are typically
+ * not that useful for the end-user and might be hidden until explicitly shown.
* This method can be invoked from a non-UI thread.
*/
- public void setResult(String resultFormat, Object...args);
+ public void logVerbose(String format, Object...args);
/**
* Sets the max value of the progress bar.
diff --git a/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/LocalSdkParser.java b/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/LocalSdkParser.java
index eb00562..c4b92b5 100755
--- a/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/LocalSdkParser.java
+++ b/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/LocalSdkParser.java
@@ -303,8 +303,12 @@ public class LocalSdkParser {
names.add(file.getName());
}
}
+
+ final String emulatorBinName =
+ SdkConstants.FN_EMULATOR + SdkConstants.FN_EMULATOR_EXTENSION;
+
if (!names.contains(SdkConstants.androidCmdName()) ||
- !names.contains(SdkConstants.FN_EMULATOR)) {
+ !names.contains(emulatorBinName)) {
return null;
}
diff --git a/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/OsHelper.java b/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/OsHelper.java
index 02cebe1..c2338f3 100755
--- a/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/OsHelper.java
+++ b/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/OsHelper.java
@@ -22,6 +22,8 @@ import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
/**
@@ -30,6 +32,21 @@ import java.io.IOException;
abstract class OsHelper {
/**
+ * Reflection method for File.setExecutable(boolean, boolean). Only present in Java 6.
+ */
+ private static Method sFileSetExecutable = null;
+ /**
+ * Whether File.setExecutable was queried through reflection. This is to only
+ * attempt reflection once.
+ */
+ private static boolean sFileReflectionDone = false;
+ /**
+ * Parameters to call File.setExecutable through reflection.
+ */
+ private final static Object[] sFileSetExecutableParams = new Object[] {
+ Boolean.TRUE, Boolean.FALSE };
+
+ /**
* Helper to delete a file or a directory.
* For a directory, recursively deletes all of its content.
* Files that cannot be deleted right away are marked for deletion on exit.
@@ -76,18 +93,49 @@ abstract class OsHelper {
}
/**
- * Sets the executable Unix permission (0777) on a file or folder.
+ * Sets the executable Unix permission (+x) on a file or folder.
+ * <p/>
+ * This attempts to use {@link File#setExecutable(boolean, boolean)} through reflection if
+ * it's available.
+ * If this is not available, this invokes a chmod exec instead,
+ * so there is no guarantee of it being fast.
* <p/>
- * This invokes a chmod exec, so there is no guarantee of it being fast.
* Caller must make sure to not invoke this under Windows.
*
* @param file The file to set permissions on.
* @throws IOException If an I/O error occurs
*/
static void setExecutablePermission(File file) throws IOException {
+ if (sFileReflectionDone == false) {
+ try {
+ sFileSetExecutable = File.class.getMethod("setExecutable", //$NON-NLS-1$
+ boolean.class, boolean.class);
+
+ } catch (SecurityException e) {
+ // do nothing we'll use chdmod instead
+ } catch (NoSuchMethodException e) {
+ // do nothing we'll use chdmod instead
+ }
+
+ sFileReflectionDone = true;
+ }
+
+ if (sFileSetExecutable != null) {
+ try {
+ sFileSetExecutable.invoke(file, sFileSetExecutableParams);
+ return;
+ } catch (IllegalArgumentException e) {
+ // we'll run chmod below
+ } catch (IllegalAccessException e) {
+ // we'll run chmod below
+ } catch (InvocationTargetException e) {
+ // we'll run chmod below
+ }
+ }
+
Runtime.getRuntime().exec(new String[] {
- "chmod", "777", file.getAbsolutePath()
- });
+ "chmod", "+x", file.getAbsolutePath() //$NON-NLS-1$ //$NON-NLS-2$
+ });
}
/**
diff --git a/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/Package.java b/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/Package.java
index 58be3c9..c597ad8 100755
--- a/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/Package.java
+++ b/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/Package.java
@@ -372,6 +372,17 @@ public abstract class Package implements IDescription, Comparable<Package> {
}
/**
+ * Returns a description of this package that is suitable for a list display.
+ * Should not be empty. Must never be null.
+ * <p/>
+ * Note that this is the "base" name for the package
+ * with no specific revision nor API mentionned.
+ * In contrast, {@link #getShortDescription()} should be used if you want more details
+ * such as the package revision number or the API, if applicable.
+ */
+ public abstract String getListDescription();
+
+ /**
* Returns a short description for an {@link IDescription}.
* Can be empty but not null.
*/
diff --git a/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/PlatformPackage.java b/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/PlatformPackage.java
index c303e2f..622a922 100755
--- a/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/PlatformPackage.java
+++ b/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/PlatformPackage.java
@@ -121,7 +121,31 @@ public class PlatformPackage extends MinToolsPackage implements IPackageVersion
return mVersion;
}
- /** Returns a short description for an {@link IDescription}. */
+ /**
+ * Returns a description of this package that is suitable for a list display.
+ * <p/>
+ * {@inheritDoc}
+ */
+ @Override
+ public String getListDescription() {
+ String s;
+
+ if (mVersion.isPreview()) {
+ s = String.format("SDK Platform Android %1$s Preview%2$s",
+ getVersionName(),
+ isObsolete() ? " (Obsolete)" : ""); //$NON-NLS-2$
+ } else {
+ s = String.format("SDK Platform Android %1$s%2$s",
+ getVersionName(),
+ isObsolete() ? " (Obsolete)" : ""); //$NON-NLS-2$
+ }
+
+ return s;
+ }
+
+ /**
+ * Returns a short description for an {@link IDescription}.
+ */
@Override
public String getShortDescription() {
String s;
@@ -130,13 +154,13 @@ public class PlatformPackage extends MinToolsPackage implements IPackageVersion
s = String.format("SDK Platform Android %1$s Preview, revision %2$s%3$s",
getVersionName(),
getRevision(),
- isObsolete() ? " (Obsolete)" : "");
+ isObsolete() ? " (Obsolete)" : ""); //$NON-NLS-2$
} else {
s = String.format("SDK Platform Android %1$s, API %2$d, revision %3$s%4$s",
getVersionName(),
mVersion.getApiLevel(),
getRevision(),
- isObsolete() ? " (Obsolete)" : "");
+ isObsolete() ? " (Obsolete)" : ""); //$NON-NLS-2$
}
return s;
diff --git a/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/PlatformToolPackage.java b/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/PlatformToolPackage.java
index 860d703..9a2de62 100755
--- a/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/PlatformToolPackage.java
+++ b/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/PlatformToolPackage.java
@@ -143,7 +143,20 @@ public class PlatformToolPackage extends Package {
archiveOsPath);
}
- /** Returns a short description for an {@link IDescription}. */
+ /**
+ * Returns a description of this package that is suitable for a list display.
+ * <p/>
+ * {@inheritDoc}
+ */
+ @Override
+ public String getListDescription() {
+ return String.format("Android SDK Platform-tools%1$s",
+ isObsolete() ? " (Obsolete)" : "");
+ }
+
+ /**
+ * Returns a short description for an {@link IDescription}.
+ */
@Override
public String getShortDescription() {
return String.format("Android SDK Platform-tools, revision %1$d%2$s",
diff --git a/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/SamplePackage.java b/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/SamplePackage.java
index 035677b..b436b91 100755
--- a/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/SamplePackage.java
+++ b/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/SamplePackage.java
@@ -175,7 +175,23 @@ public class SamplePackage extends MinToolsPackage
return mVersion;
}
- /** Returns a short description for an {@link IDescription}. */
+ /**
+ * Returns a description of this package that is suitable for a list display.
+ * <p/>
+ * {@inheritDoc}
+ */
+ @Override
+ public String getListDescription() {
+ String s = String.format("Samples for SDK API %1$s%2$s%3$s",
+ mVersion.getApiString(),
+ mVersion.isPreview() ? " Preview" : "",
+ isObsolete() ? " (Obsolete)" : "");
+ return s;
+ }
+
+ /**
+ * Returns a short description for an {@link IDescription}.
+ */
@Override
public String getShortDescription() {
String s = String.format("Samples for SDK API %1$s%2$s, revision %3$d%4$s",
diff --git a/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/SdkSource.java b/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/SdkSource.java
index 58bf314..22b9c42 100755
--- a/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/SdkSource.java
+++ b/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/SdkSource.java
@@ -57,7 +57,7 @@ import javax.xml.validation.Validator;
* It may be a full repository or an add-on only repository.
* A repository describes one or {@link Package}s available for download.
*/
-public abstract class SdkSource implements IDescription {
+public abstract class SdkSource implements IDescription, Comparable<SdkSource> {
private String mUrl;
@@ -151,6 +151,14 @@ public abstract class SdkSource implements IDescription {
}
/**
+ * Implementation of the {@link Comparable} interface.
+ * Simply compares the URL using the string's default ordering.
+ */
+ public int compareTo(SdkSource rhs) {
+ return this.getUrl().compareTo(rhs.getUrl());
+ }
+
+ /**
* Returns the UI-visible name of the source. Can be null.
*/
public String getUiName() {
@@ -250,7 +258,7 @@ public abstract class SdkSource implements IDescription {
url = url.replaceAll("https://", "http://"); //$NON-NLS-1$ //$NON-NLS-2$
}
- monitor.setDescription("Fetching %1$s", url);
+ monitor.setDescription("Fetching URL: %1$s", url);
monitor.incProgress(1);
mFetchError = null;
@@ -276,7 +284,7 @@ public abstract class SdkSource implements IDescription {
}
if (xml != null) {
- monitor.setDescription("Validate XML");
+ monitor.setDescription(String.format("Validate XML: %1$s", url));
for (int tryOtherUrl = 0; tryOtherUrl < 2; tryOtherUrl++) {
// Explore the XML to find the potential XML schema version
@@ -295,7 +303,7 @@ public abstract class SdkSource implements IDescription {
if (usingAlternateUrl && validatedDoc != null) {
// If the second tentative succeeded, indicate it in the console
// with the URL that worked.
- monitor.setResult("Repository found at %1$s", url);
+ monitor.log("Repository found at %1$s", url);
// Keep the modified URL
mUrl = url;
@@ -380,11 +388,11 @@ public abstract class SdkSource implements IDescription {
reason = String.format("Unknown (%1$s)", exception[0].getClass().getName());
}
- monitor.setResult("Failed to fetch URL %1$s, reason: %2$s", url, reason);
+ monitor.logError("Failed to fetch URL %1$s, reason: %2$s", url, reason);
}
if (validationError[0] != null) {
- monitor.setResult("%s", validationError[0]); //$NON-NLS-1$
+ monitor.logError("%s", validationError[0]); //$NON-NLS-1$
}
// Stop here if we failed to validate the XML. We don't want to load it.
@@ -424,7 +432,7 @@ public abstract class SdkSource implements IDescription {
monitor.incProgress(1);
if (xml != null) {
- monitor.setDescription("Parse XML");
+ monitor.setDescription(String.format("Parse XML: %1$s", url));
monitor.incProgress(1);
parsePackages(validatedDoc, validatedUri, monitor);
if (mPackages == null || mPackages.length == 0) {
@@ -740,12 +748,11 @@ public abstract class SdkSource implements IDescription {
if (p != null) {
packages.add(p);
- monitor.setDescription("Found %1$s", p.getShortDescription());
+ monitor.logVerbose("Found %1$s", p.getShortDescription());
}
} catch (Exception e) {
// Ignore invalid packages
- monitor.setResult("Ignoring invalid %1$s element: %2$s",
- name, e.toString());
+ monitor.logError("Ignoring invalid %1$s element: %2$s", name, e.toString());
}
}
}
@@ -794,13 +801,13 @@ public abstract class SdkSource implements IDescription {
return doc;
} catch (ParserConfigurationException e) {
- monitor.setResult("Failed to create XML document builder");
+ monitor.logError("Failed to create XML document builder");
} catch (SAXException e) {
- monitor.setResult("Failed to parse XML document");
+ monitor.logError("Failed to parse XML document");
} catch (IOException e) {
- monitor.setResult("Failed to read XML document");
+ monitor.logError("Failed to read XML document");
}
return null;
diff --git a/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/SdkSources.java b/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/SdkSources.java
index 22678b3..be99f22 100755
--- a/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/SdkSources.java
+++ b/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/SdkSources.java
@@ -111,7 +111,7 @@ public class SdkSources {
}
/**
- * Returns an array of sources attached to the given category.
+ * Returns a new array of sources attached to the given category.
* Might return an empty array, but never returns null.
*/
public SdkSource[] getSources(SdkSourceCategory category) {
diff --git a/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/ToolPackage.java b/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/ToolPackage.java
index 6e53dd7..69039ea 100755
--- a/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/ToolPackage.java
+++ b/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/ToolPackage.java
@@ -151,7 +151,20 @@ public class ToolPackage extends Package implements IMinPlatformToolsDependency
return mMinPlatformToolsRevision;
}
- /** Returns a short description for an {@link IDescription}. */
+ /**
+ * Returns a description of this package that is suitable for a list display.
+ * <p/>
+ * {@inheritDoc}
+ */
+ @Override
+ public String getListDescription() {
+ return String.format("Android SDK Tools%1$s",
+ isObsolete() ? " (Obsolete)" : "");
+ }
+
+ /**
+ * Returns a short description for an {@link IDescription}.
+ */
@Override
public String getShortDescription() {
return String.format("Android SDK Tools, revision %1$d%2$s",
@@ -250,17 +263,17 @@ public class ToolPackage extends Package implements IMinPlatformToolsDependency
status = grabProcessOutput(proc, monitor, scriptName);
} catch (Exception e) {
- monitor.setResult("Exception: %s", e.toString());
+ monitor.logError("Exception: %s", e.toString());
}
if (status != 0) {
- monitor.setResult("Failed to execute %s", scriptName);
+ monitor.logError("Failed to execute %s", scriptName);
return;
}
}
/**
- * Get the stderr/stdout outputs of a process and return when the process is done.
+ * Gets the stderr/stdout outputs of a process and returns when the process is done.
* Both <b>must</b> be read or the process will block on windows.
* @param process The process to get the ouput from.
* @param monitor The monitor where to output errors.
@@ -285,7 +298,7 @@ public class ToolPackage extends Package implements IMinPlatformToolsDependency
while (true) {
String line = errReader.readLine();
if (line != null) {
- monitor.setResult("[%1$s] Error: %2$s", scriptName, line);
+ monitor.logError("[%1$s] Error: %2$s", scriptName, line);
} else {
break;
}
@@ -306,7 +319,7 @@ public class ToolPackage extends Package implements IMinPlatformToolsDependency
while (true) {
String line = outReader.readLine();
if (line != null) {
- monitor.setResult("[%1$s] %2$s", scriptName, line);
+ monitor.log("[%1$s] %2$s", scriptName, line);
} else {
break;
}
diff --git a/sdkmanager/libs/sdklib/src/com/android/sdklib/io/FileWrapper.java b/sdkmanager/libs/sdklib/src/com/android/sdklib/io/FileWrapper.java
deleted file mode 100644
index afc19b2..0000000
--- a/sdkmanager/libs/sdklib/src/com/android/sdklib/io/FileWrapper.java
+++ /dev/null
@@ -1,147 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.sdklib.io;
-
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.net.URI;
-
-/**
- * An implementation of {@link IAbstractFile} extending {@link File}.
- */
-public class FileWrapper extends File implements IAbstractFile {
- private static final long serialVersionUID = 1L;
-
- /**
- * Creates a new File instance matching a given {@link File} object.
- * @param file the file to match
- */
- public FileWrapper(File file) {
- super(file.getAbsolutePath());
- }
-
- /**
- * Creates a new File instance from a parent abstract pathname and a child pathname string.
- * @param parent the parent pathname
- * @param child the child name
- *
- * @see File#File(File, String)
- */
- public FileWrapper(File parent, String child) {
- super(parent, child);
- }
-
- /**
- * Creates a new File instance by converting the given pathname string into an abstract
- * pathname.
- * @param osPathname the OS pathname
- *
- * @see File#File(String)
- */
- public FileWrapper(String osPathname) {
- super(osPathname);
- }
-
- /**
- * Creates a new File instance from a parent abstract pathname and a child pathname string.
- * @param parent the parent pathname
- * @param child the child name
- *
- * @see File#File(String, String)
- */
- public FileWrapper(String parent, String child) {
- super(parent, child);
- }
-
- /**
- * Creates a new File instance by converting the given <code>file:</code> URI into an
- * abstract pathname.
- * @param uri An absolute, hierarchical URI with a scheme equal to "file", a non-empty path
- * component, and undefined authority, query, and fragment components
- *
- * @see File#File(URI)
- */
- public FileWrapper(URI uri) {
- super(uri);
- }
-
- public InputStream getContents() throws StreamException {
- try {
- return new FileInputStream(this);
- } catch (FileNotFoundException e) {
- throw new StreamException(e);
- }
- }
-
- public void setContents(InputStream source) throws StreamException {
- FileOutputStream fos = null;
- try {
- fos = new FileOutputStream(this);
-
- byte[] buffer = new byte[1024];
- int count = 0;
- while ((count = source.read(buffer)) != -1) {
- fos.write(buffer, 0, count);
- }
- } catch (IOException e) {
- throw new StreamException(e);
- } finally {
- if (fos != null) {
- try {
- fos.close();
- } catch (IOException e) {
- throw new StreamException(e);
- }
- }
- }
- }
-
- public OutputStream getOutputStream() throws StreamException {
- try {
- return new FileOutputStream(this);
- } catch (FileNotFoundException e) {
- throw new StreamException(e);
- }
- }
-
- public PreferredWriteMode getPreferredWriteMode() {
- return PreferredWriteMode.OUTPUTSTREAM;
- }
-
- public String getOsLocation() {
- return getAbsolutePath();
- }
-
- @Override
- public boolean exists() {
- return isFile();
- }
-
- public IAbstractFolder getParentFolder() {
- String p = this.getParent();
- if (p == null) {
- return null;
- }
- return new FolderWrapper(p);
- }
-}
diff --git a/sdkmanager/libs/sdklib/src/com/android/sdklib/io/FolderWrapper.java b/sdkmanager/libs/sdklib/src/com/android/sdklib/io/FolderWrapper.java
deleted file mode 100644
index 33e31c1..0000000
--- a/sdkmanager/libs/sdklib/src/com/android/sdklib/io/FolderWrapper.java
+++ /dev/null
@@ -1,154 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.sdklib.io;
-
-
-import java.io.File;
-import java.net.URI;
-import java.util.ArrayList;
-
-/**
- * An implementation of {@link IAbstractFolder} extending {@link File}.
- */
-public class FolderWrapper extends File implements IAbstractFolder {
-
- private static final long serialVersionUID = 1L;
-
- /**
- * Creates a new File instance from a parent abstract pathname and a child pathname string.
- * @param parent the parent pathname
- * @param child the child name
- *
- * @see File#File(File, String)
- */
- public FolderWrapper(File parent, String child) {
- super(parent, child);
- }
-
- /**
- * Creates a new File instance by converting the given pathname string into an abstract
- * pathname.
- * @param pathname the pathname
- *
- * @see File#File(String)
- */
- public FolderWrapper(String pathname) {
- super(pathname);
- }
-
- /**
- * Creates a new File instance from a parent abstract pathname and a child pathname string.
- * @param parent the parent pathname
- * @param child the child name
- *
- * @see File#File(String, String)
- */
- public FolderWrapper(String parent, String child) {
- super(parent, child);
- }
-
- /**
- * Creates a new File instance by converting the given <code>file:</code> URI into an
- * abstract pathname.
- * @param uri An absolute, hierarchical URI with a scheme equal to "file", a non-empty path
- * component, and undefined authority, query, and fragment components
- *
- * @see File#File(URI)
- */
- public FolderWrapper(URI uri) {
- super(uri);
- }
-
- /**
- * Creates a new File instance matching a give {@link File} object.
- * @param file the file to match
- */
- public FolderWrapper(File file) {
- super(file.getAbsolutePath());
- }
-
- public IAbstractResource[] listMembers() {
- File[] files = listFiles();
- final int count = files == null ? 0 : files.length;
- IAbstractResource[] afiles = new IAbstractResource[count];
-
- if (files != null) {
- for (int i = 0 ; i < count ; i++) {
- File f = files[i];
- if (f.isFile()) {
- afiles[i] = new FileWrapper(f);
- } else if (f.isDirectory()) {
- afiles[i] = new FolderWrapper(f);
- }
- }
- }
-
- return afiles;
- }
-
- public boolean hasFile(final String name) {
- String[] match = list(new FilenameFilter() {
- public boolean accept(IAbstractFolder dir, String filename) {
- return name.equals(filename);
- }
- });
-
- return match.length > 0;
- }
-
- public IAbstractFile getFile(String name) {
- return new FileWrapper(this, name);
- }
-
- public IAbstractFolder getFolder(String name) {
- return new FolderWrapper(this, name);
- }
-
- public IAbstractFolder getParentFolder() {
- String p = this.getParent();
- if (p == null) {
- return null;
- }
- return new FolderWrapper(p);
- }
-
- public String getOsLocation() {
- return getAbsolutePath();
- }
-
- @Override
- public boolean exists() {
- return isDirectory();
- }
-
- public String[] list(FilenameFilter filter) {
- File[] files = listFiles();
- if (files != null && files.length > 0) {
- ArrayList<String> list = new ArrayList<String>();
-
- for (File file : files) {
- if (filter.accept(this, file.getName())) {
- list.add(file.getName());
- }
- }
-
- return list.toArray(new String[list.size()]);
- }
-
- return new String[0];
- }
-}
diff --git a/sdkmanager/libs/sdklib/src/com/android/sdklib/io/IAbstractFile.java b/sdkmanager/libs/sdklib/src/com/android/sdklib/io/IAbstractFile.java
deleted file mode 100644
index 2ff1fc8..0000000
--- a/sdkmanager/libs/sdklib/src/com/android/sdklib/io/IAbstractFile.java
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.sdklib.io;
-
-import java.io.InputStream;
-import java.io.OutputStream;
-
-/**
- * A file.
- */
-public interface IAbstractFile extends IAbstractResource {
- public static enum PreferredWriteMode {
- INPUTSTREAM, OUTPUTSTREAM;
- }
-
- /**
- * Returns an {@link InputStream} object on the file content.
- * @throws StreamException
- */
- InputStream getContents() throws StreamException;
-
- /**
- * Sets the content of the file.
- * @param source the content
- * @throws StreamException
- */
- void setContents(InputStream source) throws StreamException;
-
- /**
- * Returns an {@link OutputStream} to write into the file.
- * @throws StreamException
- */
- OutputStream getOutputStream() throws StreamException;
-
- /**
- * Returns the preferred mode to write into the file.
- */
- PreferredWriteMode getPreferredWriteMode();
-}
diff --git a/sdkmanager/libs/sdklib/src/com/android/sdklib/io/IAbstractFolder.java b/sdkmanager/libs/sdklib/src/com/android/sdklib/io/IAbstractFolder.java
deleted file mode 100644
index 17c0dbd..0000000
--- a/sdkmanager/libs/sdklib/src/com/android/sdklib/io/IAbstractFolder.java
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.sdklib.io;
-
-import java.io.File;
-
-/**
- * A folder.
- */
-public interface IAbstractFolder extends IAbstractResource {
- /**
- * Instances of classes that implement this interface are used to
- * filter filenames.
- */
- public interface FilenameFilter {
- /**
- * Tests if a specified file should be included in a file list.
- *
- * @param dir the directory in which the file was found.
- * @param name the name of the file.
- * @return <code>true</code> if and only if the name should be
- * included in the file list; <code>false</code> otherwise.
- */
- boolean accept(IAbstractFolder dir, String name);
- }
-
- /**
- * Returns true if the receiver contains a file with a given name
- * @param name the name of the file. This is the name without the path leading to the
- * parent folder.
- */
- boolean hasFile(String name);
-
- /**
- * Returns an {@link IAbstractFile} representing a child of the current folder with the
- * given name. The file may not actually exist.
- * @param name the name of the file.
- */
- IAbstractFile getFile(String name);
-
- /**
- * Returns an {@link IAbstractFolder} representing a child of the current folder with the
- * given name. The folder may not actually exist.
- * @param name the name of the folder.
- */
- IAbstractFolder getFolder(String name);
-
- /**
- * Returns a list of all existing file and directory members in this folder.
- * The returned array can be empty but is never null.
- */
- IAbstractResource[] listMembers();
-
- /**
- * Returns a list of all existing file and directory members in this folder
- * that satisfy the specified filter.
- *
- * @param filter A filename filter instance. Must not be null.
- * @return An array of file names (generated using {@link File#getName()}).
- * The array can be empty but is never null.
- */
- String[] list(FilenameFilter filter);
-}
diff --git a/sdkmanager/libs/sdklib/src/com/android/sdklib/io/IAbstractResource.java b/sdkmanager/libs/sdklib/src/com/android/sdklib/io/IAbstractResource.java
deleted file mode 100644
index 0ccb107..0000000
--- a/sdkmanager/libs/sdklib/src/com/android/sdklib/io/IAbstractResource.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.sdklib.io;
-
-/**
- * Base representation of a file system resource.<p/>
- * This somewhat limited interface is designed to let classes use file-system resources, without
- * having the manually handle either the standard Java file or the Eclipse file API..
- */
-public interface IAbstractResource {
-
- /**
- * Returns the name of the resource.
- */
- String getName();
-
- /**
- * Returns the OS path of the folder location.
- */
- String getOsLocation();
-
- /**
- * Returns whether the resource actually exists.
- */
- boolean exists();
-
- /**
- * Returns the parent folder or null if there is no parent.
- */
- IAbstractFolder getParentFolder();
-}
diff --git a/sdkmanager/libs/sdklib/src/com/android/sdklib/io/StreamException.java b/sdkmanager/libs/sdklib/src/com/android/sdklib/io/StreamException.java
deleted file mode 100644
index 2088864..0000000
--- a/sdkmanager/libs/sdklib/src/com/android/sdklib/io/StreamException.java
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.sdklib.io;
-
-/**
- * Exception thrown when {@link IAbstractFile#getContents()} fails.
- */
-public class StreamException extends Exception {
- private static final long serialVersionUID = 1L;
-
- public StreamException(Exception e) {
- super(e);
- }
-}
diff --git a/sdkmanager/libs/sdklib/src/com/android/sdklib/xml/AndroidManifest.java b/sdkmanager/libs/sdklib/src/com/android/sdklib/xml/AndroidManifest.java
index 2cb6ace..26fcd7b 100644
--- a/sdkmanager/libs/sdklib/src/com/android/sdklib/xml/AndroidManifest.java
+++ b/sdkmanager/libs/sdklib/src/com/android/sdklib/xml/AndroidManifest.java
@@ -16,10 +16,10 @@
package com.android.sdklib.xml;
+import com.android.io.IAbstractFile;
+import com.android.io.IAbstractFolder;
+import com.android.io.StreamException;
import com.android.sdklib.SdkConstants;
-import com.android.sdklib.io.IAbstractFile;
-import com.android.sdklib.io.IAbstractFolder;
-import com.android.sdklib.io.StreamException;
import org.w3c.dom.Node;
import org.xml.sax.InputSource;
@@ -76,6 +76,7 @@ public final class AndroidManifest {
public final static String ATTRIBUTE_REQ_HARDKEYBOARD = "reqHardKeyboard";
public final static String ATTRIBUTE_REQ_KEYBOARDTYPE = "reqKeyboardType";
public final static String ATTRIBUTE_REQ_TOUCHSCREEN = "reqTouchScreen";
+ public static final String ATTRIBUTE_THEME = "theme";
/**
* Returns an {@link IAbstractFile} object representing the manifest for the given project.
diff --git a/sdkmanager/libs/sdklib/src/com/android/sdklib/xml/AndroidManifestParser.java b/sdkmanager/libs/sdklib/src/com/android/sdklib/xml/AndroidManifestParser.java
index 09e81f7..ca59a8e 100644
--- a/sdkmanager/libs/sdklib/src/com/android/sdklib/xml/AndroidManifestParser.java
+++ b/sdkmanager/libs/sdklib/src/com/android/sdklib/xml/AndroidManifestParser.java
@@ -16,13 +16,13 @@
package com.android.sdklib.xml;
+import com.android.io.IAbstractFile;
+import com.android.io.IAbstractFolder;
+import com.android.io.StreamException;
import com.android.resources.Keyboard;
import com.android.resources.Navigation;
import com.android.resources.TouchScreen;
import com.android.sdklib.SdkConstants;
-import com.android.sdklib.io.IAbstractFile;
-import com.android.sdklib.io.IAbstractFolder;
-import com.android.sdklib.io.StreamException;
import com.android.sdklib.xml.ManifestData.Activity;
import com.android.sdklib.xml.ManifestData.Instrumentation;
import com.android.sdklib.xml.ManifestData.SupportsScreens;