aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--anttasks/src/com/android/ant/AndroidInitTask.java18
-rw-r--r--ddms/libs/ddmlib/src/com/android/ddmlib/EmulatorConsole.java2
-rw-r--r--ddms/libs/ddmuilib/src/com/android/ddmuilib/DevicePanel.java4
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/AdtPlugin.java36
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/build/ApkBuilder.java154
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/build/ApkDeltaVisitor.java7
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/build/DexWrapper.java92
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/build/PreCompilerBuilder.java14
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/debug/launching/AndroidLaunchController.java18
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/debug/launching/DeviceChooserDialog.java4
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/project/internal/AndroidClasspathContainerInitializer.java8
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/sdk/AndroidTargetData.java35
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/sdk/AndroidTargetParser.java23
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/sdk/Sdk.java187
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/common/AndroidConstants.java56
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/IconFactory.java4
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/explorer/ResourceExplorerView.java7
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/manager/ResourceMonitor.java45
-rw-r--r--eclipse/scripts/collect_sources_for_sdk.sh58
-rw-r--r--scripts/android_rules.xml17
-rw-r--r--sdkmanager/app/src/com/android/sdkmanager/Main.java25
-rw-r--r--sdkmanager/libs/sdklib/src/com/android/sdklib/AddOnTarget.java13
-rw-r--r--sdkmanager/libs/sdklib/src/com/android/sdklib/IAndroidTarget.java19
-rw-r--r--sdkmanager/libs/sdklib/src/com/android/sdklib/PlatformTarget.java16
-rw-r--r--sdkmanager/libs/sdklib/src/com/android/sdklib/SdkConstants.java48
-rw-r--r--sdkmanager/libs/sdklib/src/com/android/sdklib/SdkManager.java51
-rw-r--r--sdkmanager/libs/sdklib/src/com/android/sdklib/avd/AvdManager.java227
-rw-r--r--sdkmanager/libs/sdklib/src/com/android/sdklib/project/ProjectProperties.java9
28 files changed, 909 insertions, 288 deletions
diff --git a/anttasks/src/com/android/ant/AndroidInitTask.java b/anttasks/src/com/android/ant/AndroidInitTask.java
index 30779c5..d5bc55b 100644
--- a/anttasks/src/com/android/ant/AndroidInitTask.java
+++ b/anttasks/src/com/android/ant/AndroidInitTask.java
@@ -55,6 +55,12 @@ public class AndroidInitTask extends ImportTask {
private final static String PROPERTY_ANDROID_JAR = "android-jar";
// ant property with the path to the framework.jar
private final static String PROPERTY_ANDROID_AIDL = "android-aidl";
+ // ant property with the path to the aapt tool
+ private final static String PROPERTY_AAPT = "aapt";
+ // ant property with the path to the aidl tool
+ private final static String PROPERTY_AIDL = "aidl";
+ // ant property with the path to the dx tool
+ private final static String PROPERTY_DX = "dx";
// ref id to the <path> object containing all the boot classpaths.
private final static String REF_CLASSPATH = "android.target.classpath";
@@ -122,15 +128,19 @@ public class AndroidInitTask extends ImportTask {
System.out.println("Project Target: " + androidTarget.getName());
if (androidTarget.isPlatform() == false) {
System.out.println("Vendor: " + androidTarget.getVendor());
+ System.out.println("Platform Version: " + androidTarget.getApiVersionName());
}
- System.out.println("Platform Version: " + androidTarget.getApiVersionName());
System.out.println("API level: " + androidTarget.getApiVersionNumber());
- // sets up the properties to find android.jar/framework.aidl
+ // sets up the properties to find android.jar/framework.aidl/target tools
String androidJar = androidTarget.getPath(IAndroidTarget.ANDROID_JAR);
- String androidAidl = androidTarget.getPath(IAndroidTarget.ANDROID_AIDL);
antProject.setProperty(PROPERTY_ANDROID_JAR, androidJar);
- antProject.setProperty(PROPERTY_ANDROID_AIDL, androidAidl);
+
+ antProject.setProperty(PROPERTY_ANDROID_AIDL,
+ androidTarget.getPath(IAndroidTarget.ANDROID_AIDL));
+ antProject.setProperty(PROPERTY_AAPT, androidTarget.getPath(IAndroidTarget.AAPT));
+ antProject.setProperty(PROPERTY_AIDL, androidTarget.getPath(IAndroidTarget.AIDL));
+ antProject.setProperty(PROPERTY_DX, androidTarget.getPath(IAndroidTarget.DX));
// sets up the boot classpath
diff --git a/ddms/libs/ddmlib/src/com/android/ddmlib/EmulatorConsole.java b/ddms/libs/ddmlib/src/com/android/ddmlib/EmulatorConsole.java
index 74c432d..f3986ed 100644
--- a/ddms/libs/ddmlib/src/com/android/ddmlib/EmulatorConsole.java
+++ b/ddms/libs/ddmlib/src/com/android/ddmlib/EmulatorConsole.java
@@ -54,7 +54,7 @@ public final class EmulatorConsole {
private final static String HOST = "127.0.0.1"; //$NON-NLS-1$
private final static String COMMAND_PING = "help\r\n"; //$NON-NLS-1$
- private final static String COMMAND_AVD_NAME = "vm name\r\n"; //$NON-NLS-1$ // TODO change with emulator
+ private final static String COMMAND_AVD_NAME = "avd name\r\n"; //$NON-NLS-1$
private final static String COMMAND_KILL = "kill\r\n"; //$NON-NLS-1$
private final static String COMMAND_GSM_STATUS = "gsm status\r\n"; //$NON-NLS-1$
private final static String COMMAND_GSM_CALL = "gsm call %1$s\r\n"; //$NON-NLS-1$
diff --git a/ddms/libs/ddmuilib/src/com/android/ddmuilib/DevicePanel.java b/ddms/libs/ddmuilib/src/com/android/ddmuilib/DevicePanel.java
index d168476..81b757e 100644
--- a/ddms/libs/ddmuilib/src/com/android/ddmuilib/DevicePanel.java
+++ b/ddms/libs/ddmuilib/src/com/android/ddmuilib/DevicePanel.java
@@ -205,6 +205,10 @@ public final class DevicePanel extends Panel implements IDebugBridgeChangeListen
String debuggable = device.getProperty(Device.PROP_DEBUGGABLE);
if (device.isEmulator()) {
String avdName = device.getAvdName();
+ if (avdName == null) {
+ avdName = "?"; // the device is probably not online yet, so
+ // we don't know its AVD name just yet.
+ }
if (debuggable != null && debuggable.equals("1")) { //$NON-NLS-1$
return String.format("%1$s [%2$s, debug]", avdName,
version);
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/AdtPlugin.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/AdtPlugin.java
index ddc93ac..9aa9354 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/AdtPlugin.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/AdtPlugin.java
@@ -20,7 +20,6 @@ import com.android.ddmuilib.StackTracePanel;
import com.android.ddmuilib.StackTracePanel.ISourceRevealer;
import com.android.ddmuilib.console.DdmConsole;
import com.android.ddmuilib.console.IDdmConsole;
-import com.android.ide.eclipse.adt.build.DexWrapper;
import com.android.ide.eclipse.adt.debug.launching.AndroidLaunchController;
import com.android.ide.eclipse.adt.preferences.BuildPreferencePage;
import com.android.ide.eclipse.adt.project.ProjectHelper;
@@ -423,8 +422,6 @@ public class AdtPlugin extends AbstractUIPlugin {
stopEditors();
- DexWrapper.unloadDex();
-
mRed.dispose();
synchronized (AdtPlugin.class) {
sPlugin = null;
@@ -465,21 +462,11 @@ public class AdtPlugin extends AbstractUIPlugin {
return SdkConstants.OS_SDK_TOOLS_FOLDER + AndroidConstants.FN_ADB;
}
- /** Returns the aapt path relative to the sdk folder */
- public static String getOsRelativeAapt() {
- return SdkConstants.OS_SDK_TOOLS_FOLDER + AndroidConstants.FN_AAPT;
- }
-
/** Returns the emulator path relative to the sdk folder */
public static String getOsRelativeEmulator() {
return SdkConstants.OS_SDK_TOOLS_FOLDER + AndroidConstants.FN_EMULATOR;
}
- /** Returns the aidl path relative to the sdk folder */
- public static String getOsRelativeAidl() {
- return SdkConstants.OS_SDK_TOOLS_FOLDER + AndroidConstants.FN_AIDL;
- }
-
/** Returns the absolute adb path */
public static String getOsAbsoluteAdb() {
return getOsSdkFolder() + getOsRelativeAdb();
@@ -491,21 +478,11 @@ public class AdtPlugin extends AbstractUIPlugin {
AndroidConstants.FN_TRACEVIEW;
}
- /** Returns the absolute aapt path */
- public static String getOsAbsoluteAapt() {
- return getOsSdkFolder() + getOsRelativeAapt();
- }
-
/** Returns the absolute emulator path */
public static String getOsAbsoluteEmulator() {
return getOsSdkFolder() + getOsRelativeEmulator();
}
- /** Returns the absolute aidl path */
- public static String getOsAbsoluteAidl() {
- return getOsSdkFolder() + getOsRelativeAidl();
- }
-
/**
* Returns a Url file path to the javaDoc folder.
*/
@@ -968,8 +945,6 @@ public class AdtPlugin extends AbstractUIPlugin {
// check the path to various tools we use
String[] filesToCheck = new String[] {
osSdkLocation + getOsRelativeAdb(),
- osSdkLocation + getOsRelativeAapt(),
- osSdkLocation + getOsRelativeAidl(),
osSdkLocation + getOsRelativeEmulator()
};
for (String file : filesToCheck) {
@@ -1058,17 +1033,6 @@ public class AdtPlugin extends AbstractUIPlugin {
// FIXME: move this per platform, or somewhere else.
progress = SubMonitor.convert(monitor,
Messages.AdtPlugin_Parsing_Resources, 20);
- DexWrapper.unloadDex();
-
- IStatus res = DexWrapper.loadDex(
- mOsSdkLocation + AndroidConstants.OS_SDK_LIBS_DX_JAR);
- if (res != Status.OK_STATUS) {
- synchronized (getSdkLockObject()) {
- mSdkIsLoaded = LoadStatus.FAILED;
- mPostLoadProjectsToResolve.clear();
- }
- return res;
- }
synchronized (getSdkLockObject()) {
mSdkIsLoaded = LoadStatus.LOADED;
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/build/ApkBuilder.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/build/ApkBuilder.java
index 43971b0..c359905 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/build/ApkBuilder.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/build/ApkBuilder.java
@@ -19,7 +19,7 @@ package com.android.ide.eclipse.adt.build;
import com.android.ide.eclipse.adt.AdtConstants;
import com.android.ide.eclipse.adt.AdtPlugin;
import com.android.ide.eclipse.adt.project.ProjectHelper;
-import com.android.ide.eclipse.adt.sdk.LoadStatus;
+import com.android.ide.eclipse.adt.sdk.AndroidTargetData;
import com.android.ide.eclipse.adt.sdk.Sdk;
import com.android.ide.eclipse.common.AndroidConstants;
import com.android.ide.eclipse.common.project.BaseProjectHelper;
@@ -67,6 +67,8 @@ import java.text.DateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.Map;
+import java.util.Set;
+import java.util.Map.Entry;
public class ApkBuilder extends BaseBuilder {
@@ -280,8 +282,12 @@ public class ApkBuilder extends BaseBuilder {
}
}
- // also check the final file!
- String finalPackageName = project.getName() + AndroidConstants.DOT_ANDROID_PACKAGE;
+ // get the extra configs for the project. This will give us a list of custom apk
+ // to build based on a restricted set of resources.
+ Map<String, String> configs = Sdk.getCurrent().getProjectConfigs(project);
+
+ // also check the final file(s)!
+ String finalPackageName = getFileName(project, null /*config*/);
if (mBuildFinalPackage == false && outputFolder != null) {
tmp = outputFolder.findMember(finalPackageName);
if (tmp == null || (tmp instanceof IFile &&
@@ -290,6 +296,24 @@ public class ApkBuilder extends BaseBuilder {
AdtPlugin.printBuildToConsole(AdtConstants.BUILD_VERBOSE, project, msg);
mBuildFinalPackage = true;
}
+
+ if (configs != null) {
+ Set<Entry<String, String>> entrySet = configs.entrySet();
+
+ for (Entry<String, String> entry : entrySet) {
+ String filename = getFileName(project, entry.getKey());
+
+ tmp = outputFolder.findMember(filename);
+ if (tmp == null || (tmp instanceof IFile &&
+ tmp.exists() == false)) {
+ String msg = String.format(Messages.s_Missing_Repackaging,
+ finalPackageName);
+ AdtPlugin.printBuildToConsole(AdtConstants.BUILD_VERBOSE, project, msg);
+ mBuildFinalPackage = true;
+ break;
+ }
+ }
+ }
}
// store the build status in the persistent storage
@@ -358,6 +382,17 @@ public class ApkBuilder extends BaseBuilder {
// handle already present .apk, and if that one failed as well, the user will be
// notified.
finalPackage.delete();
+
+ if (configs != null) {
+ Set<Entry<String, String>> entrySet = configs.entrySet();
+ for (Entry<String, String> entry : entrySet) {
+ String packageFilepath = osBinPath + File.separator +
+ getFileName(project, entry.getKey());
+
+ finalPackage = new File(packageFilepath);
+ finalPackage.delete();
+ }
+ }
// first we check if we need to package the resources.
if (mPackageResources) {
@@ -401,13 +436,30 @@ public class ApkBuilder extends BaseBuilder {
osAssetsPath = assetsFolder.getLocation().toOSString();
}
+ // build the default resource package
if (executeAapt(project, osManifestPath, osResPath,
osAssetsPath, osBinPath + File.separator +
- AndroidConstants.FN_RESOURCES_AP_) == false) {
+ AndroidConstants.FN_RESOURCES_AP_, null /*configFilter*/) == false) {
// aapt failed. Whatever files that needed to be marked
// have already been marked. We just return.
return referencedProjects;
}
+
+ // now do the same thing for all the configured resource packages.
+ if (configs != null) {
+ Set<Entry<String, String>> entrySet = configs.entrySet();
+ for (Entry<String, String> entry : entrySet) {
+ String outPathFormat = osBinPath + File.separator +
+ AndroidConstants.FN_RESOURCES_S_AP_;
+ String outPath = String.format(outPathFormat, entry.getKey());
+ if (executeAapt(project, osManifestPath, osResPath,
+ osAssetsPath, outPath, entry.getValue()) == false) {
+ // aapt failed. Whatever files that needed to be marked
+ // have already been marked. We just return.
+ return referencedProjects;
+ }
+ }
+ }
// build has been done. reset the state of the builder
mPackageResources = false;
@@ -433,25 +485,49 @@ public class ApkBuilder extends BaseBuilder {
}
// now we need to make the final package from the intermediary apk
- // and classes.dex
+ // and classes.dex.
+ // This is the default package with all the resources.
+ String classesDexPath = osBinPath + File.separator + AndroidConstants.FN_CLASSES_DEX;
if (finalPackage(osBinPath + File.separator + AndroidConstants.FN_RESOURCES_AP_,
- osBinPath + File.separator + AndroidConstants.FN_CLASSES_DEX,
- osFinalPackagePath, javaProject, referencedJavaProjects) == false) {
+ classesDexPath,osFinalPackagePath, javaProject,
+ referencedJavaProjects) == false) {
return referencedProjects;
- } else {
- // get the resource to bin
- outputFolder.refreshLocal(IResource.DEPTH_ONE, monitor);
+ }
+
+ // now do the same thing for all the configured resource packages.
+ if (configs != null) {
+ String resPathFormat = osBinPath + File.separator +
+ AndroidConstants.FN_RESOURCES_S_AP_;
+
+ Set<Entry<String, String>> entrySet = configs.entrySet();
+ for (Entry<String, String> entry : entrySet) {
+ // make the filename for the resource package.
+ String resPath = String.format(resPathFormat, entry.getKey());
+
+ // make the filename for the apk to generate
+ String apkOsFilePath = osBinPath + File.separator +
+ getFileName(project, entry.getKey());
+ if (finalPackage(resPath, classesDexPath, apkOsFilePath, javaProject,
+ referencedJavaProjects) == false) {
+ return referencedProjects;
+ }
+ }
+ }
- // build has been done. reset the state of the builder
- mBuildFinalPackage = false;
+ // we are done.
+
+ // get the resource to bin
+ outputFolder.refreshLocal(IResource.DEPTH_ONE, monitor);
- // and store it
- saveProjectBooleanProperty(PROPERTY_BUILD_APK, mBuildFinalPackage);
-
- AdtPlugin.printBuildToConsole(AdtConstants.BUILD_VERBOSE, getProject(),
- "Build Success!");
- }
+ // build has been done. reset the state of the builder
+ mBuildFinalPackage = false;
+
+ // and store it
+ saveProjectBooleanProperty(PROPERTY_BUILD_APK, mBuildFinalPackage);
+
+ AdtPlugin.printBuildToConsole(AdtConstants.BUILD_VERBOSE, getProject(),
+ "Build Success!");
}
return referencedProjects;
}
@@ -475,19 +551,26 @@ public class ApkBuilder extends BaseBuilder {
* @param osResPath The path to the res folder
* @param osAssetsPath The path to the assets folder. This can be null.
* @param osOutFilePath The path to the temporary resource file to create.
+ * @param configFilter The configuration filter for the resources to include
+ * (used with -c option)
* @return true if success, false otherwise.
*/
private boolean executeAapt(IProject project, String osManifestPath,
- String osResPath, String osAssetsPath, String osOutFilePath) {
+ String osResPath, String osAssetsPath, String osOutFilePath, String configFilter) {
+ IAndroidTarget target = Sdk.getCurrent().getTarget(project);
// Create the command line.
ArrayList<String> commandArray = new ArrayList<String>();
- commandArray.add(AdtPlugin.getOsAbsoluteAapt());
+ commandArray.add(target.getPath(IAndroidTarget.AAPT));
commandArray.add("package"); //$NON-NLS-1$
commandArray.add("-f");//$NON-NLS-1$
if (AdtPlugin.getBuildVerbosity() == AdtConstants.BUILD_VERBOSE) {
commandArray.add("-v"); //$NON-NLS-1$
}
+ if (configFilter != null) {
+ commandArray.add("-c"); //$NON-NLS-1$
+ commandArray.add(configFilter);
+ }
commandArray.add("-M"); //$NON-NLS-1$
commandArray.add(osManifestPath);
commandArray.add("-S"); //$NON-NLS-1$
@@ -497,8 +580,7 @@ public class ApkBuilder extends BaseBuilder {
commandArray.add(osAssetsPath);
}
commandArray.add("-I"); //$NON-NLS-1$
- commandArray.add(
- Sdk.getCurrent().getTarget(project).getPath(IAndroidTarget.ANDROID_JAR));
+ commandArray.add(target.getPath(IAndroidTarget.ANDROID_JAR));
commandArray.add("-F"); //$NON-NLS-1$
commandArray.add(osOutFilePath);
@@ -576,14 +658,19 @@ public class ApkBuilder extends BaseBuilder {
*/
private boolean executeDx(IJavaProject javaProject, String osBinPath, String osOutFilePath,
IJavaProject[] referencedJavaProjects) throws CoreException {
+ IAndroidTarget target = Sdk.getCurrent().getTarget(javaProject.getProject());
+ AndroidTargetData targetData = Sdk.getCurrent().getTargetData(target);
+ if (targetData == null) {
+ throw new CoreException(new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID,
+ Messages.ApkBuilder_UnableBuild_Dex_Not_loaded));
+ }
+
// get the dex wrapper
- DexWrapper wrapper = DexWrapper.getWrapper();
+ DexWrapper wrapper = targetData.getDexWrapper();
if (wrapper == null) {
- if (DexWrapper.getStatus() == LoadStatus.FAILED) {
- throw new CoreException(new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID,
- Messages.ApkBuilder_UnableBuild_Dex_Not_loaded));
- }
+ throw new CoreException(new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID,
+ Messages.ApkBuilder_UnableBuild_Dex_Not_loaded));
}
// make sure dx use the proper output streams.
@@ -1003,6 +1090,19 @@ public class ApkBuilder extends BaseBuilder {
return list.toArray(new IJavaProject[list.size()]);
}
+
+ /**
+ * Returns the apk filename for the given project
+ * @param project The project.
+ * @param config An optional config name. Can be null.
+ */
+ private static String getFileName(IProject project, String config) {
+ if (config != null) {
+ return project.getName() + "-" + config + AndroidConstants.DOT_ANDROID_PACKAGE; //$NON-NLS-1$
+ }
+
+ return project.getName() + AndroidConstants.DOT_ANDROID_PACKAGE;
+ }
/**
* Checks a {@link IFile} to make sure it should be packaged as standard resources.
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/build/ApkDeltaVisitor.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/build/ApkDeltaVisitor.java
index aec703d..5d6793a 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/build/ApkDeltaVisitor.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/build/ApkDeltaVisitor.java
@@ -192,11 +192,16 @@ public class ApkDeltaVisitor extends BaseDeltaVisitor
IPath parentPath = path.removeLastSegments(1);
if (mOutputPath.equals(parentPath)) {
String resourceName = resource.getName();
+ // check if classes.dex was removed
if (resourceName.equalsIgnoreCase(AndroidConstants.FN_CLASSES_DEX)) {
mConvertToDex = true;
mMakeFinalPackage = true;
} else if (resourceName.equalsIgnoreCase(
- AndroidConstants.FN_RESOURCES_AP_)) {
+ AndroidConstants.FN_RESOURCES_AP_) ||
+ AndroidConstants.PATTERN_RESOURCES_S_AP_.matcher(
+ resourceName).matches()) {
+ // or if the default resources.ap_ or a configured version
+ // (resources-###.ap_) was removed.
mPackageResources = true;
mMakeFinalPackage = true;
}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/build/DexWrapper.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/build/DexWrapper.java
index cba8ad7..26d96d7 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/build/DexWrapper.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/build/DexWrapper.java
@@ -17,7 +17,6 @@
package com.android.ide.eclipse.adt.build;
import com.android.ide.eclipse.adt.AdtPlugin;
-import com.android.ide.eclipse.adt.sdk.LoadStatus;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IStatus;
@@ -46,10 +45,6 @@ public final class DexWrapper {
private final static String MAIN_RUN = "run"; //$NON-NLS-1$
- private static DexWrapper sWrapper;
-
- private static LoadStatus sLoadStatus = LoadStatus.LOADING;
-
private Method mRunMethod;
private Constructor<?> mArgConstructor;
@@ -67,10 +62,8 @@ public final class DexWrapper {
* @param osFilepath the location of the dex.jar file.
* @return an IStatus indicating the result of the load.
*/
- public static synchronized IStatus loadDex(String osFilepath) {
+ public synchronized IStatus loadDex(String osFilepath) {
try {
- sWrapper = null;
-
File f = new File(osFilepath);
if (f.isFile() == false) {
return new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID, String.format(
@@ -86,45 +79,39 @@ public final class DexWrapper {
Class<?> consoleClass = loader.loadClass(DEX_CONSOLE);
Class<?> argClass = loader.loadClass(DEX_ARGS);
- sWrapper = new DexWrapper(mainClass, argClass, consoleClass);
-
+ try {
+ // now get the fields/methods we need
+ mRunMethod = mainClass.getMethod(MAIN_RUN, argClass);
+
+ mArgConstructor = argClass.getConstructor();
+ mArgOutName = argClass.getField("outName"); //$NON-NLS-1$
+ mArgJarOutput = argClass.getField("jarOutput"); //$NON-NLS-1$
+ mArgFileNames = argClass.getField("fileNames"); //$NON-NLS-1$
+ mArgVerbose = argClass.getField("verbose"); //$NON-NLS-1$
+
+ mConsoleOut = consoleClass.getField("out"); //$NON-NLS-1$
+ mConsoleErr = consoleClass.getField("err"); //$NON-NLS-1$
+
+ } catch (SecurityException e) {
+ return createErrorStatus(Messages.DexWrapper_SecuryEx_Unable_To_Find_API, e);
+ } catch (NoSuchMethodException e) {
+ return createErrorStatus(Messages.DexWrapper_SecuryEx_Unable_To_Find_Method, e);
+ } catch (NoSuchFieldException e) {
+ return createErrorStatus(Messages.DexWrapper_SecuryEx_Unable_To_Find_Field, e);
+ }
+
return Status.OK_STATUS;
} catch (MalformedURLException e) {
// really this should not happen.
- return createErrorStatus(String.format(Messages.DexWrapper_Failed_to_load_s, osFilepath), e);
+ return createErrorStatus(
+ String.format(Messages.DexWrapper_Failed_to_load_s, osFilepath), e);
} catch (ClassNotFoundException e) {
- return createErrorStatus(String.format(Messages.DexWrapper_Failed_to_load_s, osFilepath), e);
- } catch (CoreException e) {
- return e.getStatus();
- } finally {
- if (sWrapper == null) {
- sLoadStatus = LoadStatus.FAILED;
- } else {
- sLoadStatus = LoadStatus.LOADED;
- }
+ return createErrorStatus(
+ String.format(Messages.DexWrapper_Failed_to_load_s, osFilepath), e);
}
}
/**
- * Unloads the loaded dex wrapper.
- */
- public static synchronized void unloadDex() {
- sWrapper = null;
- sLoadStatus = LoadStatus.LOADING;
- }
-
- public static synchronized DexWrapper getWrapper() {
- return sWrapper;
- }
-
- /**
- * Returns the {@link LoadStatus}.
- */
- public static synchronized LoadStatus getStatus() {
- return sLoadStatus;
- }
-
- /**
* Runs the dex command.
* @param osOutFilePath the OS path to the outputfile (classes.dex
* @param osFilenames list of input source files (.class and .jar files)
@@ -169,33 +156,6 @@ public final class DexWrapper {
}
}
- private DexWrapper(Class<?> mainClass, Class<?> argClass, Class<?> consoleClass)
- throws CoreException {
- try {
- // now get the fields/methods we need
- mRunMethod = mainClass.getMethod(MAIN_RUN, argClass);
-
- mArgConstructor = argClass.getConstructor();
- mArgOutName = argClass.getField("outName"); //$NON-NLS-1$
- mArgJarOutput = argClass.getField("jarOutput"); //$NON-NLS-1$
- mArgFileNames = argClass.getField("fileNames"); //$NON-NLS-1$
- mArgVerbose = argClass.getField("verbose"); //$NON-NLS-1$
-
- mConsoleOut = consoleClass.getField("out"); //$NON-NLS-1$
- mConsoleErr = consoleClass.getField("err"); //$NON-NLS-1$
-
- } catch (SecurityException e) {
- throw new CoreException(createErrorStatus(
- Messages.DexWrapper_SecuryEx_Unable_To_Find_API, e));
- } catch (NoSuchMethodException e) {
- throw new CoreException(createErrorStatus(
- Messages.DexWrapper_SecuryEx_Unable_To_Find_Method, e));
- } catch (NoSuchFieldException e) {
- throw new CoreException(createErrorStatus(
- Messages.DexWrapper_SecuryEx_Unable_To_Find_Field, e));
- }
- }
-
private static IStatus createErrorStatus(String message, Exception e) {
AdtPlugin.log(e, message);
AdtPlugin.printErrorToConsole(Messages.DexWrapper_Dex_Loader, message);
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/build/PreCompilerBuilder.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/build/PreCompilerBuilder.java
index 2c15d55..958cac2 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/build/PreCompilerBuilder.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/build/PreCompilerBuilder.java
@@ -235,6 +235,7 @@ public class PreCompilerBuilder extends BaseBuilder {
// get the project objects
IProject project = getProject();
IJavaProject javaProject = JavaCore.create(project);
+ IAndroidTarget projectTarget = Sdk.getCurrent().getTarget(project);
// now we need to get the classpath list
ArrayList<IPath> sourceList = BaseProjectHelper.getSourceClasspaths(javaProject);
@@ -407,8 +408,6 @@ public class PreCompilerBuilder extends BaseBuilder {
String osResPath = resLocation.toOSString();
String osManifestPath = manifestLocation.toOSString();
- IAndroidTarget projectTarget = Sdk.getCurrent().getTarget(project);
-
// remove the aapt markers
removeMarkersFromFile(manifest, AndroidConstants.MARKER_AAPT);
removeMarkersFromContainer(resFolder, AndroidConstants.MARKER_AAPT);
@@ -432,7 +431,7 @@ public class PreCompilerBuilder extends BaseBuilder {
// launch aapt: create the command line
ArrayList<String> array = new ArrayList<String>();
- array.add(AdtPlugin.getOsAbsoluteAapt());
+ array.add(projectTarget.getPath(IAndroidTarget.AAPT));
array.add("package"); //$NON-NLS-1$
array.add("-m"); //$NON-NLS-1$
if (AdtPlugin.getBuildVerbosity() == AdtConstants.BUILD_VERBOSE) {
@@ -541,7 +540,7 @@ public class PreCompilerBuilder extends BaseBuilder {
if (projectAidl != null && projectAidl.exists()) {
folderAidlPath = projectAidl.getLocation().toOSString();
}
- boolean aidlStatus = handleAidl(sourceList, folderAidlPath, monitor);
+ boolean aidlStatus = handleAidl(projectTarget, sourceList, folderAidlPath, monitor);
if (aidlStatus == false && mCompileResources == false) {
AdtPlugin.printBuildToConsole(AdtConstants.BUILD_VERBOSE, project,
@@ -729,14 +728,15 @@ public class PreCompilerBuilder extends BaseBuilder {
/**
* Compiles aidl files into java. This will also removes old java files
* created from aidl files that are now gone.
+ * @param projectTarget Target of the project
* @param sourceFolders the list of source folders, relative to the workspace.
* @param folderAidlPath
* @param monitor the projess monitor
* @returns true if it did something
* @throws CoreException
*/
- private boolean handleAidl(ArrayList<IPath> sourceFolders, String folderAidlPath,
- IProgressMonitor monitor) throws CoreException {
+ private boolean handleAidl(IAndroidTarget projectTarget, ArrayList<IPath> sourceFolders,
+ String folderAidlPath, IProgressMonitor monitor) throws CoreException {
if (mAidlToCompile.size() == 0 && mAidlToRemove.size() == 0) {
return false;
}
@@ -746,7 +746,7 @@ public class PreCompilerBuilder extends BaseBuilder {
String[] command = new String[4 + sourceFolders.size() + (folderAidlPath != null ? 1 : 0)];
int index = 0;
int aidlIndex;
- command[index++] = AdtPlugin.getOsAbsoluteAidl();
+ command[index++] = projectTarget.getPath(IAndroidTarget.AIDL);
command[aidlIndex = index++] = "-p"; //$NON-NLS-1$
if (folderAidlPath != null) {
command[index++] = "-p" + folderAidlPath; //$NON-NLS-1$
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/debug/launching/AndroidLaunchController.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/debug/launching/AndroidLaunchController.java
index d4952b1..ac003df 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/debug/launching/AndroidLaunchController.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/debug/launching/AndroidLaunchController.java
@@ -1519,6 +1519,7 @@ public final class AndroidLaunchController implements IDebugBridgeChangeListener
AdtPlugin.printErrorToConsole(launchInfo.mProject,
String.format(message1, launchInfo.mActivity));
}
+ launchInfo.mLaunch.stopLaunch();
}
for (DelayedLaunchInfo launchInfo : mWaitingForDebuggerApplications) {
if (launchInfo.mLaunchAction == LaunchConfigDelegate.ACTION_DO_NOTHING) {
@@ -1527,7 +1528,11 @@ public final class AndroidLaunchController implements IDebugBridgeChangeListener
AdtPlugin.printErrorToConsole(launchInfo.mProject,
String.format(message1, launchInfo.mActivity));
}
+ launchInfo.mLaunch.stopLaunch();
}
+
+ mWaitingForReadyEmulatorList.clear();
+ mWaitingForDebuggerApplications.clear();
}
}
@@ -1573,24 +1578,31 @@ public final class AndroidLaunchController implements IDebugBridgeChangeListener
*
* @see IDeviceChangeListener#deviceDisconnected(Device)
*/
+ @SuppressWarnings("unchecked")
public void deviceDisconnected(Device device) {
// any pending launch on this device must be canceled.
String message = "%1$s disconnected! Cancelling '%2$s' launch!";
synchronized (sListLock) {
- for (DelayedLaunchInfo launchInfo : mWaitingForReadyEmulatorList) {
+ ArrayList<DelayedLaunchInfo> copyList =
+ (ArrayList<DelayedLaunchInfo>)mWaitingForReadyEmulatorList.clone();
+ for (DelayedLaunchInfo launchInfo : copyList) {
if (launchInfo.mDevice == device) {
AdtPlugin.printErrorToConsole(launchInfo.mProject,
String.format(message, device.getSerialNumber(), launchInfo.mActivity));
+ launchInfo.mLaunch.stopLaunch();
+ mWaitingForReadyEmulatorList.remove(launchInfo);
}
}
- for (DelayedLaunchInfo launchInfo : mWaitingForDebuggerApplications) {
+ copyList = (ArrayList<DelayedLaunchInfo>)mWaitingForDebuggerApplications.clone();
+ for (DelayedLaunchInfo launchInfo : copyList) {
if (launchInfo.mDevice == device) {
AdtPlugin.printErrorToConsole(launchInfo.mProject,
String.format(message, device.getSerialNumber(), launchInfo.mActivity));
+ launchInfo.mLaunch.stopLaunch();
+ mWaitingForDebuggerApplications.remove(launchInfo);
}
}
}
-
}
/**
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/debug/launching/DeviceChooserDialog.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/debug/launching/DeviceChooserDialog.java
index d446e2b..a260350 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/debug/launching/DeviceChooserDialog.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/debug/launching/DeviceChooserDialog.java
@@ -310,7 +310,7 @@ public class DeviceChooserDialog extends Dialog implements IDeviceChangeListener
top.setLayout(new GridLayout(1, true));
mDeviceRadioButton = new Button(top, SWT.RADIO);
- mDeviceRadioButton.setText("Choose an Android running device");
+ mDeviceRadioButton.setText("Choose a running Android device");
mDeviceRadioButton.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
@@ -387,7 +387,7 @@ public class DeviceChooserDialog extends Dialog implements IDeviceChangeListener
});
Button radio2 = new Button(top, SWT.RADIO);
- radio2.setText("Launch a new Virtual Device");
+ radio2.setText("Launch a new Android Virtual Device");
// offset the selector from the radio button
offsetComp = new Composite(top, SWT.NONE);
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/project/internal/AndroidClasspathContainerInitializer.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/project/internal/AndroidClasspathContainerInitializer.java
index 30bf7ed..339dcd0 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/project/internal/AndroidClasspathContainerInitializer.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/project/internal/AndroidClasspathContainerInitializer.java
@@ -172,13 +172,7 @@ public class AndroidClasspathContainerInitializer extends ClasspathContainerInit
// if we are loaded and the target is non null, we create a valid ClassPathContainer
if (sdkIsLoaded && target != null) {
- String targetName = null;
- if (target.isPlatform()) {
- targetName = target.getName();
- } else {
- targetName = String.format("%1$s (%2$s)", target.getName(),
- target.getApiVersionName());
- }
+ String targetName = target.getFullName();
return new AndroidClasspathContainer(
createClasspathEntries(iProject, target, targetName),
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/sdk/AndroidTargetData.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/sdk/AndroidTargetData.java
index 60561ab..2309181 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/sdk/AndroidTargetData.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/sdk/AndroidTargetData.java
@@ -16,6 +16,7 @@
package com.android.ide.eclipse.adt.sdk;
+import com.android.ide.eclipse.adt.build.DexWrapper;
import com.android.ide.eclipse.common.resources.IResourceRepository;
import com.android.ide.eclipse.editors.descriptors.IDescriptorProvider;
import com.android.ide.eclipse.editors.layout.descriptors.LayoutDescriptors;
@@ -54,6 +55,8 @@ public class AndroidTargetData {
private final IAndroidTarget mTarget;
+ private DexWrapper mDexWrapper;
+
/**
* mAttributeValues is a map { key => list [ values ] }.
* The key for the map is "(element-xml-name,attribute-namespace:attribute-xml-local-name)".
@@ -64,27 +67,34 @@ public class AndroidTargetData {
* This is used for attributes that do not have a unique name, but still need to be populated
* with values in the UI. Uniquely named attributes have their values in {@link #mEnumValueMap}.
*/
- private final Hashtable<String, String[]> mAttributeValues = new Hashtable<String, String[]>();
+ private Hashtable<String, String[]> mAttributeValues = new Hashtable<String, String[]>();
private IResourceRepository mSystemResourceRepository;
- private final AndroidManifestDescriptors mManifestDescriptors;
- private final LayoutDescriptors mLayoutDescriptors;
- private final MenuDescriptors mMenuDescriptors;
- private final XmlDescriptors mXmlDescriptors;
+ private AndroidManifestDescriptors mManifestDescriptors;
+ private LayoutDescriptors mLayoutDescriptors;
+ private MenuDescriptors mMenuDescriptors;
+ private XmlDescriptors mXmlDescriptors;
- private final Map<String, Map<String, Integer>> mEnumValueMap;
+ private Map<String, Map<String, Integer>> mEnumValueMap;
- private final ProjectResources mFrameworkResources;
- private final LayoutBridge mLayoutBridge;
+ private ProjectResources mFrameworkResources;
+ private LayoutBridge mLayoutBridge;
private boolean mLayoutBridgeInit = false;
+ AndroidTargetData(IAndroidTarget androidTarget) {
+ mTarget = androidTarget;
+ }
+
+ void setDexWrapper(DexWrapper wrapper) {
+ mDexWrapper = wrapper;
+ }
+
/**
* Creates an AndroidTargetData object.
*/
- AndroidTargetData(IAndroidTarget androidTarget,
- IResourceRepository systemResourceRepository,
+ void setExtraData(IResourceRepository systemResourceRepository,
AndroidManifestDescriptors manifestDescriptors,
LayoutDescriptors layoutDescriptors,
MenuDescriptors menuDescriptors,
@@ -98,7 +108,6 @@ public class AndroidTargetData {
ProjectResources resources,
LayoutBridge layoutBridge) {
- mTarget = androidTarget;
mSystemResourceRepository = systemResourceRepository;
mManifestDescriptors = manifestDescriptors;
mLayoutDescriptors = layoutDescriptors;
@@ -113,6 +122,10 @@ public class AndroidTargetData {
serviceIntentActionValues, intentCategoryValues);
}
+ public DexWrapper getDexWrapper() {
+ return mDexWrapper;
+ }
+
public IResourceRepository getSystemResources() {
return mSystemResourceRepository;
}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/sdk/AndroidTargetParser.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/sdk/AndroidTargetParser.java
index dfe876f..aab660d 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/sdk/AndroidTargetParser.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/sdk/AndroidTargetParser.java
@@ -17,6 +17,7 @@
package com.android.ide.eclipse.adt.sdk;
import com.android.ide.eclipse.adt.AdtPlugin;
+import com.android.ide.eclipse.adt.build.DexWrapper;
import com.android.ide.eclipse.adt.sdk.AndroidTargetData.LayoutBridge;
import com.android.ide.eclipse.common.AndroidConstants;
import com.android.ide.eclipse.common.resources.AttrsXmlParser;
@@ -91,8 +92,25 @@ public final class AndroidTargetParser {
try {
SubMonitor progress = SubMonitor.convert(monitor,
String.format("Parsing SDK %1$s", mAndroidTarget.getName()),
- 120);
+ 200);
+ AndroidTargetData targetData = new AndroidTargetData(mAndroidTarget);
+
+ // load DX.
+ DexWrapper dexWrapper = new DexWrapper();
+ IStatus res = dexWrapper.loadDex(mAndroidTarget.getPath(IAndroidTarget.DX_JAR));
+ if (res != Status.OK_STATUS) {
+ return new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID,
+ String.format("dx.jar loading failed for target '%1$s'",
+ mAndroidTarget.getFullName()));
+ }
+
+ // we have loaded dx.
+ targetData.setDexWrapper(dexWrapper);
+
+ // parse the rest of the data.
+ progress.setWorkRemaining(120);
+
AndroidJarLoader classLoader =
new AndroidJarLoader(mAndroidTarget.getPath(IAndroidTarget.ANDROID_JAR));
@@ -229,8 +247,7 @@ public final class AndroidTargetParser {
progress.worked(10);
// and finally create the PlatformData with all that we loaded.
- AndroidTargetData targetData = new AndroidTargetData(mAndroidTarget,
- frameworkRepository,
+ targetData.setExtraData(frameworkRepository,
manifestDescriptors,
layoutDescriptors,
menuDescriptors,
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/sdk/Sdk.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/sdk/Sdk.java
index 01b722f..5bfa8a2 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/sdk/Sdk.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/sdk/Sdk.java
@@ -18,6 +18,8 @@ package com.android.ide.eclipse.adt.sdk;
import com.android.ide.eclipse.adt.AdtPlugin;
import com.android.ide.eclipse.adt.project.internal.AndroidClasspathContainerInitializer;
+import com.android.ide.eclipse.editors.resources.manager.ResourceMonitor;
+import com.android.ide.eclipse.editors.resources.manager.ResourceMonitor.IProjectListener;
import com.android.prefs.AndroidLocation.AndroidLocationException;
import com.android.sdklib.IAndroidTarget;
import com.android.sdklib.ISdkLog;
@@ -28,6 +30,8 @@ import com.android.sdklib.project.ProjectProperties;
import com.android.sdklib.project.ProjectProperties.PropertyType;
import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.IncrementalProjectBuilder;
+import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.JavaCore;
@@ -38,6 +42,9 @@ import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+import java.util.Map.Entry;
/**
* Central point to load, manipulate and deal with the Android SDK. Only one SDK can be used
@@ -48,18 +55,19 @@ import java.util.HashMap;
*
* To get the list of platforms or add-ons present in the SDK, call {@link #getTargets()}.
*/
-public class Sdk {
+public class Sdk implements IProjectListener {
private static Sdk sCurrentSdk = null;
private final SdkManager mManager;
private final AvdManager mAvdManager;
- private final HashMap<IProject, IAndroidTarget> mProjectMap =
+ private final HashMap<IProject, IAndroidTarget> mProjectTargetMap =
new HashMap<IProject, IAndroidTarget>();
- private final HashMap<IAndroidTarget, AndroidTargetData> mTargetMap =
+ private final HashMap<IAndroidTarget, AndroidTargetData> mTargetDataMap =
new HashMap<IAndroidTarget, AndroidTargetData>();
+ private final HashMap<IProject, Map<String, String>> mProjectConfigMap =
+ new HashMap<IProject, Map<String, String>>();
private final String mDocBaseUrl;
-
/**
* Loads an SDK and returns an {@link Sdk} object if success.
@@ -67,7 +75,7 @@ public class Sdk {
*/
public static Sdk loadSdk(String sdkLocation) {
if (sCurrentSdk != null) {
- // manual unload?
+ sCurrentSdk.dispose();
sCurrentSdk = null;
}
@@ -159,16 +167,16 @@ public class Sdk {
* Associates an {@link IProject} and an {@link IAndroidTarget}.
*/
public void setProject(IProject project, IAndroidTarget target) {
- synchronized (mProjectMap) {
+ synchronized (mProjectTargetMap) {
// look for the current target of the project
- IAndroidTarget previousTarget = mProjectMap.get(project);
+ IAndroidTarget previousTarget = mProjectTargetMap.get(project);
if (target != previousTarget) {
// save the target hash string in the project persistent property
setProjectTargetHashString(project, target.hashString());
// put it in a local map for easy access.
- mProjectMap.put(project, target);
+ mProjectTargetMap.put(project, target);
// recompile the project if needed.
IJavaProject javaProject = JavaCore.create(project);
@@ -182,11 +190,11 @@ public class Sdk {
* Returns the {@link IAndroidTarget} object associated with the given {@link IProject}.
*/
public IAndroidTarget getTarget(IProject project) {
- synchronized (mProjectMap) {
- IAndroidTarget target = mProjectMap.get(project);
+ synchronized (mProjectTargetMap) {
+ IAndroidTarget target = mProjectTargetMap.get(project);
if (target == null) {
// get the value from the project persistent property.
- String targetHashString = getProjectTargetHashString(project);
+ String targetHashString = loadProjectProperties(project, this);
if (targetHashString != null) {
target = mManager.getTargetFromHashString(targetHashString);
@@ -197,14 +205,19 @@ public class Sdk {
}
}
+
/**
- * Returns the hash string uniquely identifying the target of a project. This methods reads
- * the string from the project persistent preferences/properties.
- * <p/>The string is equivalent to the return of {@link IAndroidTarget#hashString()}.
+ * Parses the project properties and returns the hash string uniquely identifying the
+ * target of the given project.
+ * <p/>
+ * This methods reads the content of the <code>default.properties</code> file present in
+ * the root folder of the project.
+ * <p/>The returned string is equivalent to the return of {@link IAndroidTarget#hashString()}.
* @param project The project for which to return the target hash string.
+ * @param storeConfigs Whether the read configuration should be stored in the map.
* @return the hash string or null if the project does not have a target set.
*/
- public static String getProjectTargetHashString(IProject project) {
+ private static String loadProjectProperties(IProject project, Sdk storeConfigs) {
// load the default.properties from the project folder.
ProjectProperties properties = ProjectProperties.load(project.getLocation().toOSString(),
PropertyType.DEFAULT);
@@ -214,11 +227,46 @@ public class Sdk {
return null;
}
+ if (storeConfigs != null) {
+ // get the list of configs.
+ String configList = properties.getProperty(ProjectProperties.PROPERTY_CONFIGS);
+
+ // this is a comma separated list
+ String[] configs = configList.split(","); //$NON-NLS-1$
+
+ // read the value of each config and store it in a map
+ HashMap<String, String> configMap = new HashMap<String, String>();
+
+ for (String config : configs) {
+ String configValue = properties.getProperty(config);
+ if (configValue != null) {
+ configMap.put(config, configValue);
+ }
+ }
+
+ if (configMap.size() > 0) {
+ storeConfigs.mProjectConfigMap.put(project, configMap);
+ }
+ }
+
return properties.getProperty(ProjectProperties.PROPERTY_TARGET);
}
+
+ /**
+ * Returns the hash string uniquely identifying the target of a project.
+ * <p/>
+ * This methods reads the content of the <code>default.properties</code> file present in
+ * the root folder of the project.
+ * <p/>The string is equivalent to the return of {@link IAndroidTarget#hashString()}.
+ * @param project The project for which to return the target hash string.
+ * @return the hash string or null if the project does not have a target set.
+ */
+ public static String getProjectTargetHashString(IProject project) {
+ return loadProjectProperties(project, null /*storeConfigs*/);
+ }
/**
- * Sets a target hash string in a project's persistent preferences/property storage.
+ * Sets a target hash string in given project's <code>default.properties</code> file.
* @param project The project in which to save the hash string.
* @param targetHashString The target hash string to save. This must be the result from
* {@link IAndroidTarget#hashString()}.
@@ -249,12 +297,82 @@ public class Sdk {
* Return the {@link AndroidTargetData} for a given {@link IAndroidTarget}.
*/
public AndroidTargetData getTargetData(IAndroidTarget target) {
- synchronized (mTargetMap) {
- return mTargetMap.get(target);
+ synchronized (mTargetDataMap) {
+ return mTargetDataMap.get(target);
}
}
/**
+ * Returns the configuration map for a given project.
+ * <p/>The Map key are name to be used in the apk filename, while the values are comma separated
+ * config values. The config value can be passed directly to aapt through the -c option.
+ */
+ public Map<String, String> getProjectConfigs(IProject project) {
+ return mProjectConfigMap.get(project);
+ }
+
+ public void setProjectConfigs(IProject project, Map<String, String> configMap)
+ throws CoreException {
+ // first set the new map
+ mProjectConfigMap.put(project, configMap);
+
+ // Now we write this in default.properties.
+ // Because we don't want to erase other properties from default.properties, we first load
+ // them
+ ProjectProperties properties = ProjectProperties.load(project.getLocation().toOSString(),
+ PropertyType.DEFAULT);
+ if (properties == null) {
+ // doesn't exist yet? we create it.
+ properties = ProjectProperties.create(project.getLocation().toOSString(),
+ PropertyType.DEFAULT);
+ }
+
+ // load the current configs, in order to remove the value properties for each of them
+ // in case a config was removed.
+
+ // get the list of configs.
+ String configList = properties.getProperty(ProjectProperties.PROPERTY_CONFIGS);
+
+ // this is a comma separated list
+ String[] configs = configList.split(","); //$NON-NLS-1$
+
+ boolean hasRemovedConfig = false;
+
+ for (String config : configs) {
+ if (configMap.containsKey(config) == false) {
+ hasRemovedConfig = true;
+ properties.removeProperty(config);
+ }
+ }
+
+ // now add the properties.
+ Set<Entry<String, String>> entrySet = configMap.entrySet();
+ StringBuilder sb = new StringBuilder();
+ for (Entry<String, String> entry : entrySet) {
+ if (sb.length() > 0) {
+ sb.append(",");
+ }
+ sb.append(entry.getKey());
+ properties.setProperty(entry.getKey(), entry.getValue());
+ }
+ properties.setProperty(ProjectProperties.PROPERTY_CONFIGS, sb.toString());
+
+ // and rewrite the file.
+ try {
+ properties.save();
+ } catch (IOException e) {
+ AdtPlugin.log(e, "Failed to save default.properties for project '%s'",
+ project.getName());
+ }
+
+ // we're done, force a rebuild. If there was removed config, we clean instead of build
+ // (to remove the obsolete ap_ and apk file from removed configs).
+ project.build(hasRemovedConfig ?
+ IncrementalProjectBuilder.CLEAN_BUILD : IncrementalProjectBuilder.FULL_BUILD,
+ null);
+ }
+
+ /**
* Returns the {@link AvdManager}. If the AvdManager failed to parse the AVD folder, this could
* be <code>null</code>.
*/
@@ -266,14 +384,25 @@ public class Sdk {
mManager = manager;
mAvdManager = avdManager;
+ // listen to projects closing
+ ResourceMonitor monitor = ResourceMonitor.getMonitor();
+ monitor.addProjectListener(this);
+
// pre-compute some paths
mDocBaseUrl = getDocumentationBaseUrl(mManager.getLocation() +
SdkConstants.OS_SDK_DOCS_FOLDER);
}
+
+ /**
+ * Cleans and unloads the SDK.
+ */
+ private void dispose() {
+ ResourceMonitor.getMonitor().removeProjectListener(this);
+ }
void setTargetData(IAndroidTarget target, AndroidTargetData data) {
- synchronized (mTargetMap) {
- mTargetMap.put(target, data);
+ synchronized (mTargetDataMap) {
+ mTargetDataMap.put(target, data);
}
}
@@ -314,6 +443,24 @@ public class Sdk {
return null;
}
+ public void projectClosed(IProject project) {
+ mProjectTargetMap.remove(project);
+ mProjectConfigMap.remove(project);
+ }
+
+ public void projectDeleted(IProject project) {
+ projectClosed(project);
+ }
+
+ public void projectOpened(IProject project) {
+ // ignore this. The project will be added to the map the first time the target needs
+ // to be resolved.
+ }
+
+ public void projectOpenedWithWorkspace(IProject project) {
+ // ignore this. The project will be added to the map the first time the target needs
+ // to be resolved.
+ }
}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/common/AndroidConstants.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/common/AndroidConstants.java
index 65817c3..b1c57a6 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/common/AndroidConstants.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/common/AndroidConstants.java
@@ -19,6 +19,7 @@ package com.android.ide.eclipse.common;
import com.android.sdklib.SdkConstants;
import java.io.File;
+import java.util.regex.Pattern;
/**
* Constant definition class.<br>
@@ -49,17 +50,6 @@ public class AndroidConstants {
/** Nature of android projects */
public final static String NATURE = "com.android.ide.eclipse.adt.AndroidNature"; //$NON-NLS-1$
- public final static int PLATFORM_UNKNOWN = 0;
- public final static int PLATFORM_LINUX = 1;
- public final static int PLATFORM_WINDOWS = 2;
- public final static int PLATFORM_DARWIN = 3;
-
- /**
- * Returns current platform, one of {@link #PLATFORM_WINDOWS}, {@link #PLATFORM_DARWIN},
- * {@link #PLATFORM_LINUX} or {@link #PLATFORM_UNKNOWN}.
- */
- public final static int CURRENT_PLATFORM = currentPlatform();
-
/** Separator for workspace path, i.e. "/". */
public final static String WS_SEP = "/"; //$NON-NLS-1$
/** Separator character for workspace path, i.e. '/'. */
@@ -99,8 +89,6 @@ public class AndroidConstants {
public static final String FN_ANDROID_MANIFEST = "AndroidManifest.xml"; //$NON-NLS-1$
public static final String FN_PROJECT_AIDL = "project.aidl"; //$NON-NLS-1$
- /** dex.jar file */
- public static final String FN_DX_JAR = "dx.jar"; //$NON-NLS-1$
/** Name of the android sources directory */
public static final String FD_ANDROID_SOURCES = "sources"; //$NON-NLS-1$
@@ -114,20 +102,21 @@ public class AndroidConstants {
public final static String FN_CLASSES_DEX = "classes.dex"; //$NON-NLS-1$
/** Temporary packaged resources file name, i.e. "resources.ap_" */
public final static String FN_RESOURCES_AP_ = "resources.ap_"; //$NON-NLS-1$
+ /** Temporary packaged resources file name for a specific set of configuration */
+ public final static String FN_RESOURCES_S_AP_ = "resources-%s.ap_"; //$NON-NLS-1$
+ public final static Pattern PATTERN_RESOURCES_S_AP_ =
+ Pattern.compile("resources-.*\\.ap_", Pattern.CASE_INSENSITIVE);
- public final static String FN_ADB = (CURRENT_PLATFORM == PLATFORM_WINDOWS) ?
+ public final static String FN_ADB =
+ (SdkConstants.CURRENT_PLATFORM == SdkConstants.PLATFORM_WINDOWS) ?
"adb.exe" : "adb"; //$NON-NLS-1$ //$NON-NLS-2$
- public final static String FN_AAPT = (CURRENT_PLATFORM == PLATFORM_WINDOWS) ?
- "aapt.exe" : "aapt"; //$NON-NLS-1$ //$NON-NLS-2$
-
- public final static String FN_AIDL = (CURRENT_PLATFORM == PLATFORM_WINDOWS) ?
- "aidl.exe" : "aidl"; //$NON-NLS-1$ //$NON-NLS-2$
-
- public final static String FN_EMULATOR = (CURRENT_PLATFORM == PLATFORM_WINDOWS) ?
+ public final static String FN_EMULATOR =
+ (SdkConstants.CURRENT_PLATFORM == SdkConstants.PLATFORM_WINDOWS) ?
"emulator.exe" : "emulator"; //$NON-NLS-1$ //$NON-NLS-2$
- public final static String FN_TRACEVIEW = (CURRENT_PLATFORM == PLATFORM_WINDOWS) ?
+ public final static String FN_TRACEVIEW =
+ (SdkConstants.CURRENT_PLATFORM == SdkConstants.PLATFORM_WINDOWS) ?
"traceview.exe" : "traceview"; //$NON-NLS-1$ //$NON-NLS-2$
/** Absolute path of the workspace root, i.e. "/" */
@@ -147,11 +136,6 @@ public class AndroidConstants {
* FIXME: remove once the NPW is fixed. */
public final static String OS_SDK_SAMPLES_FOLDER = SdkConstants.FD_SAMPLES + File.separator;
- /** Path of the dx.jar file relative to the sdk folder. */
- public final static String OS_SDK_LIBS_DX_JAR =
- SdkConstants.OS_SDK_TOOLS_LIB_FOLDER + FN_DX_JAR;
-
- /** Regexp for single dot */
public final static String RE_DOT = "\\."; //$NON-NLS-1$
/** Regexp for java extension, i.e. "\.java$" */
public final static String RE_JAVA_EXT = "\\.java$"; //$NON-NLS-1$
@@ -229,22 +213,4 @@ public class AndroidConstants {
/** The base URL where to find the Android class & manifest documentation */
public static final String CODESITE_BASE_URL = "http://code.google.com/android"; //$NON-NLS-1$
- /**
- * Returns current platform
- *
- * @return one of {@link #PLATFORM_WINDOWS}, {@link #PLATFORM_DARWIN},
- * {@link #PLATFORM_LINUX} or {@link #PLATFORM_UNKNOWN}.
- */
- private static int currentPlatform() {
- String os = System.getProperty("os.name"); //$NON-NLS-1$
- if (os.startsWith("Mac OS")) { //$NON-NLS-1$
- return PLATFORM_DARWIN;
- } else if (os.startsWith("Windows")) { //$NON-NLS-1$
- return PLATFORM_WINDOWS;
- } else if (os.startsWith("Linux")) { //$NON-NLS-1$
- return PLATFORM_LINUX;
- }
-
- return PLATFORM_UNKNOWN;
- }
}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/IconFactory.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/IconFactory.java
index e3de3af..2c24772 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/IconFactory.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/IconFactory.java
@@ -18,7 +18,7 @@
package com.android.ide.eclipse.editors;
import com.android.ide.eclipse.adt.AdtPlugin;
-import com.android.ide.eclipse.common.AndroidConstants;
+import com.android.sdklib.SdkConstants;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.swt.SWT;
@@ -231,7 +231,7 @@ public class IconFactory {
// Text measurement varies so slightly depending on the platform
int ofx = 0;
int ofy = 0;
- if (AndroidConstants.CURRENT_PLATFORM == AndroidConstants.PLATFORM_WINDOWS) {
+ if (SdkConstants.CURRENT_PLATFORM == SdkConstants.PLATFORM_WINDOWS) {
ofx = +1;
ofy = -1;
}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/explorer/ResourceExplorerView.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/explorer/ResourceExplorerView.java
index 845db32..d1d8891 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/explorer/ResourceExplorerView.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/explorer/ResourceExplorerView.java
@@ -160,6 +160,13 @@ public class ResourceExplorerView extends ViewPart implements ISelectionListener
// set up the resource manager to send us resource change notification
AdtPlugin.getDefault().getResourceMonitor().addResourceEventListener(this);
}
+
+ @Override
+ public void dispose() {
+ AdtPlugin.getDefault().getResourceMonitor().removeResourceEventListener(this);
+
+ super.dispose();
+ }
@Override
public void setFocus() {
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/manager/ResourceMonitor.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/manager/ResourceMonitor.java
index dc0f505..59a72fb 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/manager/ResourceMonitor.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/manager/ResourceMonitor.java
@@ -189,20 +189,15 @@ public class ResourceMonitor implements IResourceChangeListener {
// the project is opening or closing.
IProject project = (IProject)r;
- // the OPEN flag represent a toggle in the open/close state of the
- // project, but this is sent before the project actually toggles
- // its state.
- // This means that if the project is closing, isOpen() will return true.
- boolean isClosing = project.isOpen();
- if (isClosing) {
+ if (project.isOpen()) {
// notify the listeners.
for (IProjectListener pl : mProjectListeners) {
- pl.projectClosed(project);
+ pl.projectOpened(project);
}
} else {
// notify the listeners.
for (IProjectListener pl : mProjectListeners) {
- pl.projectOpened(project);
+ pl.projectClosed(project);
}
}
}
@@ -287,6 +282,20 @@ public class ResourceMonitor implements IResourceChangeListener {
}
/**
+ * Removes an existing folder listener.
+ * @param listener the listener to remove.
+ */
+ public synchronized void removeFolderListener(IFolderListener listener) {
+ for (int i = 0 ; i < mFolderListeners.size() ; i++) {
+ FolderListenerBundle bundle = mFolderListeners.get(i);
+ if (bundle.listener == listener) {
+ mFolderListeners.remove(i);
+ return;
+ }
+ }
+ }
+
+ /**
* Adds a project listener.
* @param listener The listener to receive the events.
*/
@@ -305,11 +314,31 @@ public class ResourceMonitor implements IResourceChangeListener {
}
}
+ /**
+ * Removes an existing project listener.
+ * @param listener the listener to remove.
+ */
+ public synchronized void removeProjectListener(IProjectListener listener) {
+ mProjectListeners.remove(listener);
+ }
+
+ /**
+ * Adds a resource event listener.
+ * @param listener The listener to receive the events.
+ */
public synchronized void addResourceEventListener(IResourceEventListener listener) {
mEventListeners.add(listener);
}
/**
+ * Removes an existing Resource Event listener.
+ * @param listener the listener to remove.
+ */
+ public synchronized void removeResourceEventListener(IResourceEventListener listener) {
+ mEventListeners.remove(listener);
+ }
+
+ /**
* Processes the workspace resource change events.
*/
public void resourceChanged(IResourceChangeEvent event) {
diff --git a/eclipse/scripts/collect_sources_for_sdk.sh b/eclipse/scripts/collect_sources_for_sdk.sh
new file mode 100644
index 0000000..4637595
--- /dev/null
+++ b/eclipse/scripts/collect_sources_for_sdk.sh
@@ -0,0 +1,58 @@
+#!/bin/bash
+
+function usage() {
+ cat <<EOF
+ Description:
+ This script collects all framework Java sources from the current android
+ source code and places them in a source folder suitable for the eclipse ADT
+ plugin.
+
+ Usage:
+ $0 [-n] <android-git-repo root> <sdk/platforms/xyz/sources>
+
+ The source and destination directories must already exist.
+ Use -n for a dry-run.
+
+EOF
+}
+
+DRY=""
+if [ "-n" == "$1" ]; then
+ DRY="echo"
+ shift
+fi
+
+SRC="$1"
+DST="$2"
+
+if [ -z "$SRC" ] || [ -z "$DST" ] || [ ! -d "$SRC" ] || [ ! -d "$DST" ]; then
+ usage
+ exit 1
+fi
+
+function process() {
+ echo "Examine" $1
+}
+
+N=0
+E=0
+for i in `find -L "${SRC}/frameworks" -name "*.java"`; do
+ if [ -f "$i" ]; then
+ # look for ^package (android.view.blah);$
+ PACKAGE=`sed -n '/^package [^ ;]\+; */{s/[^ ]* *\([^ ;]*\).*/\1/p;q}' "$i"`
+ if [ -n "$PACKAGE" ]; then
+ PACKAGE=${PACKAGE//./\/} # e.g. android.view => android/view
+ JAVA=`basename "$i"` # e.g. View.java
+ [ -z $DRY ] && [ ! -d "$DST/$PACKAGE" ] && mkdir -p -v "$DST/$PACKAGE"
+ $DRY cp -v "$i" "$DST/$PACKAGE/$JAVA"
+ N=$((N+1))
+ else
+ echo "Warning: $i does not have a Java package."
+ E=$((E+1))
+ fi
+ fi
+done
+
+echo "$N java files copied"
+[ $E -gt 0 ] && echo "$E warnings"
+
diff --git a/scripts/android_rules.xml b/scripts/android_rules.xml
index 8e4f7a2..4698671 100644
--- a/scripts/android_rules.xml
+++ b/scripts/android_rules.xml
@@ -1,6 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<project name="android_rules" default="debug">
+ <!--
+ This rules file is meant to be imported by the custom Ant task:
+ com.android.ant.AndroidInitTask
+
+ The following properties are put in place by the importing task:
+ android-jar, android-aidl, aapt, aidl, and dx
+
+ Additionnaly, the task sets up the following classpath reference:
+ android.target.classpath
+ This is used by the compiler task as the boot classpath.
+ -->
+
<property name="android-tools" value="${sdk-location}/tools" />
<!-- Input directories -->
@@ -55,13 +67,10 @@
<condition property="exe" value="exe" else=""><os family="windows"/></condition>
<condition property="bat" value="bat" else=""><os family="windows"/></condition>
- <property name="aapt" value="${android-tools}/aapt${exe}"/>
- <property name="aidl" value="${android-tools}/aidl${exe}"/>
<property name="adb" value="${android-tools}/adb${exe}"/>
- <property name="dx" value="${android-tools}/dx${bat}"/>
<property name="apk-builder" value="${android-tools}/apkbuilder${bat}"/>
- <!-- rules -->
+ <!-- rules -->
<!-- Create the output directories if they don't exist yet. -->
<target name="dirs">
diff --git a/sdkmanager/app/src/com/android/sdkmanager/Main.java b/sdkmanager/app/src/com/android/sdkmanager/Main.java
index 3370e76..1a15fce 100644
--- a/sdkmanager/app/src/com/android/sdkmanager/Main.java
+++ b/sdkmanager/app/src/com/android/sdkmanager/Main.java
@@ -356,6 +356,7 @@ class Main {
*/
private void displaySkinList(IAndroidTarget target, String message) {
String[] skins = target.getSkins();
+ String defaultSkin = target.getDefaultSkin();
mSdkLog.printf(message);
if (skins != null) {
boolean first = true;
@@ -366,6 +367,10 @@ class Main {
first = false;
}
mSdkLog.printf(skin);
+
+ if (skin.equals(defaultSkin)) {
+ mSdkLog.printf(" (default)");
+ }
}
mSdkLog.printf("\n");
} else {
@@ -385,7 +390,7 @@ class Main {
int index = 1;
for (AvdInfo info : avdManager.getAvds()) {
mSdkLog.printf("[%d] %s\n", index, info.getName());
- mSdkLog.printf(" Path: %s\n", info.getPath());
+ mSdkLog.printf(" Path: %s\n", info.getPath());
// get the target of the AVD
IAndroidTarget target = info.getTarget();
@@ -395,9 +400,23 @@ class Main {
} else {
mSdkLog.printf(" Target: %s (%s)\n", target.getName(), target
.getVendor());
- mSdkLog.printf(" Based on Android %s (API level %d)\n", target
+ mSdkLog.printf(" Based on Android %s (API level %d)\n", target
.getApiVersionName(), target.getApiVersionNumber());
}
+
+ // display some extra values.
+ Map<String, String> properties = info.getProperties();
+ String skin = properties.get(AvdManager.AVD_INI_SKIN_NAME);
+ if (skin != null) {
+ mSdkLog.printf(" Skin: %s\n", skin);
+ }
+ String sdcard = properties.get(AvdManager.AVD_INI_SDCARD_SIZE);
+ if (sdcard == null) {
+ sdcard = properties.get(AvdManager.AVD_INI_SDCARD_PATH);
+ }
+ if (sdcard != null) {
+ mSdkLog.printf(" Sdcard: %s\n", sdcard);
+ }
index++;
}
@@ -489,7 +508,7 @@ class Main {
return;
}
}
-
+
AvdInfo newAvdInfo = avdManager.createAvd(avdFolder,
avdName,
target,
diff --git a/sdkmanager/libs/sdklib/src/com/android/sdklib/AddOnTarget.java b/sdkmanager/libs/sdklib/src/com/android/sdklib/AddOnTarget.java
index ada61f7..0a59107 100644
--- a/sdkmanager/libs/sdklib/src/com/android/sdklib/AddOnTarget.java
+++ b/sdkmanager/libs/sdklib/src/com/android/sdklib/AddOnTarget.java
@@ -69,6 +69,7 @@ final class AddOnTarget implements IAndroidTarget {
private final String mVendor;
private final String mDescription;
private String[] mSkins;
+ private String mDefaultSkin;
private IOptionalLibrary[] mLibraries;
/**
@@ -141,6 +142,10 @@ final class AddOnTarget implements IAndroidTarget {
return false;
}
+ public IAndroidTarget getParent() {
+ return mBasePlatform;
+ }
+
public String getPath(int pathId) {
switch (pathId) {
case IMAGES:
@@ -157,6 +162,10 @@ final class AddOnTarget implements IAndroidTarget {
public String[] getSkins() {
return mSkins;
}
+
+ public String getDefaultSkin() {
+ return mDefaultSkin;
+ }
public IOptionalLibrary[] getOptionalLibraries() {
return mLibraries;
@@ -236,7 +245,9 @@ final class AddOnTarget implements IAndroidTarget {
// ---- local methods.
- public void setSkins(String[] skins) {
+ public void setSkins(String[] skins, String defaultSkin) {
+ mDefaultSkin = defaultSkin;
+
// we mix the add-on and base platform skins
HashSet<String> skinSet = new HashSet<String>();
skinSet.addAll(Arrays.asList(skins));
diff --git a/sdkmanager/libs/sdklib/src/com/android/sdklib/IAndroidTarget.java b/sdkmanager/libs/sdklib/src/com/android/sdklib/IAndroidTarget.java
index acf1187..fa462bd 100644
--- a/sdkmanager/libs/sdklib/src/com/android/sdklib/IAndroidTarget.java
+++ b/sdkmanager/libs/sdklib/src/com/android/sdklib/IAndroidTarget.java
@@ -60,6 +60,14 @@ public interface IAndroidTarget extends Comparable<IAndroidTarget> {
public static int SOURCES = 18;
/** OS Path to the target specific docs */
public static int DOCS = 19;
+ /** OS Path to the target's version of the aapt tool. */
+ public static int AAPT = 20;
+ /** OS Path to the target's version of the aidl tool. */
+ public static int AIDL = 21;
+ /** OS Path to the target's version of the dx too. */
+ public static int DX = 22;
+ /** OS Path to the target's version of the dx.jar file. */
+ public static int DX_JAR = 23;
public interface IOptionalLibrary {
String getName();
@@ -109,6 +117,12 @@ public interface IAndroidTarget extends Comparable<IAndroidTarget> {
boolean isPlatform();
/**
+ * Returns the parent target. This is likely to only be non <code>null</code> if
+ * {@link #isPlatform()} returns <code>false</code>
+ */
+ IAndroidTarget getParent();
+
+ /**
* Returns the path of a platform component.
* @param pathId the id representing the path to return. Any of the constants defined in the
* {@link IAndroidTarget} interface can be used.
@@ -121,6 +135,11 @@ public interface IAndroidTarget extends Comparable<IAndroidTarget> {
String[] getSkins();
/**
+ * Returns the default skin for this target.
+ */
+ String getDefaultSkin();
+
+ /**
* Returns the available optional libraries for this target.
* @return an array of optional libraries or <code>null</code> if there is none.
*/
diff --git a/sdkmanager/libs/sdklib/src/com/android/sdklib/PlatformTarget.java b/sdkmanager/libs/sdklib/src/com/android/sdklib/PlatformTarget.java
index 59fa81c..a3da70e 100644
--- a/sdkmanager/libs/sdklib/src/com/android/sdklib/PlatformTarget.java
+++ b/sdkmanager/libs/sdklib/src/com/android/sdklib/PlatformTarget.java
@@ -75,8 +75,13 @@ final class PlatformTarget implements IAndroidTarget {
SdkConstants.FN_INTENT_ACTIONS_SERVICE);
mPaths.put(CATEGORIES, mLocation + SdkConstants.OS_PLATFORM_DATA_FOLDER +
SdkConstants.FN_INTENT_CATEGORIES);
+ mPaths.put(AAPT, mLocation + SdkConstants.OS_SDK_TOOLS_FOLDER + SdkConstants.FN_AAPT);
+ mPaths.put(AIDL, mLocation + SdkConstants.OS_SDK_TOOLS_FOLDER + SdkConstants.FN_AIDL);
+ mPaths.put(DX, mLocation + SdkConstants.OS_SDK_TOOLS_FOLDER + SdkConstants.FN_DX);
+ mPaths.put(DX_JAR, mLocation + SdkConstants.OS_SDK_TOOLS_LIB_FOLDER +
+ SdkConstants.FN_DX_JAR);
}
-
+
public String getLocation() {
return mLocation;
}
@@ -123,6 +128,10 @@ final class PlatformTarget implements IAndroidTarget {
return true;
}
+ public IAndroidTarget getParent() {
+ return null;
+ }
+
public String getPath(int pathId) {
return mPaths.get(pathId);
}
@@ -130,6 +139,11 @@ final class PlatformTarget implements IAndroidTarget {
public String[] getSkins() {
return mSkins;
}
+
+ public String getDefaultSkin() {
+ // at this time, this is the default skin for all the platform.
+ return "HVGA";
+ }
/*
* Always returns null, as a standard platforms have no optional libraries.
diff --git a/sdkmanager/libs/sdklib/src/com/android/sdklib/SdkConstants.java b/sdkmanager/libs/sdklib/src/com/android/sdklib/SdkConstants.java
index b79dedb..87f9b56 100644
--- a/sdkmanager/libs/sdklib/src/com/android/sdklib/SdkConstants.java
+++ b/sdkmanager/libs/sdklib/src/com/android/sdklib/SdkConstants.java
@@ -30,7 +30,18 @@ import java.io.File;
*
*/
public final class SdkConstants {
+ public final static int PLATFORM_UNKNOWN = 0;
+ public final static int PLATFORM_LINUX = 1;
+ public final static int PLATFORM_WINDOWS = 2;
+ public final static int PLATFORM_DARWIN = 3;
+ /**
+ * Returns current platform, one of {@link #PLATFORM_WINDOWS}, {@link #PLATFORM_DARWIN},
+ * {@link #PLATFORM_LINUX} or {@link #PLATFORM_UNKNOWN}.
+ */
+ public final static int CURRENT_PLATFORM = currentPlatform();
+
+
/** An SDK Project's AndroidManifest.xml file */
public static final String FN_ANDROID_MANIFEST_XML= "AndroidManifest.xml";
/** An SDK Project's build.xml file */
@@ -69,6 +80,21 @@ public final class SdkConstants {
/** Skin layout file */
public final static String FN_SKIN_LAYOUT = "layout";//$NON-NLS-1$
+ /** dex.jar file */
+ public static final String FN_DX_JAR = "dx.jar"; //$NON-NLS-1$
+
+ /** dx executable */
+ public final static String FN_DX = (CURRENT_PLATFORM == PLATFORM_WINDOWS) ?
+ "dx.bat" : "dx"; //$NON-NLS-1$ //$NON-NLS-2$
+
+ /** aapt executable */
+ public final static String FN_AAPT = (CURRENT_PLATFORM == PLATFORM_WINDOWS) ?
+ "aapt.exe" : "aapt"; //$NON-NLS-1$ //$NON-NLS-2$
+
+ /** aidl executable */
+ public final static String FN_AIDL = (CURRENT_PLATFORM == PLATFORM_WINDOWS) ?
+ "aidl.exe" : "aidl"; //$NON-NLS-1$ //$NON-NLS-2$
+
/* Folder Names for Android Projects . */
/** Resources folder name, i.e. "res". */
@@ -142,11 +168,11 @@ public final class SdkConstants {
* 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.
+ /** Path of the tools directory relative to the sdk folder, or to a platform 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.
+ /** Path of the lib directory relative to the sdk folder, or to a platform 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;
@@ -233,4 +259,22 @@ public final class SdkConstants {
return cmd;
}
+ /**
+ * Returns current platform
+ *
+ * @return one of {@link #PLATFORM_WINDOWS}, {@link #PLATFORM_DARWIN},
+ * {@link #PLATFORM_LINUX} or {@link #PLATFORM_UNKNOWN}.
+ */
+ private static int currentPlatform() {
+ String os = System.getProperty("os.name"); //$NON-NLS-1$
+ if (os.startsWith("Mac OS")) { //$NON-NLS-1$
+ return PLATFORM_DARWIN;
+ } else if (os.startsWith("Windows")) { //$NON-NLS-1$
+ return PLATFORM_WINDOWS;
+ } else if (os.startsWith("Linux")) { //$NON-NLS-1$
+ return PLATFORM_LINUX;
+ }
+
+ return PLATFORM_UNKNOWN;
+ }
}
diff --git a/sdkmanager/libs/sdklib/src/com/android/sdklib/SdkManager.java b/sdkmanager/libs/sdklib/src/com/android/sdklib/SdkManager.java
index f6fb622..28227c6 100644
--- a/sdkmanager/libs/sdklib/src/com/android/sdklib/SdkManager.java
+++ b/sdkmanager/libs/sdklib/src/com/android/sdklib/SdkManager.java
@@ -44,6 +44,7 @@ public final class SdkManager {
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 Pattern PATTERN_PROP = Pattern.compile(
"^([a-zA-Z0-9._-]+)\\s*=\\s*(.*)\\s*$");
@@ -51,6 +52,17 @@ public final class SdkManager {
private final static Pattern PATTERN_LIB_DATA = Pattern.compile(
"^([a-zA-Z0-9._-]+\\.jar);(.*)$", Pattern.CASE_INSENSITIVE);
+ /** List of items in the platform to check when parsing it. These paths are relative to the
+ * platform root folder. */
+ private final static String[] sPlatformContentList = new String[] {
+ SdkConstants.FN_FRAMEWORK_LIBRARY,
+ SdkConstants.FN_FRAMEWORK_AIDL,
+ SdkConstants.OS_SDK_TOOLS_FOLDER + SdkConstants.FN_AAPT,
+ SdkConstants.OS_SDK_TOOLS_FOLDER + SdkConstants.FN_AIDL,
+ SdkConstants.OS_SDK_TOOLS_FOLDER + SdkConstants.FN_DX,
+ SdkConstants.OS_SDK_TOOLS_LIB_FOLDER + SdkConstants.FN_DX_JAR,
+ };
+
/** the location of the SDK */
private final String mSdkLocation;
private IAndroidTarget[] mTargets;
@@ -176,6 +188,10 @@ public final class SdkManager {
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(),
@@ -351,7 +367,19 @@ public final class SdkManager {
// need to parse the skins.
String[] skins = parseSkinFolder(target.getPath(IAndroidTarget.SKINS));
- target.setSkins(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;
}
@@ -369,7 +397,28 @@ public final class SdkManager {
addonName, valueName, SdkConstants.FN_MANIFEST_INI);
}
}
+
+ /**
+ * Checks the given platform has all the required files, and returns true if they are all
+ * present.
+ * <p/>This checks the presence of the following files: android.jar, framework.aidl, aapt(.exe),
+ * aidl(.exe), dx(.bat), and dx.jar
+ */
+ private boolean checkPlatformContent(File platform, ISdkLog log) {
+ 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;
+ }
+
/**
* Parses a property file and returns
* @param buildProp the property file to parse
diff --git a/sdkmanager/libs/sdklib/src/com/android/sdklib/avd/AvdManager.java b/sdkmanager/libs/sdklib/src/com/android/sdklib/avd/AvdManager.java
index d466182..b44cf01 100644
--- a/sdkmanager/libs/sdklib/src/com/android/sdklib/avd/AvdManager.java
+++ b/sdkmanager/libs/sdklib/src/com/android/sdklib/avd/AvdManager.java
@@ -44,28 +44,42 @@ import java.util.regex.Pattern;
public final class AvdManager {
public static final String AVD_FOLDER_EXTENSION = ".avd";
+
private final static String AVD_INFO_PATH = "path";
private final static String AVD_INFO_TARGET = "target";
-
- private final static String IMAGE_USERDATA = "userdata.img";
+
+ public final static String AVD_INI_SKIN_PATH = "skin.path";
+ public final static String AVD_INI_SKIN_NAME = "skin.name";
+ public final static String AVD_INI_SDCARD_PATH = "sdcard.path";
+ public final static String AVD_INI_SDCARD_SIZE = "sdcard.size";
+ public final static String AVD_INI_IMAGES_1 = "image.sysdir.1";
+ public final static String AVD_INI_IMAGES_2 = "image.sysdir.2";
+
+ private final static String USERDATA_IMG = "userdata.img";
private final static String CONFIG_INI = "config.ini";
+ private final static String SDCARD_IMG = "sdcard.img";
- private final static Pattern INI_NAME_PATTERN = Pattern.compile("(.+)\\.ini$",
+ private final static String INI_EXTENSION = ".ini";
+ private final static Pattern INI_NAME_PATTERN = Pattern.compile("(.+)\\" + INI_EXTENSION + "$",
Pattern.CASE_INSENSITIVE);
private final static Pattern SDCARD_SIZE_PATTERN = Pattern.compile("\\d+[MK]?");
/** An immutable structure describing an Android Virtual Device. */
public static final class AvdInfo {
- private String mName;
- private String mPath;
- private IAndroidTarget mTarget;
+ private final String mName;
+ private final String mPath;
+ private final IAndroidTarget mTarget;
+ private final Map<String, String> mProperties;
- /** Creates a new AVD info. Valures are immutable. */
- public AvdInfo(String name, String path, IAndroidTarget target) {
+ /** Creates a new AVD info. Valures are immutable.
+ * @param properties */
+ public AvdInfo(String name, String path, IAndroidTarget target,
+ Map<String, String> properties) {
mName = name;
mPath = path;
mTarget = target;
+ mProperties = properties;
}
/** Returns the name of the AVD. */
@@ -90,7 +104,7 @@ public final class AvdManager {
public static File getIniFile(String name) throws AndroidLocationException {
String avdRoot;
avdRoot = AndroidLocation.getFolder() + AndroidLocation.FOLDER_AVD;
- return new File(avdRoot, name + ".ini");
+ return new File(avdRoot, name + INI_EXTENSION);
}
/**
@@ -100,6 +114,13 @@ public final class AvdManager {
public File getIniFile() throws AndroidLocationException {
return getIniFile(mName);
}
+
+ /**
+ * Returns a map of properties for the AVD.
+ */
+ public Map<String, String> getProperties() {
+ return mProperties;
+ }
}
private final ArrayList<AvdInfo> mAvdList = new ArrayList<AvdInfo>();
@@ -149,6 +170,8 @@ public final class AvdManager {
String skinName, String sdcard, Map<String,String> hardwareConfig,
boolean removePrevious, ISdkLog log) {
+ File iniFile = null;
+ boolean needCleanup = false;
try {
if (avdFolder.exists()) {
if (removePrevious) {
@@ -170,14 +193,27 @@ public final class AvdManager {
}
// actually write the ini file
- createAvdIniFile(name, avdFolder, target);
+ iniFile = createAvdIniFile(name, avdFolder, target);
// writes the userdata.img in it.
String imagePath = target.getPath(IAndroidTarget.IMAGES);
- File userdataSrc = new File(imagePath, IMAGE_USERDATA);
+ File userdataSrc = new File(imagePath, USERDATA_IMG);
+
+ if (userdataSrc.exists() == false && target.isPlatform() == false) {
+ imagePath = target.getParent().getPath(IAndroidTarget.IMAGES);
+ userdataSrc = new File(imagePath, USERDATA_IMG);
+ }
+
+ if (userdataSrc.exists() == false) {
+ log.error(null, "Unable to find a '%1$s' file to copy into the AVD folder.",
+ USERDATA_IMG);
+ needCleanup = true;
+ return null;
+ }
+
FileInputStream fis = new FileInputStream(userdataSrc);
- File userdataDest = new File(avdFolder, IMAGE_USERDATA);
+ File userdataDest = new File(avdFolder, USERDATA_IMG);
FileOutputStream fos = new FileOutputStream(userdataDest);
byte[] buffer = new byte[4096];
@@ -189,23 +225,61 @@ public final class AvdManager {
fos.close();
fis.close();
- // Config file
+ // Config file.
HashMap<String, String> values = new HashMap<String, String>();
- if (skinName != null) {
- // assume skin name is valid
- values.put("skin", skinName);
+
+ // First the image folders of the target itself
+ imagePath = getImageRelativePath(target, log);
+ if (imagePath == null) {
+ needCleanup = true;
+ return null;
}
+
+ values.put(AVD_INI_IMAGES_1, imagePath);
+
+ // If the target is an add-on we need to add the Platform image as a backup.
+ IAndroidTarget parent = target.getParent();
+ if (parent != null) {
+ imagePath = getImageRelativePath(parent, log);
+ if (imagePath == null) {
+ needCleanup = true;
+ return null;
+ }
+
+ values.put(AVD_INI_IMAGES_2, imagePath);
+ }
+
+
+ // Now the skin.
+ if (skinName == null) {
+ skinName = target.getDefaultSkin();
+ }
+
+ // get the path of the skin (relative to the SDK)
+ // assume skin name is valid
+ String skinPath = getSkinRelativePath(skinName, target, log);
+ if (skinPath == null) {
+ needCleanup = true;
+ return null;
+ }
+
+ values.put(AVD_INI_SKIN_PATH, skinPath);
+ values.put(AVD_INI_SKIN_NAME, skinName);
if (sdcard != null) {
File sdcardFile = new File(sdcard);
if (sdcardFile.isFile()) {
- values.put("sdcard", sdcard);
+ // sdcard value is an external sdcard, so we put its path into the config.ini
+ values.put(AVD_INI_SDCARD_PATH, sdcard);
} else {
- // check that it matches the pattern for sdcard size
+ // Sdcard is possibly a size. In that case we create a file called 'sdcard.img'
+ // in the AVD folder, and do not put any value in config.ini.
+
+ // First, check that it matches the pattern for sdcard size
Matcher m = SDCARD_SIZE_PATTERN.matcher(sdcard);
if (m.matches()) {
// create the sdcard.
- sdcardFile = new File(avdFolder, "sdcard.img");
+ sdcardFile = new File(avdFolder, SDCARD_IMG);
String path = sdcardFile.getAbsolutePath();
// execute mksdcard with the proper parameters.
@@ -215,18 +289,27 @@ public final class AvdManager {
if (mkSdCard.isFile() == false) {
log.error(null, "'%1$s' is missing from the SDK tools folder.",
mkSdCard.getName());
+ needCleanup = true;
return null;
}
if (createSdCard(mkSdCard.getAbsolutePath(), sdcard, path, log) == false) {
+ needCleanup = true;
return null; // mksdcard output has already been displayed, no need to
// output anything else.
}
- // add its path to the values.
- values.put("sdcard", path);
+ // add a property containing the size of the sdcard for display purpose
+ // only when the dev does 'android list avd'
+ values.put(AVD_INI_SDCARD_SIZE, sdcard);
} else {
- log.error(null, "'%1$s' is not recognized as a valid sdcard value", sdcard);
+ log.error(null,
+ "'%1$s' is not recognized as a valid sdcard value.\n" +
+ "Value should be:\n" +
+ "1. path to an sdcard.\n" +
+ "2. size of the sdcard to create: <size>[K|M]",
+ sdcard);
+ needCleanup = true;
return null;
}
}
@@ -249,7 +332,7 @@ public final class AvdManager {
}
// create the AvdInfo object, and add it to the list
- AvdInfo avdInfo = new AvdInfo(name, avdFolder.getAbsolutePath(), target);
+ AvdInfo avdInfo = new AvdInfo(name, avdFolder.getAbsolutePath(), target, values);
mAvdList.add(avdInfo);
@@ -262,12 +345,84 @@ public final class AvdManager {
if (log != null) {
log.error(e, null);
}
+ } finally {
+ if (needCleanup) {
+ if (iniFile != null && iniFile.exists()) {
+ iniFile.delete();
+ }
+
+ recursiveDelete(avdFolder);
+ avdFolder.delete();
+ }
}
return null;
}
/**
+ * Returns the path to the target images folder as a relative path to the SDK.
+ */
+ private String getImageRelativePath(IAndroidTarget target, ISdkLog log) {
+ String imageFullPath = target.getPath(IAndroidTarget.IMAGES);
+
+ // make this path relative to the SDK location
+ String sdkLocation = mSdk.getLocation();
+ if (imageFullPath.startsWith(sdkLocation) == false) {
+ // this really really should not happen.
+ log.error(null, "Target location is not inside the SDK.");
+ assert false;
+ return null;
+ }
+
+ imageFullPath = imageFullPath.substring(sdkLocation.length());
+ if (imageFullPath.charAt(0) == File.separatorChar) {
+ imageFullPath = imageFullPath.substring(1);
+ }
+ return imageFullPath;
+ }
+
+ /**
+ * Returns the path to the skin, as a relative path to the SDK.
+ */
+ private String getSkinRelativePath(String skinName, IAndroidTarget target, ISdkLog log) {
+ // first look to see if the skin is in the target
+
+ String path = target.getPath(IAndroidTarget.SKINS);
+ File skin = new File(path, skinName);
+
+ if (skin.exists() == false && target.isPlatform() == false) {
+ target = target.getParent();
+
+ path = target.getPath(IAndroidTarget.SKINS);
+ skin = new File(path, skinName);
+ }
+
+ // skin really does not exist!
+ if (skin.exists() == false) {
+ log.error(null, "Skin '%1$s' does not exist.", skinName);
+ return null;
+ }
+
+ // get the skin path
+ path = skin.getAbsolutePath();
+
+ // make this path relative to the SDK location
+ String sdkLocation = mSdk.getLocation();
+ if (path.startsWith(sdkLocation) == false) {
+ // this really really should not happen.
+ log.error(null, "Target location is not inside the SDK.");
+ assert false;
+ return null;
+ }
+
+ path = path.substring(sdkLocation.length());
+ if (path.charAt(0) == File.separatorChar) {
+ path = path.substring(1);
+ }
+ return path;
+ }
+
+ /**
* Creates the ini file for an AVD.
*
* @param name of the AVD.
@@ -276,13 +431,15 @@ public final class AvdManager {
* @throws AndroidLocationException if there's a problem getting android root directory.
* @throws IOException if {@link File#getAbsolutePath()} fails.
*/
- private void createAvdIniFile(String name, File avdFolder, IAndroidTarget target)
+ private File createAvdIniFile(String name, File avdFolder, IAndroidTarget target)
throws AndroidLocationException, IOException {
HashMap<String, String> values = new HashMap<String, String>();
File iniFile = AvdInfo.getIniFile(name);
values.put(AVD_INFO_PATH, avdFolder.getAbsolutePath());
values.put(AVD_INFO_TARGET, target.hashString());
createConfigIni(iniFile, values);
+
+ return iniFile;
}
/**
@@ -292,8 +449,8 @@ public final class AvdManager {
* @throws AndroidLocationException if there's a problem getting android root directory.
* @throws IOException if {@link File#getAbsolutePath()} fails.
*/
- private void createAvdIniFile(AvdInfo info) throws AndroidLocationException, IOException {
- createAvdIniFile(info.getName(), new File(info.getPath()), info.getTarget());
+ private File createAvdIniFile(AvdInfo info) throws AndroidLocationException, IOException {
+ return createAvdIniFile(info.getName(), new File(info.getPath()), info.getTarget());
}
/**
@@ -306,8 +463,6 @@ public final class AvdManager {
*/
public void deleteAvd(AvdInfo avdInfo, ISdkLog log) {
try {
- String avdRoot = AndroidLocation.getFolder() + AndroidLocation.FOLDER_AVD;
-
File f = avdInfo.getIniFile();
if (f.exists()) {
log.warning("Deleting file %s", f.getCanonicalPath());
@@ -359,7 +514,8 @@ public final class AvdManager {
}
// update avd info
- AvdInfo info = new AvdInfo(avdInfo.getName(), paramFolderPath, avdInfo.getTarget());
+ AvdInfo info = new AvdInfo(avdInfo.getName(), paramFolderPath, avdInfo.getTarget(),
+ avdInfo.getProperties());
mAvdList.remove(avdInfo);
mAvdList.add(info);
avdInfo = info;
@@ -380,7 +536,8 @@ public final class AvdManager {
}
// update avd info
- AvdInfo info = new AvdInfo(newName, avdInfo.getPath(), avdInfo.getTarget());
+ AvdInfo info = new AvdInfo(newName, avdInfo.getPath(), avdInfo.getTarget(),
+ avdInfo.getProperties());
mAvdList.remove(avdInfo);
mAvdList.add(info);
}
@@ -458,18 +615,22 @@ public final class AvdManager {
if (target == null) {
return null;
}
+
+ // load the avd properties.
+ File configIniFile = new File(avdPath, CONFIG_INI);
+ Map<String, String> properties = SdkManager.parsePropertyFile(configIniFile, mSdkLog);
Matcher matcher = INI_NAME_PATTERN.matcher(path.getName());
AvdInfo info = new AvdInfo(
matcher.matches() ? matcher.group(1) : path.getName(), // should not happen
avdPath,
- target
- );
+ target,
+ properties);
return info;
}
-
+
private static void createConfigIni(File iniFile, Map<String, String> values)
throws IOException {
FileWriter writer = new FileWriter(iniFile);
diff --git a/sdkmanager/libs/sdklib/src/com/android/sdklib/project/ProjectProperties.java b/sdkmanager/libs/sdklib/src/com/android/sdklib/project/ProjectProperties.java
index 4e1c27f..1f6a047 100644
--- a/sdkmanager/libs/sdklib/src/com/android/sdklib/project/ProjectProperties.java
+++ b/sdkmanager/libs/sdklib/src/com/android/sdklib/project/ProjectProperties.java
@@ -33,6 +33,7 @@ import java.util.Map.Entry;
public final class ProjectProperties {
/** The property name for the project target */
public final static String PROPERTY_TARGET = "target";
+ public final static String PROPERTY_CONFIGS = "configs";
public final static String PROPERTY_SDK = "sdk-location";
public static enum PropertyType {
@@ -201,6 +202,14 @@ public final class ProjectProperties {
public String getProperty(String name) {
return mProperties.get(name);
}
+
+ /**
+ * Removes a property and returns its previous value (or null if the property did not exist).
+ * @param name the name of the property to remove.
+ */
+ public String removeProperty(String name) {
+ return mProperties.remove(name);
+ }
/**
* Saves the property file.