FileDocCategorySizeDatePackage
SdkManager.javaAPI DocAndroid 1.5 API19862Wed May 06 22:41:10 BST 2009com.android.sdklib

SdkManager

public final class SdkManager extends Object
The SDK manager parses the SDK folder and gives access to the content.
see
PlatformTarget
see
AddOnTarget

Fields Summary
public static final String
PROP_VERSION_SDK
public static final String
PROP_VERSION_RELEASE
private static final String
ADDON_NAME
private static final String
ADDON_VENDOR
private static final String
ADDON_API
private static final String
ADDON_DESCRIPTION
private static final String
ADDON_LIBRARIES
private static final String
ADDON_DEFAULT_SKIN
private static final Pattern
PATTERN_PROP
private static final Pattern
PATTERN_LIB_DATA
private static final String[]
sPlatformContentList
List of items in the platform to check when parsing it. These paths are relative to the platform root folder.
private final String
mSdkLocation
the location of the SDK
private IAndroidTarget[]
mTargets
Constructors Summary
private SdkManager(String sdkLocation)

        mSdkLocation = sdkLocation;
    
Methods Summary
private booleancheckPlatformContent(java.io.File platform, ISdkLog log)
Checks the given platform has all the required files, and returns true if they are all present.

This checks the presence of the following files: android.jar, framework.aidl, aapt(.exe), aidl(.exe), dx(.bat), and dx.jar

        for (String relativePath : sPlatformContentList) {
            File f = new File(platform, relativePath);
            if (f.exists() == false) {
                log.error(null,
                        "Ignoring platform '%1$s': %2$s is missing.",
                        platform.getName(), relativePath);
                return false;
            }
            
        }
        return true;
    
public static com.android.sdklib.SdkManagercreateManager(java.lang.String sdkLocation, ISdkLog log)
Creates an {@link SdkManager} for a given sdk location.

param
sdkLocation the location of the SDK.
param
log the ISdkLog object receiving warning/error from the parsing.
return
the created {@link SdkManager} or null if the location is not valid.


                                                
           
        try {
            SdkManager manager = new SdkManager(sdkLocation);
            ArrayList<IAndroidTarget> list = new ArrayList<IAndroidTarget>();
            manager.loadPlatforms(list, log);
            manager.loadAddOns(list, log);
            
            // sort the targets/add-ons
            Collections.sort(list);
            
            manager.setTargets(list.toArray(new IAndroidTarget[list.size()]));
            
            return manager;
        } catch (IllegalArgumentException e) {
            if (log != null) {
                log.error(e, "Error parsing the sdk.");
            }
        }
        
        return null;
    
private voiddisplayAddonManifestError(ISdkLog log, java.lang.String addonName, java.lang.String valueName)

        if (log != null) {
            log.error(null, "Ignoring add-on '%1$s': '%2$s' is missing from %3$s.",
                    addonName, valueName, SdkConstants.FN_MANIFEST_INI);
        }
    
public java.lang.StringgetLocation()
Returns the location of the SDK.

        return mSdkLocation;
    
public IAndroidTargetgetTargetFromHashString(java.lang.String hash)
Returns a target from a hash that was generated by {@link IAndroidTarget#hashString()}.

param
hash the {@link IAndroidTarget} hash string.
return
The matching {@link IAndroidTarget} or null.

        if (hash != null) {
            for (IAndroidTarget target : mTargets) {
                if (hash.equals(target.hashString())) {
                    return target;
                }
            }
        }

        return null;
    
public IAndroidTarget[]getTargets()
Returns the targets that are available in the SDK.

        return mTargets;
    
private voidloadAddOns(java.util.ArrayList list, ISdkLog log)
Loads the Add-on from the SDK.

param
list the list to fill with the add-ons.
param
log the ISdkLog object receiving warning/error from the parsing.

        File addonFolder = new File(mSdkLocation, SdkConstants.FD_ADDONS);
        if (addonFolder.isDirectory()) {
            File[] addons  = addonFolder.listFiles();
            
            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);
                    if (target != null) {
                        list.add(target);
                    }
                }
            }

            return;
        }

        String message = null;
        if (addonFolder.exists() == false) {
            message = "%s is missing.";
        } else {
            message = "%s is not a folder.";
        }

        throw new IllegalArgumentException(String.format(message,
                addonFolder.getAbsolutePath()));
    
