diff options
Diffstat (limited to 'anttasks/src')
-rw-r--r-- | anttasks/src/com/android/ant/AaptExecLoopTask.java | 237 | ||||
-rw-r--r-- | anttasks/src/com/android/ant/ApkBuilderTask.java | 111 | ||||
-rw-r--r-- | anttasks/src/com/android/ant/SetupTask.java | 88 | ||||
-rw-r--r-- | anttasks/src/com/android/ant/TaskHelper.java | 33 |
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><res path=""></td><td>nested element(s)<br>with attribute (Path)</td></tr> + * <tr><td>-0 extension</td><td><nocompress extension=""><br><nocompress></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]; + } + +} |