diff options
Diffstat (limited to 'sdkmanager/libs/sdklib/src/com/android')
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; |