aboutsummaryrefslogtreecommitdiffstats
path: root/anttasks/src
diff options
context:
space:
mode:
Diffstat (limited to 'anttasks/src')
-rw-r--r--anttasks/src/com/android/ant/AaptExecLoopTask.java237
-rw-r--r--anttasks/src/com/android/ant/ApkBuilderTask.java111
-rw-r--r--anttasks/src/com/android/ant/SetupTask.java88
-rw-r--r--anttasks/src/com/android/ant/TaskHelper.java33
4 files changed, 369 insertions, 100 deletions
diff --git a/anttasks/src/com/android/ant/AaptExecLoopTask.java b/anttasks/src/com/android/ant/AaptExecLoopTask.java
index 6610d23..afe4d35 100644
--- a/anttasks/src/com/android/ant/AaptExecLoopTask.java
+++ b/anttasks/src/com/android/ant/AaptExecLoopTask.java
@@ -34,9 +34,26 @@ import java.util.Map.Entry;
/**
* Task able to run an Exec task on aapt several times.
- * It does not follow the exec task format, instead it has its own parameters, which maps
- * directly to aapt.
+ * <p>It does not follow the exec task format, instead it has its own parameters, which maps
+ * directly to aapt.</p>
+ * <p>The following map shows how to use the task for each supported aapt command line
+ * parameter.</p>
*
+ * <table border="1">
+ * <tr><td><b>Aapt Option</b></td><td><b>Ant Name</b></td><td><b>Type</b></td></tr>
+ * <tr><td>path to aapt</td><td>executable</td><td>attribute (Path)</td>
+ * <tr><td>command</td><td>command</td><td>attribute (String)</td>
+ * <tr><td>-v</td><td>verbose</td><td>attribute (boolean)</td></tr>
+ * <tr><td>-f</td><td>force</td><td>attribute (boolean)</td></tr>
+ * <tr><td>-M AndroidManifest.xml</td><td>manifest</td><td>attribute (Path)</td></tr>
+ * <tr><td>-I base-package</td><td>androidjar</td><td>attribute (Path)</td></tr>
+ * <tr><td>-A asset-source-dir</td><td>assets</td><td>attribute (Path</td></tr>
+ * <tr><td>-S resource-sources</td><td>&lt;res path=""&gt;</td><td>nested element(s)<br>with attribute (Path)</td></tr>
+ * <tr><td>-0 extension</td><td>&lt;nocompress extension=""&gt;<br>&lt;nocompress&gt;</td><td>nested element(s)<br>with attribute (String)</td></tr>
+ * <tr><td>-F apk-file</td><td>apkfolder<br>outfolder<br>apkbasename<br>basename</td><td>attribute (Path)<br>attribute (Path) deprecated<br>attribute (String)<br>attribute (String) deprecated</td></tr>
+ * <tr><td>-J R-file-dir</td><td>rfolder</td><td>attribute (Path)<br>-m always enabled</td></tr>
+ * <tr><td></td><td></td><td></td></tr>
+ * </table>
*/
public final class AaptExecLoopTask extends Task {
@@ -61,20 +78,23 @@ public final class AaptExecLoopTask extends Task {
private String mExecutable;
private String mCommand;
+ private boolean mForce = true; // true due to legacy reasons
+ private boolean mVerbose = false;
private String mManifest;
- private String mResources;
+ private ArrayList<Path> mResources;
private String mAssets;
private String mAndroidJar;
- private String mOutFolder;
- private String mBaseName;
+ private String mApkFolder;
+ private String mApkBaseName;
+ private String mRFolder;
private final ArrayList<NoCompress> mNoCompressList = new ArrayList<NoCompress>();
/**
* Sets the value of the "executable" attribute.
* @param executable the value.
*/
- public void setExecutable(String executable) {
- mExecutable = executable;
+ public void setExecutable(Path executable) {
+ mExecutable = TaskHelper.checkSinglePath("executable", executable);
}
/**
@@ -86,19 +106,42 @@ public final class AaptExecLoopTask extends Task {
}
/**
+ * Sets the value of the "force" attribute.
+ * @param force the value.
+ */
+ public void setForce(boolean force) {
+ mForce = force;
+ }
+
+ /**
+ * Sets the value of the "verbose" attribute.
+ * @param verbose the value.
+ */
+ public void setVerbose(boolean verbose) {
+ mVerbose = verbose;
+ }
+
+ /**
* Sets the value of the "manifest" attribute.
* @param manifest the value.
*/
public void setManifest(Path manifest) {
- mManifest = manifest.toString();
+ mManifest = TaskHelper.checkSinglePath("manifest", manifest);
}
/**
* Sets the value of the "resources" attribute.
* @param resources the value.
+ *
+ * @deprecated Uses nested element(s) <res path="value" />
*/
+ @Deprecated
public void setResources(Path resources) {
- mResources = resources.toString();
+ if (mResources == null) {
+ mResources = new ArrayList<Path>();
+ }
+
+ mResources.add(new Path(getProject(), resources.toString()));
}
/**
@@ -106,7 +149,7 @@ public final class AaptExecLoopTask extends Task {
* @param assets the value.
*/
public void setAssets(Path assets) {
- mAssets = assets.toString();
+ mAssets = TaskHelper.checkSinglePath("assets", assets);
}
/**
@@ -114,23 +157,51 @@ public final class AaptExecLoopTask extends Task {
* @param androidJar the value.
*/
public void setAndroidjar(Path androidJar) {
- mAndroidJar = androidJar.toString();
+ mAndroidJar = TaskHelper.checkSinglePath("androidjar", androidJar);
}
/**
* Sets the value of the "outfolder" attribute.
* @param outFolder the value.
+ * @deprecated use {@link #setApkfolder(Path)}
*/
+ @Deprecated
public void setOutfolder(Path outFolder) {
- mOutFolder = outFolder.toString();
+ mApkFolder = TaskHelper.checkSinglePath("outfolder", outFolder);
+ }
+
+ /**
+ * Sets the value of the "apkfolder" attribute.
+ * @param apkFolder the value.
+ */
+ public void setApkfolder(Path apkFolder) {
+ mApkFolder = TaskHelper.checkSinglePath("apkfolder", apkFolder);
}
/**
* Sets the value of the "basename" attribute.
* @param baseName the value.
+ * @deprecated use {@link #setApkbasename(String)}
*/
+ @Deprecated
public void setBasename(String baseName) {
- mBaseName = baseName;
+ mApkBaseName = baseName;
+ }
+
+ /**
+ * Sets the value of the "apkbasename" attribute.
+ * @param apkbaseName the value.
+ */
+ public void setApkbasename(String apkbaseName) {
+ mApkBaseName = apkbaseName;
+ }
+
+ /**
+ * Sets the value of the "rfolder" attribute.
+ * @param rFolder the value.
+ */
+ public void setRfolder(Path rFolder) {
+ mRFolder = TaskHelper.checkSinglePath("rfolder", rFolder);
}
/**
@@ -142,6 +213,20 @@ public final class AaptExecLoopTask extends Task {
return nc;
}
+ /**
+ * Returns an object representing a nested <var>res</var> element.
+ */
+ public Object createRes() {
+ if (mResources == null) {
+ mResources = new ArrayList<Path>();
+ }
+
+ Path path = new Path(getProject());
+ mResources.add(path);
+
+ return path;
+ }
+
/*
* (non-Javadoc)
*
@@ -155,7 +240,25 @@ public final class AaptExecLoopTask extends Task {
Project taskProject = getProject();
// first do a full resource package
- createPackage(null /*configName*/, null /*resourceFilter*/);
+ createPackage(null /*configName*/, null /*resourceFilter*/, null /*customPackage*/);
+
+ if (mRFolder != null && new File(mRFolder).isDirectory()) {
+ String libPkgProp = taskProject.getProperty("android.libraries.package");
+ if (libPkgProp != null) {
+ // get the main package to compare in case the libraries use the same
+ String mainPackage = taskProject.getProperty("manifest.package");
+
+ String[] libPkgs = libPkgProp.split(";");
+ for (String libPkg : libPkgs) {
+ if (libPkg.length() > 0 && mainPackage.equals(libPkg) == false) {
+ // FIXME: instead of recreating R.java from scratch, maybe copy
+ // the files (R.java and manifest.java)? This would force to replace
+ // the package line on the fly.
+ createPackage(null, null, libPkg);
+ }
+ }
+ }
+ }
// now see if we need to create file with filtered resources.
// Get the project base directory.
@@ -169,7 +272,7 @@ public final class AaptExecLoopTask extends Task {
Map<String, String> apkFilters = apkSettings.getResourceFilters();
if (apkFilters.size() > 0) {
for (Entry<String, String> entry : apkFilters.entrySet()) {
- createPackage(entry.getKey(), entry.getValue());
+ createPackage(entry.getKey(), entry.getValue(), null /*custom package*/);
}
}
}
@@ -182,10 +285,13 @@ public final class AaptExecLoopTask extends Task {
* @param resourceFilter the resource configuration filter to pass to aapt (if configName is
* non null)
*/
- private void createPackage(String configName, String resourceFilter) {
+ private void createPackage(String configName, String resourceFilter, String customPackage) {
Project taskProject = getProject();
- if (configName == null || resourceFilter == null) {
+ final boolean generateRClass = mRFolder != null && new File(mRFolder).isDirectory();
+
+ if (generateRClass) {
+ } else if (configName == null || resourceFilter == null) {
System.out.println("Creating full resource package...");
} else {
System.out.println(String.format(
@@ -202,7 +308,18 @@ public final class AaptExecLoopTask extends Task {
task.createArg().setValue(mCommand);
// force flag
- task.createArg().setValue("-f");
+ if (mForce) {
+ task.createArg().setValue("-f");
+ }
+
+ // verbose flag
+ if (mVerbose) {
+ task.createArg().setValue("-v");
+ }
+
+ if (generateRClass) {
+ task.createArg().setValue("-m");
+ }
// filters if needed
if (configName != null && resourceFilter != null) {
@@ -229,39 +346,81 @@ public final class AaptExecLoopTask extends Task {
}
}
+ if (customPackage != null) {
+ task.createArg().setValue("--custom-package");
+ task.createArg().setValue(customPackage);
+ }
+
+ // if the project contains libraries, force auto-add-overlay
+ Object libSrc = taskProject.getReference("android.libraries.res");
+ if (libSrc != null) {
+ task.createArg().setValue("--auto-add-overlay");
+ }
+
// manifest location
- task.createArg().setValue("-M");
- task.createArg().setValue(mManifest);
-
- // resources location. This may not exists, and aapt doesn't like it, so we check first.
- File res = new File(mResources);
- if (res.isDirectory()) {
- task.createArg().setValue("-S");
- task.createArg().setValue(mResources);
+ if (mManifest != null) {
+ task.createArg().setValue("-M");
+ task.createArg().setValue(mManifest);
+ }
+
+ // resources locations.
+ if (mResources.size() > 0) {
+ for (Path pathList : mResources) {
+ for (String path : pathList.list()) {
+ // This may not exists, and aapt doesn't like it, so we check first.
+ File res = new File(path);
+ if (res.isDirectory()) {
+ task.createArg().setValue("-S");
+ task.createArg().setValue(path);
+ }
+ }
+ }
+ }
+
+ // add other resources coming from library project
+ Object libPath = taskProject.getReference("android.libraries.res");
+ if (libPath instanceof Path) {
+ for (String path : ((Path)libPath).list()) {
+ // This may not exists, and aapt doesn't like it, so we check first.
+ File res = new File(path);
+ if (res.isDirectory()) {
+ task.createArg().setValue("-S");
+ task.createArg().setValue(path);
+ }
+ }
}
// assets location. This may not exists, and aapt doesn't like it, so we check first.
- File assets = new File(mAssets);
- if (assets.isDirectory()) {
+ if (mAssets != null && new File(mAssets).isDirectory()) {
task.createArg().setValue("-A");
task.createArg().setValue(mAssets);
}
// android.jar
- task.createArg().setValue("-I");
- task.createArg().setValue(mAndroidJar);
+ if (mAndroidJar != null) {
+ task.createArg().setValue("-I");
+ task.createArg().setValue(mAndroidJar);
+ }
- // out file. This is based on the outFolder, baseName, and the configName (if applicable)
- String filename;
- if (configName != null && resourceFilter != null) {
- filename = mBaseName + "-" + configName + ".ap_";
- } else {
- filename = mBaseName + ".ap_";
+ // apk file. This is based on the apkFolder, apkBaseName, and the configName (if applicable)
+ if (mApkBaseName != null && mApkBaseName != null) {
+ String filename;
+ if (configName != null && resourceFilter != null) {
+ filename = mApkBaseName + "-" + configName + ".ap_";
+ } else {
+ filename = mApkBaseName + ".ap_";
+ }
+
+ File file = new File(mApkFolder, filename);
+ task.createArg().setValue("-F");
+ task.createArg().setValue(file.getAbsolutePath());
}
- File file = new File(mOutFolder, filename);
- task.createArg().setValue("-F");
- task.createArg().setValue(file.getAbsolutePath());
+ // R class generation
+ if (generateRClass) {
+ task.createArg().setValue("-J");
+ task.createArg().setValue(mRFolder);
+ }
// final setup of the task
task.setProject(taskProject);
diff --git a/anttasks/src/com/android/ant/ApkBuilderTask.java b/anttasks/src/com/android/ant/ApkBuilderTask.java
index b1e6d80..c326fa9 100644
--- a/anttasks/src/com/android/ant/ApkBuilderTask.java
+++ b/anttasks/src/com/android/ant/ApkBuilderTask.java
@@ -26,7 +26,6 @@ import com.android.sdklib.internal.project.ProjectProperties.PropertyType;
import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.Project;
-import org.apache.tools.ant.ProjectComponent;
import org.apache.tools.ant.Task;
import org.apache.tools.ant.types.Path;
import org.apache.tools.ant.types.Path.PathElement;
@@ -43,35 +42,18 @@ public class ApkBuilderTask extends Task {
// ref id to the <path> object containing all the boot classpaths.
private final static String REF_APK_PATH = "android.apks.path";
- /**
- * Class to represent nested elements. Since they all have only one attribute ('path'), the
- * same class can be used for all the nested elements (zip, file, sourcefolder, jarfolder,
- * nativefolder).
- */
- public final static class Value extends ProjectComponent {
- String mPath;
-
- /**
- * Sets the value of the "path" attribute.
- * @param path the value.
- */
- public void setPath(Path path) {
- mPath = path.toString();
- }
- }
-
private String mOutFolder;
private String mBaseName;
private boolean mVerbose = false;
private boolean mSigned = true;
private boolean mDebug = false;
- private final ArrayList<Value> mZipList = new ArrayList<Value>();
- private final ArrayList<Value> mFileList = new ArrayList<Value>();
- private final ArrayList<Value> mSourceList = new ArrayList<Value>();
- private final ArrayList<Value> mJarfolderList = new ArrayList<Value>();
- private final ArrayList<Value> mJarfileList = new ArrayList<Value>();
- private final ArrayList<Value> mNativeList = new ArrayList<Value>();
+ private final ArrayList<Path> mZipList = new ArrayList<Path>();
+ private final ArrayList<Path> mFileList = new ArrayList<Path>();
+ private final ArrayList<Path> mSourceList = new ArrayList<Path>();
+ private final ArrayList<Path> mJarfolderList = new ArrayList<Path>();
+ private final ArrayList<Path> mJarfileList = new ArrayList<Path>();
+ private final ArrayList<Path> mNativeList = new ArrayList<Path>();
private final ArrayList<FileInputStream> mZipArchives = new ArrayList<FileInputStream>();
private final ArrayList<File> mArchiveFiles = new ArrayList<File>();
@@ -84,7 +66,7 @@ public class ApkBuilderTask extends Task {
* @param outFolder the value.
*/
public void setOutfolder(Path outFolder) {
- mOutFolder = outFolder.toString();
+ mOutFolder = TaskHelper.checkSinglePath("outfolder", outFolder);
}
/**
@@ -123,54 +105,54 @@ public class ApkBuilderTask extends Task {
* Returns an object representing a nested <var>zip</var> element.
*/
public Object createZip() {
- Value zip = new Value();
- mZipList.add(zip);
- return zip;
+ Path path = new Path(getProject());
+ mZipList.add(path);
+ return path;
}
/**
* Returns an object representing a nested <var>file</var> element.
*/
public Object createFile() {
- Value file = new Value();
- mFileList.add(file);
- return file;
+ Path path = new Path(getProject());
+ mFileList.add(path);
+ return path;
}
/**
* Returns an object representing a nested <var>sourcefolder</var> element.
*/
public Object createSourcefolder() {
- Value file = new Value();
- mSourceList.add(file);
- return file;
+ Path path = new Path(getProject());
+ mSourceList.add(path);
+ return path;
}
/**
* Returns an object representing a nested <var>jarfolder</var> element.
*/
public Object createJarfolder() {
- Value file = new Value();
- mJarfolderList.add(file);
- return file;
+ Path path = new Path(getProject());
+ mJarfolderList.add(path);
+ return path;
}
/**
* Returns an object representing a nested <var>jarfile</var> element.
*/
public Object createJarfile() {
- Value file = new Value();
- mJarfileList.add(file);
- return file;
+ Path path = new Path(getProject());
+ mJarfileList.add(path);
+ return path;
}
/**
* Returns an object representing a nested <var>nativefolder</var> element.
*/
public Object createNativefolder() {
- Value file = new Value();
- mNativeList.add(file);
- return file;
+ Path path = new Path(getProject());
+ mNativeList.add(path);
+ return path;
}
@Override
@@ -187,37 +169,48 @@ public class ApkBuilderTask extends Task {
// go through the list of zip files to add. This will not include
// the resource package, which is handled separaly for each apk to create.
- for (Value v : mZipList) {
- FileInputStream input = new FileInputStream(v.mPath);
- mZipArchives.add(input);
+ for (Path pathList : mZipList) {
+ for (String path : pathList.list()) {
+ FileInputStream input = new FileInputStream(path);
+ mZipArchives.add(input);
+ }
}
// now go through the list of file to directly add the to the list.
- for (Value v : mFileList) {
- mArchiveFiles.add(ApkBuilderImpl.getInputFile(v.mPath));
+ for (Path pathList : mFileList) {
+ for (String path : pathList.list()) {
+ mArchiveFiles.add(ApkBuilderImpl.getInputFile(path));
+ }
}
// now go through the list of file to directly add the to the list.
- for (Value v : mSourceList) {
- ApkBuilderImpl.processSourceFolderForResource(new File(v.mPath), mJavaResources);
+ for (Path pathList : mSourceList) {
+ for (String path : pathList.list()) {
+ ApkBuilderImpl.processSourceFolderForResource(new File(path),
+ mJavaResources);
+ }
}
// now go through the list of jar folders.
- for (Value v : mJarfolderList) {
- ApkBuilderImpl.processJar(new File(v.mPath), mResourcesJars);
+ for (Path pathList : mJarfolderList) {
+ for (String path : pathList.list()) {
+ ApkBuilderImpl.processJar(new File(path), mResourcesJars);
+ }
}
// now go through the list of jar files.
- for (Value v : mJarfileList) {
- ApkBuilderImpl.processJar(new File(v.mPath), mResourcesJars);
+ for (Path pathList : mJarfileList) {
+ for (String path : pathList.list()) {
+ ApkBuilderImpl.processJar(new File(path), mResourcesJars);
+ }
}
// now the native lib folder.
- for (Value v : mNativeList) {
- String parameter = v.mPath;
- File f = new File(parameter);
-
- ApkBuilderImpl.processNativeFolder(f, mDebug, mNativeLibraries);
+ for (Path pathList : mNativeList) {
+ for (String path : pathList.list()) {
+ ApkBuilderImpl.processNativeFolder(new File(path), mDebug,
+ mNativeLibraries);
+ }
}
// create the Path item that will contain all the generated APKs
diff --git a/anttasks/src/com/android/ant/SetupTask.java b/anttasks/src/com/android/ant/SetupTask.java
index 72f5d11..6f3d0a5 100644
--- a/anttasks/src/com/android/ant/SetupTask.java
+++ b/anttasks/src/com/android/ant/SetupTask.java
@@ -22,8 +22,9 @@ import com.android.sdklib.ISdkLog;
import com.android.sdklib.SdkManager;
import com.android.sdklib.IAndroidTarget.IOptionalLibrary;
import com.android.sdklib.internal.project.ProjectProperties;
-import com.android.sdklib.xml.AndroidXPathFactory;
+import com.android.sdklib.internal.project.ProjectProperties.PropertyType;
import com.android.sdklib.xml.AndroidManifest;
+import com.android.sdklib.xml.AndroidXPathFactory;
import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.Project;
@@ -61,6 +62,8 @@ public final class SetupTask extends ImportTask {
private final static String ANDROID_RULES = "android_rules.xml";
// additional android rules for test project - depends on android_rules.xml
private final static String ANDROID_TEST_RULES = "android_test_rules.xml";
+ // additional android rules for test project - depends on android_rules.xml
+ private final static String ANDROID_LIBRARY_RULES = "android_lib_rules.xml";
// ant property with the path to the android.jar
private final static String PROPERTY_ANDROID_JAR = "android.jar";
// LEGACY - compatibility with 1.6 and before
@@ -153,8 +156,22 @@ public final class SetupTask extends ImportTask {
"Unable to resolve target '%s'", targetHashString));
}
+ // check if the project is a library
+ boolean isLibrary = false;
+
+ String libraryProp = antProject.getProperty(ProjectProperties.PROPERTY_LIBRARY);
+ if (libraryProp != null) {
+ isLibrary = Boolean.valueOf(libraryProp).booleanValue();
+ }
+
+ // look for referenced libraries.
+ processReferencedLibraries(antProject);
+
// display it
System.out.println("Project Target: " + androidTarget.getName());
+ if (isLibrary) {
+ System.out.println("Type: Android Library");
+ }
if (androidTarget.isPlatform() == false) {
System.out.println("Vendor: " + androidTarget.getVendor());
System.out.println("Platform Version: " + androidTarget.getVersionName());
@@ -227,7 +244,8 @@ public final class SetupTask extends ImportTask {
templateFolder));
}
- String importedRulesFileName = isTestProject ? ANDROID_TEST_RULES : ANDROID_RULES;
+ String importedRulesFileName = isLibrary ? ANDROID_LIBRARY_RULES :
+ isTestProject ? ANDROID_TEST_RULES : ANDROID_RULES;
// now check the rules file exists.
File rules = new File(templateFolder, importedRulesFileName);
@@ -333,4 +351,70 @@ public final class SetupTask extends ImportTask {
throw new BuildException(e);
}
}
+
+ private void processReferencedLibraries(Project antProject) {
+ // prepare several paths for future tasks
+ Path sourcePath = new Path(antProject);
+ Path resPath = new Path(antProject);
+ StringBuilder sb = new StringBuilder();
+
+ int index = 1;
+ while (true) {
+ String propName = ProjectProperties.PROPERTY_LIB_REF + Integer.toString(index++);
+ String rootPath = antProject.getProperty(propName);
+
+ if (rootPath == null) {
+ break;
+ }
+
+ // get the source path. default is src but can be overriden by the property
+ // "source.dir" in build.properties.
+ PathElement element = sourcePath.createPathElement();
+ ProjectProperties prop = ProjectProperties.load(rootPath, PropertyType.BUILD);
+ String sourceDir = "src";
+ if (prop != null) {
+ String value = prop.getProperty(ProjectProperties.PROPERTY_BUILD_SOURCE_DIR);
+ if (value != null) {
+ sourceDir = value;
+ }
+ }
+
+ element.setPath(rootPath + "/" + sourceDir);
+
+ // get the res path. Always $PROJECT/res
+ element = resPath.createPathElement();
+ element.setPath(rootPath + "/res");
+
+ // get the package from the manifest.
+ File manifest = new File(rootPath, "AndroidManifest.xml");
+ XPath xPath = AndroidXPathFactory.newXPath();
+
+ // check the package name.
+ try {
+ String value = xPath.evaluate(
+ "/" + AndroidManifest.NODE_MANIFEST +
+ "/@" + AndroidManifest.ATTRIBUTE_PACKAGE,
+ new InputSource(new FileInputStream(manifest)));
+ if (value != null) { // aapt will complain if it's missing.
+ sb.append(';');
+ sb.append(value);
+ }
+ } catch (XPathExpressionException e) {
+ throw new BuildException(e);
+ } catch (FileNotFoundException e) {
+ throw new BuildException(e);
+ }
+
+ }
+
+ // even with no libraries, always setup android.libraries.src so that javac
+ // doesn't complain
+ antProject.addReference("android.libraries.src", sourcePath);
+
+ // the rest is done only if there's a library.
+ if (sourcePath.list().length > 0) {
+ antProject.addReference("android.libraries.res", resPath);
+ antProject.setProperty("android.libraries.package", sb.toString());
+ }
+ }
}
diff --git a/anttasks/src/com/android/ant/TaskHelper.java b/anttasks/src/com/android/ant/TaskHelper.java
new file mode 100644
index 0000000..361725a
--- /dev/null
+++ b/anttasks/src/com/android/ant/TaskHelper.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.ant;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.types.Path;
+
+public class TaskHelper {
+
+ public static String checkSinglePath(String attribute, Path path) {
+ String[] paths = path.list();
+ if (paths.length != 1) {
+ throw new BuildException(String.format("Path value for '%1$s' is not valid.", attribute));
+ }
+
+ return paths[0];
+ }
+
+}