import com.android.sdklib.AndroidVersion.AndroidVersionException;
import com.android.sdklib.internal.project.ProjectProperties;
import com.android.sdklib.io.FileWrapper;
+import com.android.sdklib.util.Pair;
import java.io.File;
import java.io.FileInputStream;
*/
public final class SdkManager {
- public final static String PROP_VERSION_SDK = "ro.build.version.sdk";
- public final static String PROP_VERSION_CODENAME = "ro.build.version.codename";
- public final static String PROP_VERSION_RELEASE = "ro.build.version.release";
+ public final static String PROP_VERSION_SDK = "ro.build.version.sdk"; //$NON-NLS-1$
+ public final static String PROP_VERSION_CODENAME = "ro.build.version.codename"; //$NON-NLS-1$
+ public final static String PROP_VERSION_RELEASE = "ro.build.version.release"; //$NON-NLS-1$
- private final static String ADDON_NAME = "name";
- private final static String ADDON_VENDOR = "vendor";
- private final static String ADDON_API = "api";
- private final static String ADDON_DESCRIPTION = "description";
- private final static String ADDON_LIBRARIES = "libraries";
- private final static String ADDON_DEFAULT_SKIN = "skin";
- private final static String ADDON_USB_VENDOR = "usb-vendor";
- private final static String ADDON_REVISION = "revision";
- private final static String ADDON_REVISION_OLD = "version";
+ public final static String ADDON_NAME = "name"; //$NON-NLS-1$
+ public final static String ADDON_VENDOR = "vendor"; //$NON-NLS-1$
+ public final static String ADDON_API = "api"; //$NON-NLS-1$
+ public final static String ADDON_DESCRIPTION = "description"; //$NON-NLS-1$
+ public final static String ADDON_LIBRARIES = "libraries"; //$NON-NLS-1$
+ public final static String ADDON_DEFAULT_SKIN = "skin"; //$NON-NLS-1$
+ public final static String ADDON_USB_VENDOR = "usb-vendor"; //$NON-NLS-1$
+ public final static String ADDON_REVISION = "revision"; //$NON-NLS-1$
+ public final static String ADDON_REVISION_OLD = "version"; //$NON-NLS-1$
private final static Pattern PATTERN_LIB_DATA = Pattern.compile(
- "^([a-zA-Z0-9._-]+\\.jar);(.*)$", Pattern.CASE_INSENSITIVE);
+ "^([a-zA-Z0-9._-]+\\.jar);(.*)$", Pattern.CASE_INSENSITIVE); //$NON-NLS-1$
// usb ids are 16-bit hexadecimal values.
private final static Pattern PATTERN_USB_IDS = Pattern.compile(
- "^0x[a-f0-9]{4}$", Pattern.CASE_INSENSITIVE);
+ "^0x[a-f0-9]{4}$", Pattern.CASE_INSENSITIVE); //$NON-NLS-1$
/** List of items in the platform to check when parsing it. These paths are relative to the
* platform root folder. */
};
/** Preference file containing the usb ids for adb */
- private final static String ADB_INI_FILE = "adb_usb.ini";
+ private final static String ADB_INI_FILE = "adb_usb.ini"; //$NON-NLS-1$
//0--------90--------90--------90--------90--------90--------90--------90--------9
private final static String ADB_INI_HEADER =
- "# ANDROID 3RD PARTY USB VENDOR ID LIST -- DO NOT EDIT.\n" +
- "# USE 'android update adb' TO GENERATE.\n" +
- "# 1 USB VENDOR ID PER LINE.\n";
+ "# ANDROID 3RD PARTY USB VENDOR ID LIST -- DO NOT EDIT.\n" + //$NON-NLS-1$
+ "# USE 'android update adb' TO GENERATE.\n" + //$NON-NLS-1$
+ "# 1 USB VENDOR ID PER LINE.\n"; //$NON-NLS-1$
- /** the location of the SDK */
- private final String mSdkLocation;
+ /** The location of the SDK as an OS path */
+ private final String mOsSdkPath;
+ /** Valid targets that have been loaded. */
private IAndroidTarget[] mTargets;
/**
* Create a new {@link SdkManager} instance.
* External users should use {@link #createManager(String, ISdkLog)}.
*
- * @param sdkLocation the location of the SDK.
+ * @param osSdkPath the location of the SDK.
*/
- private SdkManager(String sdkLocation) {
- mSdkLocation = sdkLocation;
+ private SdkManager(String osSdkPath) {
+ mOsSdkPath = osSdkPath;
}
/**
* Creates an {@link SdkManager} for a given sdk location.
- * @param sdkLocation the location of the SDK.
+ * @param osSdkPath the location of the SDK.
* @param log the ISdkLog object receiving warning/error from the parsing. Cannot be null.
* @return the created {@link SdkManager} or null if the location is not valid.
*/
- public static SdkManager createManager(String sdkLocation, ISdkLog log) {
+ public static SdkManager createManager(String osSdkPath, ISdkLog log) {
try {
- SdkManager manager = new SdkManager(sdkLocation);
+ SdkManager manager = new SdkManager(osSdkPath);
ArrayList<IAndroidTarget> list = new ArrayList<IAndroidTarget>();
- loadPlatforms(sdkLocation, list, log);
- loadAddOns(sdkLocation, list, log);
+ loadPlatforms(osSdkPath, list, log);
+ loadAddOns(osSdkPath, list, log);
// sort the targets/add-ons
Collections.sort(list);
* Returns the location of the SDK.
*/
public String getLocation() {
- return mSdkLocation;
+ return mOsSdkPath;
}
/**
// now write the Id in a text file, one per line.
for (Integer i : set) {
- writer.write(String.format("0x%04x\n", i));
+ writer.write(String.format("0x%04x\n", i)); //$NON-NLS-1$
}
} finally {
if (writer != null) {
public void reloadSdk(ISdkLog log) {
// get the current target list.
ArrayList<IAndroidTarget> list = new ArrayList<IAndroidTarget>();
- loadPlatforms(mSdkLocation, list, log);
- loadAddOns(mSdkLocation, list, log);
+ loadPlatforms(mOsSdkPath, list, log);
+ loadAddOns(mOsSdkPath, list, log);
// For now replace the old list with the new one.
// In the future we may want to keep the current objects, so that ADT doesn't have to deal
sourcePropFile, log);
if (sourceProp != null) {
try {
- revision = Integer.parseInt(sourceProp.get("Pkg.Revision"));
+ revision = Integer.parseInt(sourceProp.get("Pkg.Revision")); //$NON-NLS-1$
} catch (NumberFormatException e) {
// do nothing, we'll keep the default value of 1.
}
return target;
}
} else {
- log.warning("Ignoring platform '%1$s': %2$s is missing.", platformFolder.getName(),
+ log.warning("Ignoring platform '%1$s': %2$s is missing.", //$NON-NLS-1$
+ platformFolder.getName(),
SdkConstants.FN_BUILD_PROP);
}
/**
* Loads the Add-on from the SDK.
- * @param location Location of the SDK
+ * @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.
*/
- private static void loadAddOns(String location, ArrayList<IAndroidTarget> list, ISdkLog log) {
- File addonFolder = new File(location, SdkConstants.FD_ADDONS);
+ 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();
+ IAndroidTarget[] targetList = list.toArray(new IAndroidTarget[list.size()]);
+
for (File addon : addons) {
// Add-ons have to be folders. Ignore files and no need to warn about them.
if (addon.isDirectory()) {
- AddOnTarget target = loadAddon(addon, list, log);
+ AddOnTarget target = loadAddon(addon, targetList, log);
if (target != null) {
list.add(target);
}
/**
* Loads a specific Add-on at a given location.
- * @param addon the location of the addon.
+ * @param addonDir the location of the add-on directory.
* @param targetList The list of Android target that were already loaded from the SDK.
* @param log the ISdkLog object receiving warning/error from the parsing. Cannot be null.
*/
- private static AddOnTarget loadAddon(File addon, ArrayList<IAndroidTarget> targetList,
+ private static AddOnTarget loadAddon(File addonDir,
+ IAndroidTarget[] targetList,
ISdkLog log) {
- FileWrapper addOnManifest = new FileWrapper(addon, SdkConstants.FN_MANIFEST_INI);
- if (addOnManifest.isFile()) {
- Map<String, String> propertyMap = ProjectProperties.parsePropertyFile(
- addOnManifest, log);
+ // Parse the addon properties to ensure we can load it.
+ Pair<Map<String, String>, String> infos = parseAddonProperties(addonDir, targetList, log);
- if (propertyMap != null) {
- // look for some specific values in the map.
- // we require name, vendor, and api
- String name = propertyMap.get(ADDON_NAME);
- if (name == null) {
- displayAddonManifestWarning(log, addon.getName(), ADDON_NAME);
- return null;
- }
+ Map<String, String> propertyMap = infos.getFirst();
+ String error = infos.getSecond();
- String vendor = propertyMap.get(ADDON_VENDOR);
- if (vendor == null) {
- displayAddonManifestWarning(log, addon.getName(), ADDON_VENDOR);
- return null;
- }
+ if (error != null) {
+ log.warning("Ignoring add-on '%1$s': %2$s", addonDir.getName(), error);
+ return null;
+ }
- String api = propertyMap.get(ADDON_API);
- PlatformTarget baseTarget = null;
- if (api == null) {
- displayAddonManifestWarning(log, addon.getName(), ADDON_API);
- return null;
- } else {
- // Look for a platform that has a matching api level or codename.
- for (IAndroidTarget target : targetList) {
- if (target.isPlatform() && target.getVersion().equals(api)) {
- baseTarget = (PlatformTarget)target;
- break;
- }
- }
+ // Since error==null we're not supposed to encounter any issues loading this add-on.
+ try {
+ assert propertyMap != null;
- if (baseTarget == null) {
- // Ignore this add-on.
- log.warning(
- "Ignoring add-on '%1$s': Unable to find base platform with API level '%2$s'",
- addon.getName(), api);
- return null;
- }
- }
+ String api = propertyMap.get(ADDON_API);
+ String name = propertyMap.get(ADDON_NAME);
+ String vendor = propertyMap.get(ADDON_VENDOR);
- // get the optional description
- String description = propertyMap.get(ADDON_DESCRIPTION);
+ assert api != null;
+ assert name != null;
+ assert vendor != null;
- // get the add-on revision
- int revisionValue = 1;
- String revision = propertyMap.get(ADDON_REVISION);
- if (revision == null) {
- revision = propertyMap.get(ADDON_REVISION_OLD);
- }
- if (revision != null) {
- try {
- revisionValue = Integer.parseInt(revision);
- } catch (NumberFormatException e) {
- // looks like apiNumber does not parse to a number.
- // Ignore this add-on.
- log.warning(
- "Ignoring add-on '%1$s': %2$s is not a valid number in %3$s.",
- addon.getName(), ADDON_REVISION, SdkConstants.FN_BUILD_PROP);
- return null;
- }
+ PlatformTarget baseTarget = null;
+
+ // Look for a platform that has a matching api level or codename.
+ for (IAndroidTarget target : targetList) {
+ if (target.isPlatform() && target.getVersion().equals(api)) {
+ baseTarget = (PlatformTarget)target;
+ break;
}
+ }
+
+ assert baseTarget != null;
+
+ // get the optional description
+ String description = propertyMap.get(ADDON_DESCRIPTION);
+
+ // get the add-on revision
+ int revisionValue = 1;
+ String revision = propertyMap.get(ADDON_REVISION);
+ if (revision == null) {
+ revision = propertyMap.get(ADDON_REVISION_OLD);
+ }
+ if (revision != null) {
+ revisionValue = Integer.parseInt(revision);
+ }
- // get the optional libraries
- String librariesValue = propertyMap.get(ADDON_LIBRARIES);
- Map<String, String[]> libMap = null;
-
- if (librariesValue != null) {
- librariesValue = librariesValue.trim();
- if (librariesValue.length() > 0) {
- // split in the string into the libraries name
- String[] libraries = librariesValue.split(";");
- if (libraries.length > 0) {
- libMap = new HashMap<String, String[]>();
- for (String libName : libraries) {
- libName = libName.trim();
-
- // get the library data from the properties
- String libData = propertyMap.get(libName);
-
- if (libData != null) {
- // split the jar file from the description
- Matcher m = PATTERN_LIB_DATA.matcher(libData);
- if (m.matches()) {
- libMap.put(libName, new String[] {
- m.group(1), m.group(2) });
- } else {
- log.warning(
- "Ignoring library '%1$s', property value has wrong format\n\t%2$s",
- libName, libData);
- }
+ // get the optional libraries
+ String librariesValue = propertyMap.get(ADDON_LIBRARIES);
+ Map<String, String[]> libMap = null;
+
+ if (librariesValue != null) {
+ librariesValue = librariesValue.trim();
+ if (librariesValue.length() > 0) {
+ // split in the string into the libraries name
+ String[] libraries = librariesValue.split(";"); //$NON-NLS-1$
+ if (libraries.length > 0) {
+ libMap = new HashMap<String, String[]>();
+ for (String libName : libraries) {
+ libName = libName.trim();
+
+ // get the library data from the properties
+ String libData = propertyMap.get(libName);
+
+ if (libData != null) {
+ // split the jar file from the description
+ Matcher m = PATTERN_LIB_DATA.matcher(libData);
+ if (m.matches()) {
+ libMap.put(libName, new String[] {
+ m.group(1), m.group(2) });
} else {
log.warning(
- "Ignoring library '%1$s', missing property value",
+ "Ignoring library '%1$s', property value has wrong format\n\t%2$s",
libName, libData);
}
+ } else {
+ log.warning(
+ "Ignoring library '%1$s', missing property value",
+ libName, libData);
}
}
}
}
+ }
- AddOnTarget target = new AddOnTarget(addon.getAbsolutePath(), name, vendor,
- revisionValue, description, libMap, baseTarget);
+ AddOnTarget target = new AddOnTarget(addonDir.getAbsolutePath(), name, vendor,
+ revisionValue, description, libMap, baseTarget);
- // need to parse the skins.
- String[] skins = parseSkinFolder(target.getPath(IAndroidTarget.SKINS));
+ // need to parse the skins.
+ String[] skins = parseSkinFolder(target.getPath(IAndroidTarget.SKINS));
- // get the default skin, or take it from the base platform if needed.
- String defaultSkin = propertyMap.get(ADDON_DEFAULT_SKIN);
- if (defaultSkin == null) {
- if (skins.length == 1) {
- defaultSkin = skins[0];
- } else {
- defaultSkin = baseTarget.getDefaultSkin();
- }
+ // get the default skin, or take it from the base platform if needed.
+ String defaultSkin = propertyMap.get(ADDON_DEFAULT_SKIN);
+ if (defaultSkin == null) {
+ if (skins.length == 1) {
+ defaultSkin = skins[0];
+ } else {
+ defaultSkin = baseTarget.getDefaultSkin();
}
+ }
- // get the USB ID (if available)
- int usbVendorId = convertId(propertyMap.get(ADDON_USB_VENDOR));
- if (usbVendorId != IAndroidTarget.NO_USB_ID) {
- target.setUsbVendorId(usbVendorId);
- }
+ // get the USB ID (if available)
+ int usbVendorId = convertId(propertyMap.get(ADDON_USB_VENDOR));
+ if (usbVendorId != IAndroidTarget.NO_USB_ID) {
+ target.setUsbVendorId(usbVendorId);
+ }
- target.setSkins(skins, defaultSkin);
+ target.setSkins(skins, defaultSkin);
- return target;
- }
- } else {
- log.warning("Ignoring add-on '%1$s': %2$s is missing.", addon.getName(),
- SdkConstants.FN_MANIFEST_INI);
+ return target;
+ }
+ catch (Exception e) {
+ log.warning("Ignoring add-on '%1$s': error %2$s.",
+ addonDir.getName(), e.toString());
}
return null;
}
/**
+ * Parses the add-on properties and decodes any error that occurs when loading an addon.
+ *
+ * @param addonDir the location of the addon directory.
+ * @param targetList The list of Android target that were already loaded from the SDK.
+ * @param log the ISdkLog object receiving warning/error from the parsing. Cannot be null.
+ * @return A pair with the property map and an error string. Both can be null but not at the
+ * same time. If a non-null error is present then the property map must be ignored. The error
+ * should be translatable as it might show up in the SdkManager UI.
+ */
+ public static Pair<Map<String, String>, String> parseAddonProperties(
+ File addonDir,
+ IAndroidTarget[] targetList,
+ ISdkLog log) {
+ Map<String, String> propertyMap = null;
+ String error = null;
+
+ FileWrapper addOnManifest = new FileWrapper(addonDir, SdkConstants.FN_MANIFEST_INI);
+
+ do {
+ if (!addOnManifest.isFile()) {
+ error = String.format("File not found: %1$s", SdkConstants.FN_MANIFEST_INI);
+ break;
+ }
+
+ propertyMap = ProjectProperties.parsePropertyFile(addOnManifest, log);
+ if (propertyMap == null) {
+ error = String.format("Failed to parse properties from %1$s",
+ SdkConstants.FN_MANIFEST_INI);
+ break;
+ }
+
+ // look for some specific values in the map.
+ // we require name, vendor, and api
+ String name = propertyMap.get(ADDON_NAME);
+ if (name == null) {
+ error = addonManifestWarning(ADDON_NAME);
+ break;
+ }
+
+ String vendor = propertyMap.get(ADDON_VENDOR);
+ if (vendor == null) {
+ error = addonManifestWarning(ADDON_VENDOR);
+ break;
+ }
+
+ String api = propertyMap.get(ADDON_API);
+ PlatformTarget baseTarget = null;
+ if (api == null) {
+ error = addonManifestWarning(ADDON_API);
+ break;
+ }
+
+ // Look for a platform that has a matching api level or codename.
+ for (IAndroidTarget target : targetList) {
+ if (target.isPlatform() && target.getVersion().equals(api)) {
+ baseTarget = (PlatformTarget)target;
+ break;
+ }
+ }
+
+ if (baseTarget == null) {
+ error = String.format("Unable to find base platform with API level '%1$s'", api);
+ break;
+ }
+
+ // get the add-on revision
+ String revision = propertyMap.get(ADDON_REVISION);
+ if (revision == null) {
+ revision = propertyMap.get(ADDON_REVISION_OLD);
+ }
+ if (revision != null) {
+ try {
+ Integer.parseInt(revision);
+ } catch (NumberFormatException e) {
+ // looks like revision does not parse to a number.
+ error = String.format("%1$s is not a valid number in %2$s.",
+ ADDON_REVISION, SdkConstants.FN_BUILD_PROP);
+ break;
+ }
+ }
+
+ } while(false);
+
+ return Pair.of(propertyMap, error);
+ }
+
+ /**
* Converts a string representation of an hexadecimal ID into an int.
* @param value the string to convert.
* @return the int value, or {@link IAndroidTarget#NO_USB_ID} if the convertion failed.
}
/**
- * Displays a warning in the log about the addon being ignored due to a missing manifest value.
+ * Prepares a warning about the addon being ignored due to a missing manifest value.
+ * This string will show up in the SdkManager UI.
*
- * @param log The logger object. Cannot be null.
- * @param addonName The addon name, for display.
* @param valueName The missing manifest value, for display.
*/
- private static void displayAddonManifestWarning(ISdkLog log, String addonName,
- String valueName) {
- log.warning("Ignoring add-on '%1$s': '%2$s' is missing from %3$s.",
- addonName, valueName, SdkConstants.FN_MANIFEST_INI);
+ private static String addonManifestWarning(String valueName) {
+ return String.format("'%1$s' is missing from %2$s.",
+ valueName, SdkConstants.FN_MANIFEST_INI);
}
/**
File f = new File(platform, relativePath);
if (!f.exists()) {
log.warning(
- "Ignoring platform '%1$s': %2$s is missing.",
+ "Ignoring platform '%1$s': %2$s is missing.", //$NON-NLS-1$
platform.getName(), relativePath);
return false;
}
* @param log Logger. Cannot be null.
*/
private void loadSamples(ISdkLog log) {
- File sampleFolder = new File(mSdkLocation, SdkConstants.FD_SAMPLES);
+ File sampleFolder = new File(mOsSdkPath, SdkConstants.FD_SAMPLES);
if (sampleFolder.isDirectory()) {
File[] platforms = sampleFolder.listFiles();
return new AndroidVersion(p);
} catch (FileNotFoundException e) {
- log.warning("Ignoring sample '%1$s': does not contain %2$s.", //$NON-NLS-1$
+ log.warning("Ignoring sample '%1$s': does not contain %2$s.", //$NON-NLS-1$
folder.getName(), SdkConstants.FN_SOURCE_PROP);
} catch (IOException e) {
- log.warning("Ignoring sample '%1$s': failed reading %2$s.", //$NON-NLS-1$
+ log.warning("Ignoring sample '%1$s': failed reading %2$s.", //$NON-NLS-1$
folder.getName(), SdkConstants.FN_SOURCE_PROP);
} catch (AndroidVersionException e) {
- log.warning("Ignoring sample '%1$s': no android version found in %2$s.", //$NON-NLS-1$
+ log.warning("Ignoring sample '%1$s': no android version found in %2$s.", //$NON-NLS-1$
folder.getName(), SdkConstants.FN_SOURCE_PROP);
}
--- /dev/null
+/*\r
+ * Copyright (C) 2010 The Android Open Source Project\r
+ *\r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+\r
+package com.android.sdklib.internal.repository;\r
+\r
+import com.android.sdklib.SdkManager;\r
+import com.android.sdklib.internal.repository.Archive.Arch;\r
+import com.android.sdklib.internal.repository.Archive.Os;\r
+\r
+import java.io.File;\r
+import java.util.Properties;\r
+\r
+/**\r
+ * Represents an SDK repository package that is incomplete.\r
+ * It has a distinct icon and a specific error that is supposed to help the user on how to fix it.\r
+ */\r
+public class BrokenPackage extends Package implements IMinApiLevelDependency {\r
+\r
+ /**\r
+ * The minimal API level required by this extra package, if > 0,\r
+ * or {@link #MIN_API_LEVEL_NOT_SPECIFIED} if there is no such requirement.\r
+ */\r
+ private final int mMinApiLevel;\r
+\r
+ private final String mShortDescription;\r
+\r
+ /**\r
+ * Creates a new "broken" package that represents a package that we failed to load,\r
+ * for whatever error indicated in <code>error</code>.\r
+ * There is also an <em>optional</em> API level dependency that can be specified.\r
+ * <p/>\r
+ * By design, this creates a package with one and only one archive.\r
+ */\r
+ BrokenPackage(Properties props,\r
+ String shortDescription,\r
+ String longDescription,\r
+ int minApiLevel,\r
+ String archiveOsPath) {\r
+ super( null, //source\r
+ props, //properties\r
+ 0, //revision will be taken from props\r
+ null, //license\r
+ longDescription, //description\r
+ null, //descUrl\r
+ Os.ANY, //archiveOs\r
+ Arch.ANY, //archiveArch\r
+ archiveOsPath //archiveOsPath\r
+ );\r
+ mShortDescription = shortDescription;\r
+ mMinApiLevel = minApiLevel;\r
+ }\r
+\r
+ /**\r
+ * Save the properties of the current packages in the given {@link Properties} object.\r
+ * These properties will later be given to a constructor that takes a {@link Properties} object.\r
+ * <p/>\r
+ * Base implementation override: We don't actually save properties for a broken package.\r
+ */\r
+ @Override\r
+ void saveProperties(Properties props) {\r
+ // Nop. We don't actually save properties for a broken package.\r
+ }\r
+\r
+ /**\r
+ * Returns the minimal API level required by this extra package, if > 0,\r
+ * or {@link #MIN_API_LEVEL_NOT_SPECIFIED} if there is no such requirement.\r
+ */\r
+ public int getMinApiLevel() {\r
+ return mMinApiLevel;\r
+ }\r
+\r
+ /** Returns a short description for an {@link IDescription}. */\r
+ @Override\r
+ public String getShortDescription() {\r
+ return mShortDescription;\r
+ }\r
+\r
+ /**\r
+ * Returns a long description for an {@link IDescription}.\r
+ *\r
+ * The long description is whatever the XML contains for the <description> field,\r
+ * or the short description if the former is empty.\r
+ */\r
+ @Override\r
+ public String getLongDescription() {\r
+ String s = getDescription();\r
+ if (s == null || s.length() == 0) {\r
+ s = getShortDescription();\r
+ }\r
+ return s;\r
+ }\r
+\r
+ /**\r
+ * We should not be attempting to install a broken package.\r
+ *\r
+ * {@inheritDoc}\r
+ */\r
+ @Override\r
+ public File getInstallFolder(String osSdkRoot, SdkManager sdkManager) {\r
+ // We should not be attempting to install a broken package.\r
+ return null;\r
+ }\r
+\r
+ @Override\r
+ public boolean sameItemAs(Package pkg) {\r
+ if (pkg instanceof BrokenPackage) {\r
+ return mShortDescription.equals(((BrokenPackage) pkg).mShortDescription) &&\r
+ getDescription().equals(pkg.getDescription()) &&\r
+ getMinApiLevel() == ((BrokenPackage) pkg).getMinApiLevel();\r
+ }\r
+\r
+ return false;\r
+ }\r
+\r
+ @Override\r
+ public boolean preInstallHook(Archive archive,\r
+ ITaskMonitor monitor,\r
+ String osSdkRoot,\r
+ File installFolder) {\r
+ // Nothing specific to do.\r
+ return super.preInstallHook(archive, monitor, osSdkRoot, installFolder);\r
+ }\r
+\r
+ /**\r
+ * Computes a hash of the installed content (in case of successful install.)\r
+ *\r
+ * {@inheritDoc}\r
+ */\r
+ @Override\r
+ public void postInstallHook(Archive archive, ITaskMonitor monitor, File installFolder) {\r
+ // Nothing specific to do.\r
+ super.postInstallHook(archive, monitor, installFolder);\r
+ }\r
+}\r
import com.android.sdklib.SdkManager;\r
import com.android.sdklib.internal.repository.Archive.Arch;\r
import com.android.sdklib.internal.repository.Archive.Os;\r
+import com.android.sdklib.util.Pair;\r
\r
import java.io.File;\r
import java.io.FileInputStream;\r
import java.util.ArrayList;\r
import java.util.Collections;\r
import java.util.HashSet;\r
+import java.util.Map;\r
import java.util.Properties;\r
import java.util.Set;\r
\r
\r
// for platforms, add-ons and samples, rely on the SdkManager parser\r
for(IAndroidTarget target : sdkManager.getTargets()) {\r
-\r
Properties props = parseProperties(new File(target.getLocation(),\r
SdkConstants.FN_SOURCE_PROP));\r
\r
try {\r
if (target.isPlatform()) {\r
- pkg = new PlatformPackage(target, props);\r
+ pkg = PlatformPackage.create(target, props);\r
\r
if (samplesRoot.isDirectory()) {\r
// Get the samples dir for a platform if it is located in the new\r
Properties samplesProps = parseProperties(\r
new File(samplesDir, SdkConstants.FN_SOURCE_PROP));\r
if (samplesProps != null) {\r
- SamplePackage pkg2 = new SamplePackage(target, samplesProps);\r
+ Package pkg2 = SamplePackage.create(target, samplesProps);\r
packages.add(pkg2);\r
}\r
visited.add(samplesDir);\r
}\r
}\r
} else {\r
- pkg = new AddonPackage(target, props);\r
+ pkg = AddonPackage.create(target, props);\r
}\r
} catch (Exception e) {\r
log.error(e, null);\r
}\r
}\r
\r
+ scanMissingAddons(sdkManager, visited, packages, log);\r
scanMissingSamples(osSdkRoot, visited, packages, log);\r
scanExtras(osSdkRoot, visited, packages, log);\r
\r
Properties props = parseProperties(new File(dir, SdkConstants.FN_SOURCE_PROP));\r
if (props != null) {\r
try {\r
- ExtraPackage pkg = new ExtraPackage(\r
+ Package pkg = ExtraPackage.create(\r
null, //source\r
props, //properties\r
null, //vendor\r
dir.getPath() //archiveOsPath\r
);\r
\r
- // We only accept this as an extra package if it has a valid local path.\r
- if (pkg.isPathValid()) {\r
- packages.add(pkg);\r
- visited.add(dir);\r
- }\r
+ packages.add(pkg);\r
+ visited.add(dir);\r
} catch (Exception e) {\r
log.error(e, null);\r
}\r
Properties props = parseProperties(new File(dir, SdkConstants.FN_SOURCE_PROP));\r
if (props != null) {\r
try {\r
- SamplePackage pkg = new SamplePackage(dir.getAbsolutePath(), props);\r
+ Package pkg = SamplePackage.create(dir.getAbsolutePath(), props);\r
packages.add(pkg);\r
visited.add(dir);\r
} catch (Exception e) {\r
}\r
\r
/**\r
+ * The sdk manager only lists valid addons. However here we also want to find "broken"\r
+ * addons, i.e. addons that failed to load for some reason.\r
+ * <p/>\r
+ * Find any other sub-directories under the /add-ons root that hasn't been visited yet\r
+ * and assume they contain broken addons.\r
+ */\r
+ private void scanMissingAddons(SdkManager sdkManager,\r
+ HashSet<File> visited,\r
+ ArrayList<Package> packages,\r
+ ISdkLog log) {\r
+ File addons = new File(new File(sdkManager.getLocation()), SdkConstants.FD_ADDONS);\r
+\r
+ if (!addons.isDirectory()) {\r
+ // It makes listFiles() return null so let's avoid it.\r
+ return;\r
+ }\r
+\r
+ for (File dir : addons.listFiles()) {\r
+ if (dir.isDirectory() && !visited.contains(dir)) {\r
+ Pair<Map<String, String>, String> infos =\r
+ SdkManager.parseAddonProperties(dir, sdkManager.getTargets(), log);\r
+\r
+ Map<String, String> props = infos.getFirst();\r
+ String error = infos.getSecond();\r
+ try {\r
+ Package pkg = AddonPackage.create(dir.getAbsolutePath(), props, error);\r
+ packages.add(pkg);\r
+ visited.add(dir);\r
+ } catch (Exception e) {\r
+ log.error(e, null);\r
+ }\r
+ }\r
+ }\r
+ }\r
+\r
+ /**\r
* Try to find a tools package at the given location.\r
* Returns null if not found.\r
*/\r
\r
// Create our package. use the properties if we found any.\r
try {\r
- ToolPackage pkg = new ToolPackage(\r
+ Package pkg = ToolPackage.create(\r
null, //source\r
props, //properties\r
0, //revision\r
return null;\r
}\r
\r
- Set<String> names = new HashSet<String>();\r
- for (File file : platformToolsFolder.listFiles()) {\r
- names.add(file.getName());\r
- }\r
- if (!names.contains(SdkConstants.FN_ADB) ||\r
- !names.contains(SdkConstants.FN_AAPT) ||\r
- !names.contains(SdkConstants.FN_AIDL) ||\r
- !names.contains(SdkConstants.FN_DX)) {\r
- return null;\r
- }\r
-\r
// Create our package. use the properties if we found any.\r
try {\r
- PlatformToolPackage pkg = new PlatformToolPackage(\r
+ Package pkg = PlatformToolPackage.create(\r
null, //source\r
props, //properties\r
0, //revision\r
// We don't actually check the content of the file.\r
if (new File(docFolder, "index.html").isFile()) {\r
try {\r
- DocPackage pkg = new DocPackage(\r
+ Package pkg = DocPackage.create(\r
null, //source\r
props, //properties\r
0, //apiLevel\r