private AddOnTargetloadAddon(java.io.File addon, java.util.ArrayList list, ISdkLog log)
Loads a specific Add-on at a given location.

param
addon the location of the addon.
param
list
param
log

        File addOnManifest = new File(addon, SdkConstants.FN_MANIFEST_INI);
        
        if (addOnManifest.isFile()) {
            Map<String, String> propertyMap = parsePropertyFile(addOnManifest, 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) {
                    displayAddonManifestError(log, addon.getName(), ADDON_NAME);
                    return null;
                }
                
                String vendor = propertyMap.get(ADDON_VENDOR);
                if (vendor == null) {
                    displayAddonManifestError(log, addon.getName(), ADDON_VENDOR);
                    return null;
                }

                String api = propertyMap.get(ADDON_API);
                PlatformTarget baseTarget = null;
                if (api == null) {
                    displayAddonManifestError(log, addon.getName(), ADDON_API);
                    return null;
                } else {
                    try {
                        int apiValue = Integer.parseInt(api);
                        for (IAndroidTarget target : list) {
                            if (target.isPlatform() &&
                                    target.getApiVersionNumber() == apiValue) {
                                baseTarget = (PlatformTarget)target;
                                break;
                            }
                        }
                        
                        if (baseTarget == null) {
                            if (log != null) {
                                log.error(null,
                                        "Ignoring add-on '%1$s': Unable to find base platform with API level %2$d",
                                        addon.getName(), apiValue);
                            }

                            return null;
                        }
                    } catch (NumberFormatException e) {
                        // looks like apiNumber does not parse to a number.
                        // Ignore this add-on.
                        if (log != null) {
                            log.error(null,
                                    "Ignoring add-on '%1$s': %2$s is not a valid number in %3$s.",
                                    addon.getName(), ADDON_API, SdkConstants.FN_BUILD_PROP);
                        }
                        return null;
                    }
                }
                
                // get the optional description
                String description = propertyMap.get(ADDON_DESCRIPTION);
                
                // 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 if (log != null) {
                                        log.error(null,
                                                "Ignoring library '%1$s', property value has wrong format\n\t%2$s",
                                                libName, libData);
                                    }
                                } else if (log != null) {
                                    log.error(null,
                                            "Ignoring library '%1$s', missing property value",
                                            libName, libData);
                                }
                            }
                        }
                    }
                }

                AddOnTarget target = new AddOnTarget(addon.getAbsolutePath(), name, vendor,
                        description, libMap, baseTarget);
                
                // 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[1];
                    } else {
                        defaultSkin = baseTarget.getDefaultSkin();
                    }
                }
                
                target.setSkins(skins, defaultSkin);

                return target;
            }
        } else if (log != null) {
            log.error(null, "Ignoring add-on '%1$s': %2$s is missing.", addon.getName(),
                    SdkConstants.FN_MANIFEST_INI);
        }
        
        return null;
    
private PlatformTargetloadPlatform(java.io.File platform, ISdkLog log)
Loads a specific Platform at a given location.

param
platform the location of the platform.
param
log the ISdkLog object receiving warning/error from the parsing.

        File buildProp = new File(platform, SdkConstants.FN_BUILD_PROP);
        
        if (buildProp.isFile()) {
            Map<String, String> map = parsePropertyFile(buildProp, log);
            
            if (map != null) {
                // look for some specific values in the map.
                try {
                    String apiNumber = map.get(PROP_VERSION_SDK);
                    String apiName = map.get(PROP_VERSION_RELEASE);
                    if (apiNumber != null && apiName != null) {
                        // api number and name looks valid, perform a few more checks
                        if (checkPlatformContent(platform, log) == false) {
                            return null;
                        }
                        // create the target.
                        PlatformTarget target = new PlatformTarget(
                                platform.getAbsolutePath(),
                                map,
                                Integer.parseInt(apiNumber),
                                apiName);
                        
                        // need to parse the skins.
                        String[] skins = parseSkinFolder(target.getPath(IAndroidTarget.SKINS));
                        target.setSkins(skins);

                        return target;
                    }
                } catch (NumberFormatException e) {
                    // looks like apiNumber does not parse to a number.
                    // Ignore this platform.
                    if (log != null) {
                        log.error(null,
                                "Ignoring platform '%1$s': %2$s is not a valid number in %3$s.",
                                platform.getName(), PROP_VERSION_SDK, SdkConstants.FN_BUILD_PROP);
                    }
                }
            }
        } else if (log != null) {
            log.error(null, "Ignoring platform '%1$s': %2$s is missing.", platform.getName(),
                    SdkConstants.FN_BUILD_PROP);
        }
        
        return null;
    
