diff options
Diffstat (limited to 'sdkmanager/libs/sdklib')
13 files changed, 1728 insertions, 0 deletions
diff --git a/sdkmanager/libs/sdklib/.classpath b/sdkmanager/libs/sdklib/.classpath new file mode 100644 index 0000000..fc17a43 --- /dev/null +++ b/sdkmanager/libs/sdklib/.classpath @@ -0,0 +1,7 @@ +<?xml version="1.0" encoding="UTF-8"?> +<classpath> + <classpathentry kind="src" path="src"/> + <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/> + <classpathentry combineaccessrules="false" kind="src" path="/AndroidPrefs"/> + <classpathentry kind="output" path="bin"/> +</classpath> diff --git a/sdkmanager/libs/sdklib/.project b/sdkmanager/libs/sdklib/.project new file mode 100644 index 0000000..97a8578 --- /dev/null +++ b/sdkmanager/libs/sdklib/.project @@ -0,0 +1,17 @@ +<?xml version="1.0" encoding="UTF-8"?> +<projectDescription> + <name>SdkLib</name> + <comment></comment> + <projects> + </projects> + <buildSpec> + <buildCommand> + <name>org.eclipse.jdt.core.javabuilder</name> + <arguments> + </arguments> + </buildCommand> + </buildSpec> + <natures> + <nature>org.eclipse.jdt.core.javanature</nature> + </natures> +</projectDescription> diff --git a/sdkmanager/libs/sdklib/Android.mk b/sdkmanager/libs/sdklib/Android.mk new file mode 100644 index 0000000..509c573 --- /dev/null +++ b/sdkmanager/libs/sdklib/Android.mk @@ -0,0 +1,17 @@ +# +# 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. +# +SDKLIB_LOCAL_DIR := $(call my-dir) +include $(SDKLIB_LOCAL_DIR)/src/Android.mk diff --git a/sdkmanager/libs/sdklib/src/Android.mk b/sdkmanager/libs/sdklib/src/Android.mk new file mode 100644 index 0000000..a059a46 --- /dev/null +++ b/sdkmanager/libs/sdklib/src/Android.mk @@ -0,0 +1,27 @@ +# +# 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. +# +LOCAL_PATH := $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_SRC_FILES := $(call all-subdir-java-files) + +LOCAL_JAVA_LIBRARIES := \ + androidprefs + +LOCAL_MODULE := sdklib + +include $(BUILD_HOST_JAVA_LIBRARY) + diff --git a/sdkmanager/libs/sdklib/src/com/android/sdklib/AddOnTarget.java b/sdkmanager/libs/sdklib/src/com/android/sdklib/AddOnTarget.java new file mode 100644 index 0000000..5759613 --- /dev/null +++ b/sdkmanager/libs/sdklib/src/com/android/sdklib/AddOnTarget.java @@ -0,0 +1,198 @@ +/* + * 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; + +import java.io.File; +import java.util.Map; +import java.util.Map.Entry; + +/** + * Represents an add-on target in the SDK. + * An add-on extends a standard {@link PlatformTarget}. + */ +final class AddOnTarget implements IAndroidTarget { + /** + * String to compute hash for add-on targets. + * Format is vendor:name:apiVersion + * */ + private final static String ADD_ON_FORMAT = "%s:%s:%d"; //$NON-NLS-1$ + + private final static class OptionalLibrary implements IOptionalLibrary { + private final String mJarName; + private final String mJarPath; + private final String mName; + + OptionalLibrary(String jarName, String jarPath, String name) { + mJarName = jarName; + mJarPath = jarPath; + mName = name; + } + + public String getJarName() { + return mJarName; + } + + public String getJarPath() { + return mJarPath; + } + + public String getName() { + return mName; + } + } + + private final String mLocation; + private final PlatformTarget mBasePlatform; + private final String mName; + private final String mVendor; + private final String mDescription; + private String[] mSkins; + private IOptionalLibrary[] mLibraries; + + /** + * Creates a new add-on + * @param location the OS path location of the add-on + * @param name the name of the add-on + * @param vendor the vendor name of the add-on + * @param description the add-on description + * @param libMap A map containing the optional libraries. The map key is the fully-qualified + * library name. The value is the .jar filename + * @param basePlatform the platform the add-on is extending. + */ + AddOnTarget(String location, String name, String vendor, String description, + Map<String, String> libMap, PlatformTarget basePlatform) { + if (location.endsWith(File.separator) == false) { + location = location + File.separator; + } + + mLocation = location; + mName = name; + mVendor = vendor; + mDescription = description; + mBasePlatform = basePlatform; + + // handle the optional libraries. + mLibraries = new IOptionalLibrary[libMap.size()]; + int index = 0; + for (Entry<String, String> entry : libMap.entrySet()) { + mLibraries[index++] = new OptionalLibrary(entry.getValue(), + mLocation + SdkConstants.OS_ADDON_LIBS_FOLDER + entry.getValue(), + entry.getKey()); + } + } + + public String getName() { + return mName; + } + + public String getVendor() { + return mVendor; + } + + public String getDescription() { + return mDescription; + } + + public String getApiVersionName() { + // this is always defined by the base platform + return mBasePlatform.getApiVersionName(); + } + + public int getApiVersionNumber() { + // this is always defined by the base platform + return mBasePlatform.getApiVersionNumber(); + } + + public boolean isPlatform() { + return false; + } + + public String getPath(int pathId) { + switch (pathId) { + case IMAGES: + return mLocation + SdkConstants.OS_IMAGES_FOLDER; + case SKINS: + return mLocation + SdkConstants.OS_SKINS_FOLDER; + default : + return mBasePlatform.getPath(pathId); + } + } + + public String[] getSkins() { + return mSkins; + } + + public IOptionalLibrary[] getOptionalLibraries() { + return mLibraries; + } + + public String hashString() { + return String.format(ADD_ON_FORMAT, mVendor, mName, mBasePlatform.getApiVersionNumber()); + } + + @Override + public int hashCode() { + return hashString().hashCode(); + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof AddOnTarget) { + AddOnTarget addon = (AddOnTarget)obj; + + return mVendor.equals(addon.mVendor) && mName.equals(addon.mName) && + mBasePlatform.getApiVersionNumber() == addon.mBasePlatform.getApiVersionNumber(); + } + + return super.equals(obj); + } + + /* + * Always return +1 if the object we compare to is a platform. + * Otherwise, do vendor then name then api version comparison. + * (non-Javadoc) + * @see java.lang.Comparable#compareTo(java.lang.Object) + */ + public int compareTo(IAndroidTarget target) { + if (target.isPlatform()) { + return +1; + } + + // vendor + int value = mVendor.compareTo(target.getVendor()); + + // name + if (value == 0) { + value = mName.compareTo(target.getName()); + } + + // api version + if (value == 0) { + value = getApiVersionNumber() - target.getApiVersionNumber(); + } + + return value; + } + + + // ---- local methods. + + + public void setSkins(String[] skins) { + mSkins = skins; + } +} diff --git a/sdkmanager/libs/sdklib/src/com/android/sdklib/IAndroidTarget.java b/sdkmanager/libs/sdklib/src/com/android/sdklib/IAndroidTarget.java new file mode 100644 index 0000000..e5d45b2 --- /dev/null +++ b/sdkmanager/libs/sdklib/src/com/android/sdklib/IAndroidTarget.java @@ -0,0 +1,104 @@ +/* + * 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; + + +/** + * A version of Android that application can target when building. + */ +public interface IAndroidTarget extends Comparable<IAndroidTarget> { + + public static int ANDROID_JAR = 1; + public static int ANDROID_AIDL = 2; + public static int IMAGES = 3; + public static int SAMPLES = 4; + public static int SKINS = 5; + public static int TEMPLATES = 6; + public static int DATA = 7; + public static int ATTRIBUTES = 8; + public static int MANIFEST_ATTRIBUTES = 9; + public static int LAYOUT_LIB = 10; + public static int RESOURCES = 11; + public static int FONTS = 12; + public static int WIDGETS = 13; + public static int ACTIONS_ACTIVITY = 14; + public static int ACTIONS_BROADCAST = 15; + public static int ACTIONS_SERVICE = 16; + public static int CATEGORIES = 17; + public static int SOURCES = 18; + + public interface IOptionalLibrary { + String getName(); + String getJarName(); + String getJarPath(); + } + + /** + * Returns the name of the vendor of the target. + */ + String getVendor(); + + /** + * Returns the name of the target. + */ + String getName(); + + /** + * Returns the description of the target. + */ + String getDescription(); + + /** + * Returns the api version as an integer. + */ + int getApiVersionNumber(); + + /** + * Returns the platform version as a readable string. + */ + String getApiVersionName(); + + /** + * Returns true if the target is a standard Android platform. + */ + boolean isPlatform(); + + /** + * Returns the path of a platform component. + * @param pathId the id representing the path to return. Any of the constants defined in the + * {@link ITargetDataProvider} interface can be used. + */ + String getPath(int pathId); + + /** + * Returns the available skins for this target. + */ + String[] getSkins(); + + /** + * Returns the available optional libraries for this target. + * @return an array of optional libraries or <code>null</code> if there is none. + */ + IOptionalLibrary[] getOptionalLibraries(); + + /** + * Returns a string able to uniquely identify a target. + * Typically the target will encode information such as api level, whether it's a platform + * or add-on, and if it's an add-on vendor and add-on name. + */ + String hashString(); +} diff --git a/sdkmanager/libs/sdklib/src/com/android/sdklib/ISdkLog.java b/sdkmanager/libs/sdklib/src/com/android/sdklib/ISdkLog.java new file mode 100644 index 0000000..3eda37f --- /dev/null +++ b/sdkmanager/libs/sdklib/src/com/android/sdklib/ISdkLog.java @@ -0,0 +1,25 @@ +/* + * 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; + +/** + * Interface used to display warnings/errors while parsing the SDK content. + */ +public interface ISdkLog { + void warning(String warningFormat, Object... args); + void error(String errorFormat, Object... args); +} diff --git a/sdkmanager/libs/sdklib/src/com/android/sdklib/PlatformTarget.java b/sdkmanager/libs/sdklib/src/com/android/sdklib/PlatformTarget.java new file mode 100644 index 0000000..f5a1f6d --- /dev/null +++ b/sdkmanager/libs/sdklib/src/com/android/sdklib/PlatformTarget.java @@ -0,0 +1,186 @@ +/* + * 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; + +import java.io.File; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +/** + * Represents a platform target in the SDK. + */ +final class PlatformTarget implements IAndroidTarget { + /** String used to get a hash to the platform target */ + private final static String PLATFORM_HASH = "android-%d"; + + private final static String PLATFORM_VENDOR = "Android"; + private final static String PLATFORM_NAME = "Android %s"; + + private final String mLocation; + private final String mName; + private final int mApiVersionNumber; + private final String mApiVersionName; + private final Map<String, String> mProperties; + private final Map<Integer, String> mPaths = new HashMap<Integer, String>(); + private String[] mSkins; + + PlatformTarget(String location, Map<String, String> properties, + int apiNumber, String apiName) { + mName = String.format(PLATFORM_NAME, apiName); + if (location.endsWith(File.separator) == false) { + location = location + File.separator; + } + mLocation = location; + mProperties = Collections.unmodifiableMap(properties); + mApiVersionNumber = apiNumber; + mApiVersionName = apiName; + + // pre-build the path to the platform components + mPaths.put(ANDROID_JAR, mLocation + SdkConstants.FN_FRAMEWORK_LIBRARY); + mPaths.put(SOURCES, mLocation + SdkConstants.FD_ANDROID_SOURCES); + mPaths.put(ANDROID_AIDL, mLocation + SdkConstants.FN_FRAMEWORK_AIDL); + mPaths.put(IMAGES, mLocation + SdkConstants.OS_IMAGES_FOLDER); + mPaths.put(SAMPLES, mLocation + SdkConstants.OS_PLATFORM_SAMPLES_FOLDER); + mPaths.put(SKINS, mLocation + SdkConstants.OS_SKINS_FOLDER); + mPaths.put(TEMPLATES, mLocation + SdkConstants.OS_PLATFORM_TEMPLATES_FOLDER); + mPaths.put(DATA, mLocation + SdkConstants.OS_PLATFORM_DATA_FOLDER); + mPaths.put(ATTRIBUTES, mLocation + SdkConstants.OS_PLATFORM_ATTRS_XML); + mPaths.put(MANIFEST_ATTRIBUTES, mLocation + SdkConstants.OS_PLATFORM_ATTRS_MANIFEST_XML); + mPaths.put(RESOURCES, mLocation + SdkConstants.OS_PLATFORM_RESOURCES_FOLDER); + mPaths.put(FONTS, mLocation + SdkConstants.OS_PLATFORM_FONTS_FOLDER); + mPaths.put(LAYOUT_LIB, mLocation + SdkConstants.OS_PLATFORM_DATA_FOLDER + + SdkConstants.FN_LAYOUTLIB_JAR); + mPaths.put(WIDGETS, mLocation + SdkConstants.OS_PLATFORM_DATA_FOLDER + + SdkConstants.FN_WIDGETS); + mPaths.put(ACTIONS_ACTIVITY, mLocation + SdkConstants.OS_PLATFORM_DATA_FOLDER + + SdkConstants.FN_INTENT_ACTIONS_ACTIVITY); + mPaths.put(ACTIONS_BROADCAST, mLocation + SdkConstants.OS_PLATFORM_DATA_FOLDER + + SdkConstants.FN_INTENT_ACTIONS_BROADCAST); + mPaths.put(ACTIONS_SERVICE, mLocation + SdkConstants.OS_PLATFORM_DATA_FOLDER + + SdkConstants.FN_INTENT_ACTIONS_SERVICE); + mPaths.put(CATEGORIES, mLocation + SdkConstants.OS_PLATFORM_DATA_FOLDER + + SdkConstants.FN_INTENT_CATEGORIES); + } + + public String getLocation() { + return mLocation; + } + + /* + * (non-Javadoc) + * + * For Platform, the vendor name is always "Android". + * + * @see com.android.sdklib.IAndroidTarget#getVendor() + */ + public String getVendor() { + return PLATFORM_VENDOR; + } + + public String getName() { + return mName; + } + + /* + * (non-Javadoc) + * + * Description for the Android platform is dynamically generated. + * + * @see com.android.sdklib.IAndroidTarget#getDescription() + */ + public String getDescription() { + return String.format("Standard Android platform %s", mApiVersionName); + } + + public int getApiVersionNumber(){ + return mApiVersionNumber; + } + + public String getApiVersionName() { + return mApiVersionName; + } + + public boolean isPlatform() { + return true; + } + + public String getPath(int pathId) { + return mPaths.get(pathId); + } + + public String[] getSkins() { + return mSkins; + } + + /* + * Always returns null, as a standard platforms have no optional libraries. + * + * (non-Javadoc) + * @see com.android.sdklib.IAndroidTarget#getOptionalLibraries() + */ + public IOptionalLibrary[] getOptionalLibraries() { + return null; + } + + + public String hashString() { + return String.format(PLATFORM_HASH, mApiVersionNumber); + } + + @Override + public int hashCode() { + return hashString().hashCode(); + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof PlatformTarget) { + return mApiVersionNumber == ((PlatformTarget)obj).mApiVersionNumber; + } + + return super.equals(obj); + } + + /* + * Always return -1 if the object we compare to is an addon. + * Otherwise, compare api level. + * (non-Javadoc) + * @see java.lang.Comparable#compareTo(java.lang.Object) + */ + public int compareTo(IAndroidTarget target) { + if (target.isPlatform() == false) { + return -1; + } + + return mApiVersionNumber - target.getApiVersionNumber(); + } + + // ---- platform only methods. + + public String getProperty(String name) { + return mProperties.get(name); + } + + public Map<String, String> getProperties() { + return mProperties; // mProperties is unmodifiable. + } + + void setSkins(String[] skins) { + mSkins = skins; + } +} diff --git a/sdkmanager/libs/sdklib/src/com/android/sdklib/SdkConstants.java b/sdkmanager/libs/sdklib/src/com/android/sdklib/SdkConstants.java new file mode 100644 index 0000000..78d1fda --- /dev/null +++ b/sdkmanager/libs/sdklib/src/com/android/sdklib/SdkConstants.java @@ -0,0 +1,174 @@ +/* + * Copyright (C) 2007 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; + +import java.io.File; + +/** + * Constant definition class.<br> + * <br> + * Most constants have a prefix defining the content. + * <ul> + * <li><code>OS_</code> OS path constant. These paths are different depending on the platform.</li> + * <li><code>FN_</code> File name constant.</li> + * <li><code>FD_</code> Folder name constant.</li> + * </ul> + * + */ +public final class SdkConstants { + + /** Name of the framework library, i.e. "android.jar" */ + public static final String FN_FRAMEWORK_LIBRARY = "android.jar"; + /** Name of the layout attributes, i.e. "attrs.xml" */ + public static final String FN_ATTRS_XML = "attrs.xml"; + /** Name of the layout attributes, i.e. "attrs_manifest.xml" */ + public static final String FN_ATTRS_MANIFEST_XML = "attrs_manifest.xml"; + /** framework aidl import file */ + public static final String FN_FRAMEWORK_AIDL = "framework.aidl"; + /** layoutlib.jar file */ + public static final String FN_LAYOUTLIB_JAR = "layoutlib.jar"; + /** widget list file */ + public static final String FN_WIDGETS = "widgets.txt"; + /** Intent activity actions list file */ + public static final String FN_INTENT_ACTIONS_ACTIVITY = "activity_actions.txt"; + /** Intent broadcast actions list file */ + public static final String FN_INTENT_ACTIONS_BROADCAST = "broadcast_actions.txt"; + /** Intent service actions list file */ + public static final String FN_INTENT_ACTIONS_SERVICE = "service_actions.txt"; + /** Intent category list file */ + public static final String FN_INTENT_CATEGORIES = "categories.txt"; + + /** platform build property file */ + public final static String FN_BUILD_PROP = "build.prop"; + /** plugin properties file */ + public final static String FN_PLUGIN_PROP = "plugin.prop"; + /** add-on manifest file */ + public final static String FN_MANIFEST_INI = "manifest.ini"; + /** hardware properties definition file */ + public final static String FN_HARDWARE_INI = "hardware-properties.ini"; + + /** Skin layout file */ + public final static String FN_SKIN_LAYOUT = "layout";//$NON-NLS-1$ + + /* Folder Names for the Android SDK */ + + /** Name of the SDK platforms folder. */ + public final static String FD_PLATFORMS = "platforms"; + /** Name of the SDK addons folder. */ + public final static String FD_ADDONS = "add-ons"; + /** Name of the SDK tools folder. */ + public final static String FD_TOOLS = "tools"; + /** Name of the SDK tools/lib folder. */ + public final static String FD_LIB = "lib"; + /** Name of the SDK docs folder. */ + public final static String FD_DOCS = "docs"; + /** Name of the SDK images folder. */ + public final static String FD_IMAGES = "images"; + /** Name of the SDK skins folder. */ + public final static String FD_SKINS = "skins"; + /** Name of the SDK samples folder. */ + public final static String FD_SAMPLES = "samples"; + /** Name of the SDK templates folder, i.e. "templates" */ + public final static String FD_TEMPLATES = "templates"; + /** Name of the SDK data folder, i.e. "data" */ + public final static String FD_DATA = "data"; + /** Name of the SDK resources folder, i.e. "res" */ + public final static String FD_RES = "res"; + /** Name of the SDK font folder, i.e. "fonts" */ + public final static String FD_FONTS = "fonts"; + /** Default values resource folder name, i.e. "values" */ + public final static String FD_VALUES = "values"; + /** Name of the android sources directory */ + public static final String FD_ANDROID_SOURCES = "sources"; + /** Name of the addon libs folder. */ + public final static String FD_ADDON_LIBS = "libs"; + + /* Folder path relative to the SDK root */ + /** Path of the documentation directory relative to the sdk folder. + * This is an OS path, ending with a separator. */ + public final static String OS_SDK_DOCS_FOLDER = FD_DOCS + File.separator; + + /** Path of the tools directory relative to the sdk folder. + * This is an OS path, ending with a separator. */ + public final static String OS_SDK_TOOLS_FOLDER = FD_TOOLS + File.separator; + + /** Path of the lib directory relative to the sdk folder. + * This is an OS path, ending with a separator. */ + public final static String OS_SDK_TOOLS_LIB_FOLDER = + OS_SDK_TOOLS_FOLDER + FD_LIB + File.separator; + + /* Folder paths relative to a platform or add-on folder */ + + /** Path of the images directory relative to a platform or addon folder. + * This is an OS path, ending with a separator. */ + public final static String OS_IMAGES_FOLDER = FD_IMAGES + File.separator; + + /** Path of the skin directory relative to a platform or addon folder. + * This is an OS path, ending with a separator. */ + public final static String OS_SKINS_FOLDER = FD_SKINS + File.separator; + + /* Folder paths relative to a Platform folder */ + + /** Path of the data directory relative to a platform folder. + * This is an OS path, ending with a separator. */ + public final static String OS_PLATFORM_DATA_FOLDER = FD_DATA + File.separator; + + /** Path of the samples directory relative to a platform folder. + * This is an OS path, ending with a separator. */ + public final static String OS_PLATFORM_SAMPLES_FOLDER = FD_SAMPLES + File.separator; + + /** Path of the resources directory relative to a platform folder. + * This is an OS path, ending with a separator. */ + public final static String OS_PLATFORM_RESOURCES_FOLDER = + OS_PLATFORM_DATA_FOLDER + FD_RES + File.separator; + + /** Path of the fonts directory relative to a platform folder. + * This is an OS path, ending with a separator. */ + public final static String OS_PLATFORM_FONTS_FOLDER = + OS_PLATFORM_DATA_FOLDER + FD_FONTS + File.separator; + + /** Path of the android source directory relative to a platform folder. + * This is an OS path, ending with a separator. */ + public final static String OS_PLATFORM_SOURCES_FOLDER = FD_ANDROID_SOURCES + File.separator; + + /** Path of the android templates directory relative to a platform folder. + * This is an OS path, ending with a separator. */ + public final static String OS_PLATFORM_TEMPLATES_FOLDER = FD_TEMPLATES + File.separator; + + /** 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; + + /** 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; + + /** Path of the layoutlib.jar file relative to a platform folder. */ + public final static String OS_PLATFORM_LAYOUTLIB_JAR = + OS_PLATFORM_DATA_FOLDER + FN_LAYOUTLIB_JAR; + + /* Folder paths relative to a addon folder */ + + /** Path of the images directory relative to a folder folder. + * This is an OS path, ending with a separator. */ + public final static String OS_ADDON_LIBS_FOLDER = FD_ADDON_LIBS + File.separator; + + + /* Skin default */ + public final static String SKIN_DEFAULT = "default"; + +} diff --git a/sdkmanager/libs/sdklib/src/com/android/sdklib/SdkManager.java b/sdkmanager/libs/sdklib/src/com/android/sdklib/SdkManager.java new file mode 100644 index 0000000..67b8499 --- /dev/null +++ b/sdkmanager/libs/sdklib/src/com/android/sdklib/SdkManager.java @@ -0,0 +1,420 @@ +/* + * 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; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStreamReader; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * The SDK manager parses the SDK folder and gives access to the content. + * @see PlatformTarget + * @see AddOnTarget + */ +public final class SdkManager { + + private final static String PROP_VERSION_SDK = "ro.build.version.sdk"; + private final static String PROP_VERSION_RELEASE = "ro.build.version.release"; + + 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 Pattern PATTERN_PROP = Pattern.compile( + "^([a-zA-Z0-9._-]+)\\s*=\\s*(.*)\\s*$"); + + /** the location of the SDK */ + private final String mSdkLocation; + private IAndroidTarget[] mTargets; + + /** + * 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. + */ + public static SdkManager createManager(String sdkLocation, ISdkLog log) { + 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.getMessage()); + } + } + + return null; + } + + /** + * Returns the location of the SDK. + */ + public String getLocation() { + return mSdkLocation; + } + + /** + * Returns the targets that are available in the SDK. + */ + public IAndroidTarget[] getTargets() { + return mTargets; + } + + /** + * Returns a target from a hash that was generated by {@link IAndroidTarget#hashString()}. + * @param hash the hash + */ + public IAndroidTarget getTargetFromHashString(String hash) { + if (hash != null) { + for (IAndroidTarget target : mTargets) { + if (hash.equals(target.hashString())) { + return target; + } + } + } + + return null; + } + + + private SdkManager(String sdkLocation) { + mSdkLocation = sdkLocation; + } + + private void setTargets(IAndroidTarget[] targets) { + mTargets = targets; + } + + /** + * 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. + */ + private void loadPlatforms(ArrayList<IAndroidTarget> list, ISdkLog log) { + 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())); + } + + /** + * 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. + */ + private PlatformTarget loadPlatform(File platform, ISdkLog log) { + 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) { + // 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("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("Ignoring platform '%1$s': %2$s is missing.", platform.getName(), + SdkConstants.FN_BUILD_PROP); + } + + return null; + } + + /** + * 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. + */ + private void loadAddOns(ArrayList<IAndroidTarget> list, ISdkLog log) { + File addonFolder = new File(mSdkLocation, SdkConstants.FD_ADDONS); + if (addonFolder.isDirectory()) { + File[] addons = addonFolder.listFiles(); + + for (File addon : addons) { + if (addon.isDirectory()) { + AddOnTarget target = loadAddon(addon, list, log); + if (target != null) { + list.add(target); + } + } else if (log != null) { + log.warning("Ignoring add-on '%1$s', not a folder.", addon.getName()); + } + } + + 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())); + } + + /** + * Loads a specific Add-on at a given location. + * @param addon the location of the addon. + * @param list + * @param log + */ + private AddOnTarget loadAddon(File addon, ArrayList<IAndroidTarget> list, ISdkLog log) { + File addOnManifest = new File(addon, SdkConstants.FN_MANIFEST_INI); + + if (addOnManifest.isFile()) { + Map<String, String> map = parsePropertyFile(addOnManifest, log); + + if (map != null) { + // look for some specific values in the map. + // we require name, vendor, and api + String name = map.get(ADDON_NAME); + if (name == null) { + displayAddonManifestError(log, addon.getName(), ADDON_NAME); + return null; + } + + String vendor = map.get(ADDON_VENDOR); + if (vendor == null) { + displayAddonManifestError(log, addon.getName(), ADDON_VENDOR); + return null; + } + + String api = map.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( + "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( + "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 = map.get(ADDON_DESCRIPTION); + + // get the optional libraries + String librariesValue = map.get(ADDON_LIBRARIES); + + // split in the string into the values we care about + String[] libraries = librariesValue.split(";"); + Map<String, String> libMap = null; + if (libraries.length > 0) { + libMap = new HashMap<String, String>(); + for (String lib : libraries) { + String[] values = lib.split(":"); + if (values.length == 2) { + libMap.put(values[0], values[1]); + } else { + // TODO: log error + } + } + } + + AddOnTarget target = new AddOnTarget(addon.getAbsolutePath(), name, vendor, + description, libMap, baseTarget); + + // need to parse the skins. + String[] skins = parseSkinFolder(target.getPath(IAndroidTarget.SKINS)); + target.setSkins(skins); + + return target; + } + } else if (log != null) { + log.error("Ignoring add-on '%1$s': %2$s is missing.", addon.getName(), + SdkConstants.FN_MANIFEST_INI); + } + + return null; + } + + private void displayAddonManifestError(ISdkLog log, String addonName, String valueName) { + if (log != null) { + log.error("Ignoring add-on '%1$s': '%2$s' is missing from %3$s.", + addonName, valueName, SdkConstants.FN_MANIFEST_INI); + } + } + + /** + * 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. + */ + public static Map<String, String> parsePropertyFile(File buildProp, ISdkLog log) { + try { + FileInputStream fis = new FileInputStream(buildProp); + BufferedReader 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()); + } + } + + return null; + } + + /** + * Parses the skin folder and builds the skin list. + * @param osPath The path of the skin root folder. + */ + private String[] parseSkinFolder(String osPath) { + 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]; + } +} diff --git a/sdkmanager/libs/sdklib/src/com/android/sdklib/project/ProjectProperties.java b/sdkmanager/libs/sdklib/src/com/android/sdklib/project/ProjectProperties.java new file mode 100644 index 0000000..c0c1fe3 --- /dev/null +++ b/sdkmanager/libs/sdklib/src/com/android/sdklib/project/ProjectProperties.java @@ -0,0 +1,136 @@ +/* + * 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.project; + +import com.android.sdklib.SdkManager; + +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; +import java.util.Map.Entry; + +/** + * Class to load and save project properties for both ADT and Ant-based build. + * + */ +public final class ProjectProperties { + /** The property name for the project target */ + public final static String PROPERTY_TARGET = "target"; + public final static String PROPERTY_SDK = "sdk-folder"; + + private final static String PROPERTIES_FILE = "default.properties"; + + private final static String PROP_HEADER = + "# This file is automatically generated by Android Tools.\n" + + "# Do not modify this file -- YOUR CHANGES WILL BE ERASED!\n" + + "# For customized properties when using Ant, set new values\n" + + "# in a \"build.properties\" file.\n\n"; + + private final static Map<String, String> COMMENT_MAP = new HashMap<String, String>(); + static { + COMMENT_MAP.put(PROPERTY_TARGET, "# Project target.\n"); + COMMENT_MAP.put(PROPERTY_SDK, "# location of the SDK. Only used by Ant.\n"); + } + + private final String mProjectFolderOsPath; + private final Map<String, String> mProperties; + + /** + * Loads a project properties file and return a {@link ProjectProperties} object + * containing the properties + * @param projectFolderOsPath the project folder. + */ + public static ProjectProperties load(String projectFolderOsPath) { + File projectFolder = new File(projectFolderOsPath); + if (projectFolder.isDirectory()) { + File defaultFile = new File(projectFolder, PROPERTIES_FILE); + if (defaultFile.isFile()) { + Map<String, String> map = SdkManager.parsePropertyFile(defaultFile, null /* log */); + if (map != null) { + return new ProjectProperties(projectFolderOsPath, map); + } + } + } + return null; + } + + /** + * Creates a new project properties file, with no properties. + * <p/>The file is not created until {@link #save()} is called. + * @param projectFolderOsPath the project folder. + */ + public static ProjectProperties create(String projectFolderOsPath) { + // create and return a ProjectProperties with an empty map. + return new ProjectProperties(projectFolderOsPath, new HashMap<String, String>()); + } + + /** + * Sets a new properties. If a property with the same name already exists, it is replaced. + * @param name the name of the property. + * @param value the value of the property. + */ + public void setProperty(String name, String value) { + mProperties.put(name, value); + } + + /** + * Returns the value of a property. + * @param name the name of the property. + * @return the property value or null if the property is not set. + */ + public String getProperty(String name) { + return mProperties.get(name); + } + + /** + * Saves the property file. + * @throws IOException + */ + public void save() throws IOException { + File toSave = new File(mProjectFolderOsPath, PROPERTIES_FILE); + + FileWriter writer = new FileWriter(toSave); + + // write the header + writer.write(PROP_HEADER); + + // write the properties. + for (Entry<String, String> entry : mProperties.entrySet()) { + String comment = COMMENT_MAP.get(entry.getKey()); + if (comment != null) { + writer.write(comment); + } + writer.write(String.format("%s=%s\n", entry.getKey(), entry.getValue())); + } + + // close the file to flush + writer.close(); + } + + /** + * Private constructor. + * Use {@link #load(String)} or {@link #create(String)} to instantiate. + * @param projectFolderOsPath + * @param map + */ + private ProjectProperties(String projectFolderOsPath, Map<String, String> map) { + mProjectFolderOsPath = projectFolderOsPath; + mProperties = map; + } +} diff --git a/sdkmanager/libs/sdklib/src/com/android/sdklib/vm/HardwareProperties.java b/sdkmanager/libs/sdklib/src/com/android/sdklib/vm/HardwareProperties.java new file mode 100644 index 0000000..cb2c8c2 --- /dev/null +++ b/sdkmanager/libs/sdklib/src/com/android/sdklib/vm/HardwareProperties.java @@ -0,0 +1,159 @@ +/* + * 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.vm; + +import com.android.sdklib.ISdkLog; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStreamReader; +import java.util.ArrayList; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class HardwareProperties { + private final static Pattern PATTERN_PROP = Pattern.compile( + "^([a-zA-Z0-9._-]+)\\s*=\\s*(.*)\\s*$"); + + private final static String HW_PROP_NAME = "name"; + private final static String HW_PROP_TYPE = "type"; + private final static String HW_PROP_DEFAULT = "default"; + private final static String HW_PROP_ABSTRACT = "abstract"; + private final static String HW_PROP_DESC = "description"; + + public enum ValueType { + INTEGER("integer"), + BOOLEAN("boolean"), + DISKSIZE("diskSize"); + + private String mValue; + + ValueType(String value) { + mValue = value; + } + + public static ValueType getEnum(String value) { + for (ValueType type : values()) { + if (type.mValue.equals(value)) { + return type; + } + } + + return null; + } + } + + public static final class HardwareProperty { + private String mName; + private ValueType mType; + /** the string representation of the default value. can be null. */ + private String mDefault; + private String mAbstract; + private String mDescription; + + public String getName() { + return mName; + } + + public ValueType getType() { + return mType; + } + + public String getDefault() { + return mDefault; + } + + public String getAbstract() { + return mAbstract; + } + + public String getDescription() { + return mDescription; + } + } + + /** + * Parses the harware definition file. + * @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. + */ + public static List<HardwareProperty> parseHardwareDefinitions(File file, ISdkLog log) { + try { + FileInputStream fis = new FileInputStream(file); + BufferedReader reader = new BufferedReader(new InputStreamReader(fis)); + + List<HardwareProperty> map = new ArrayList<HardwareProperty>(); + + String line = null; + HardwareProperty prop = null; + while ((line = reader.readLine()) != null) { + if (line.length() > 0 && line.charAt(0) != '#') { + Matcher m = PATTERN_PROP.matcher(line); + if (m.matches()) { + String valueName = m.group(1); + String value = m.group(2); + + if (HW_PROP_NAME.equals(valueName)) { + prop = new HardwareProperty(); + prop.mName = value; + map.add(prop); + } + + if (prop == null) { + log.warning("Error parsing '%1$s': missing '%2$s'", + file.getAbsolutePath(), HW_PROP_NAME); + return null; + } + + if (HW_PROP_TYPE.equals(valueName)) { + prop.mType = ValueType.getEnum(value); + } else if (HW_PROP_DEFAULT.equals(valueName)) { + prop.mDefault = value; + } else if (HW_PROP_ABSTRACT.equals(valueName)) { + prop.mAbstract = value; + } else if (HW_PROP_DESC.equals(valueName)) { + prop.mDescription = value; + } + } else { + log.warning("Error parsing '%1$s': \"%2$s\" is not a valid syntax", + file.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.", file.getAbsolutePath(), + e.getMessage()); + } + } + + return null; + } + +} diff --git a/sdkmanager/libs/sdklib/src/com/android/sdklib/vm/VmManager.java b/sdkmanager/libs/sdklib/src/com/android/sdklib/vm/VmManager.java new file mode 100644 index 0000000..a9f1b17 --- /dev/null +++ b/sdkmanager/libs/sdklib/src/com/android/sdklib/vm/VmManager.java @@ -0,0 +1,258 @@ +/* + * 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.vm; + +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 java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.FileWriter; +import java.io.FilenameFilter; +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; +import java.util.Map.Entry; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * Virtual Machine manager to access the list of VMs or create new ones. + */ +public final class VmManager { + + private final static String VM_INFO_PATH = "path"; + private final static String VM_INFO_TARGET = "target"; + + private final static String IMAGE_USERDATA = "userdata.img"; + private final static String CONFIG_INI = "config.ini"; + + private final static Pattern INI_NAME_PATTERN = Pattern.compile("(.+)\\.ini$", + Pattern.CASE_INSENSITIVE); + + public static final class VmInfo { + String name; + String path; + IAndroidTarget target; + + public String getName() { + return name; + } + + public String getPath() { + return path; + } + + public IAndroidTarget getTarget() { + return target; + } + } + + private final ArrayList<VmInfo> mVmList = new ArrayList<VmInfo>(); + private ISdkLog mSdkLog; + + public VmManager(SdkManager sdk, ISdkLog sdkLog) throws AndroidLocationException { + mSdkLog = sdkLog; + buildVmList(sdk); + } + + public VmInfo[] getVms() { + return mVmList.toArray(new VmInfo[mVmList.size()]); + } + + /** + * Creates a new VM. + * @param parentFolder the folder to contain the VM. A new folder will be created in this + * folder with the name of the VM + * @param name the name of the VM + * @param target the target of the VM + * @param skinName the name of the skin. Can be null. + * @param sdcardPath the path to the sdCard. Can be null. + * @param sdcardSize the size of a local sdcard to create. Can be 0 for no local sdcard. + * @param hardwareConfig the hardware setup for the VM + */ + public static void createVm(String parentFolder, String name, IAndroidTarget target, + String skinName, String sdcardPath, int sdcardSize, Map<String,String> hardwareConfig, + ISdkLog log) { + + // now write the ini file in the vmRoot folder. + // get the Android prefs location. + try { + File rootDirectory = new File(parentFolder); + if (rootDirectory.isDirectory() == false) { + if (log != null) { + log.error("%s does not exists.", parentFolder); + } + return; + } + + File vmFolder = new File(parentFolder, name + ".avm"); + if (vmFolder.exists()) { + if (log != null) { + log.error("%s already exists.", vmFolder.getAbsolutePath()); + } + return; + } + + // create the vm folder. + vmFolder.mkdir(); + + HashMap<String, String> values = new HashMap<String, String>(); + + // prepare the ini file. + String vmRoot = AndroidLocation.getFolder() + AndroidLocation.FOLDER_VMS; + File iniFile = new File(vmRoot, name + ".ini"); + values.put(VM_INFO_PATH, vmFolder.getAbsolutePath()); + values.put(VM_INFO_TARGET, target.hashString()); + createConfigIni(iniFile, values); + + // writes the userdata.img in it. + String imagePath = target.getPath(IAndroidTarget.IMAGES); + File userdataSrc = new File(imagePath, IMAGE_USERDATA); + FileInputStream fis = new FileInputStream(userdataSrc); + + File userdataDest = new File(vmFolder, IMAGE_USERDATA); + FileOutputStream fos = new FileOutputStream(userdataDest); + + byte[] buffer = new byte[4096]; + int count; + while ((count = fis.read(buffer)) != -1) { + fos.write(buffer, 0, count); + } + + fos.close(); + fis.close(); + + // Config file + values.clear(); + if (skinName != null) { + values.put("skin", skinName); + } else { + values.put("skin", SdkConstants.SKIN_DEFAULT); + } + + if (sdcardPath != null) { + values.put("sdcard", sdcardPath); + } else if (sdcardSize != 0) { + // TODO: create sdcard image. + } + + if (hardwareConfig != null) { + values.putAll(hardwareConfig); + } + + File configIniFile = new File(vmFolder, CONFIG_INI); + createConfigIni(configIniFile, values); + + if (target.isPlatform()) { + System.out.println(String.format( + "Created VM '%s' based on %s", name, target.getName())); + } else { + System.out.println(String.format( + "Created VM '%s' based on %s (%s)", name, target.getName(), + target.getVendor())); + } + } catch (AndroidLocationException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + + private void buildVmList(SdkManager sdk) throws AndroidLocationException { + // get the Android prefs location. + String vmRoot = AndroidLocation.getFolder() + AndroidLocation.FOLDER_VMS; + + // ensure folder validity. + File folder = new File(vmRoot); + if (folder.isFile()) { + throw new AndroidLocationException(String.format("%s is not a valid folder.", vmRoot)); + } else if (folder.exists() == false) { + // folder is not there, we create it and return + folder.mkdirs(); + return; + } + + File[] vms = folder.listFiles(new FilenameFilter() { + public boolean accept(File parent, String name) { + if (INI_NAME_PATTERN.matcher(name).matches()) { + // check it's a file and not a folder + return new File(parent, name).isFile(); + } + + return false; + } + }); + + for (File vm : vms) { + VmInfo info = parseVmInfo(vm, sdk); + if (info != null) { + mVmList.add(info); + } + } + } + + private VmInfo parseVmInfo(File path, SdkManager sdk) { + Map<String, String> map = SdkManager.parsePropertyFile(path, mSdkLog); + + String vmPath = map.get(VM_INFO_PATH); + if (vmPath == null) { + return null; + } + + String targetHash = map.get(VM_INFO_TARGET); + if (targetHash == null) { + return null; + } + + IAndroidTarget target = sdk.getTargetFromHashString(targetHash); + if (target == null) { + return null; + } + + VmInfo info = new VmInfo(); + Matcher matcher = INI_NAME_PATTERN.matcher(path.getName()); + if (matcher.matches()) { + info.name = matcher.group(1); + } else { + info.name = path.getName(); // really this should not happen. + } + info.path = vmPath; + info.target = target; + + return info; + } + + private static void createConfigIni(File iniFile, Map<String, String> values) + throws IOException { + FileWriter writer = new FileWriter(iniFile); + + for (Entry<String, String> entry : values.entrySet()) { + writer.write(String.format("%s=%s\n", entry.getKey(), entry.getValue())); + } + writer.close(); + + } +} |