private voidloadPlatforms(java.util.ArrayList list, ISdkLog log)
Loads the Platforms from the SDK.

param
list the list to fill with the platforms.
param
log the ISdkLog object receiving warning/error from the parsing.

        File platformFolder = new File(mSdkLocation, SdkConstants.FD_PLATFORMS);
        if (platformFolder.isDirectory()) {
            File[] platforms  = platformFolder.listFiles();
            
            for (File platform : platforms) {
                if (platform.isDirectory()) {
                    PlatformTarget target = loadPlatform(platform, log);
                    if (target != null) {
                        list.add(target);
                    }
                } else if (log != null) {
                    log.warning("Ignoring platform '%1$s', not a folder.", platform.getName());
                }
            }
            
            return;
        }

        String message = null;
        if (platformFolder.exists() == false) {
            message = "%s is missing.";
        } else {
            message = "%s is not a folder.";
        }

        throw new IllegalArgumentException(String.format(message,
                platformFolder.getAbsolutePath()));
    
public static java.util.MapparsePropertyFile(java.io.File buildProp, ISdkLog log)
Parses a property file and returns

param
buildProp the property file to parse
param
log the ISdkLog object receiving warning/error from the parsing.
return
the map of (key,value) pairs, or null if the parsing failed.

        FileInputStream fis = null;
        BufferedReader reader = null;
        try {
            fis = new FileInputStream(buildProp);
            reader = new BufferedReader(new InputStreamReader(fis));

            String line = null;
            Map<String, String> map = new HashMap<String, String>();
            while ((line = reader.readLine()) != null) {
                if (line.length() > 0 && line.charAt(0) != '#") {
                    
                    Matcher m = PATTERN_PROP.matcher(line);
                    if (m.matches()) {
                        map.put(m.group(1), m.group(2));
                    } else {
                        log.warning("Error parsing '%1$s': \"%2$s\" is not a valid syntax",
                                buildProp.getAbsolutePath(), line);
                        return null;
                    }
                }
            }
            
            return map;
        } catch (FileNotFoundException e) {
            // this should not happen since we usually test the file existence before
            // calling the method.
            // Return null below.
        } catch (IOException e) {
            if (log != null) {
                log.warning("Error parsing '%1$s': %2$s.", buildProp.getAbsolutePath(),
                        e.getMessage());
            }
        } finally {
            if (reader != null) {
                try {
                    reader.close();
                } catch (IOException e) {
                    // pass
                }
            }
            if (fis != null) {
                try {
                    fis.close();
                } catch (IOException e) {
                    // pass
                }
            }
        }

        return null;
    
private java.lang.String[]parseSkinFolder(java.lang.String osPath)
Parses the skin folder and builds the skin list.

param
osPath The path of the skin root folder.

        File skinRootFolder = new File(osPath);

        if (skinRootFolder.isDirectory()) {
            ArrayList<String> skinList = new ArrayList<String>();

            File[] files = skinRootFolder.listFiles();

            for (File skinFolder : files) {
                if (skinFolder.isDirectory()) {
                    // check for layout file
                    File layout = new File(skinFolder, SdkConstants.FN_SKIN_LAYOUT);

                    if (layout.isFile()) {
                        // for now we don't parse the content of the layout and
                        // simply add the directory to the list.
                        skinList.add(skinFolder.getName());
                    }
                }
            }

            return skinList.toArray(new String[skinList.size()]);
        }
        
        return new String[0];
    
private voidsetTargets(IAndroidTarget[] targets)

        mTargets = targets;