diff options
48 files changed, 2156 insertions, 1063 deletions
diff --git a/anttasks/src/com/android/ant/AaptExecTask.java b/anttasks/src/com/android/ant/AaptExecTask.java index eabbbd2..d0fba5f 100644 --- a/anttasks/src/com/android/ant/AaptExecTask.java +++ b/anttasks/src/com/android/ant/AaptExecTask.java @@ -93,8 +93,8 @@ public final class AaptExecTask extends SingleDependencyTask { private String mResourceFilter; private String mRFolder; private final ArrayList<NoCompress> mNoCompressList = new ArrayList<NoCompress>(); - private String mProjectLibrariesResName; - private String mProjectLibrariesPackageName; + private String mLibraryResFolderPathRefid; + private String mLibraryPackagesRefid; private boolean mNonConstantId; /** @@ -302,15 +302,20 @@ public final class AaptExecTask extends SingleDependencyTask { } } - public void setProjectLibrariesResName(String projectLibrariesResName) { - mProjectLibrariesResName = projectLibrariesResName; + /** + * Set the property name of the property that contains the list of res folder for + * Library Projects. This sets the name and not the value itself to handle the case where + * it doesn't exist. + * @param projectLibrariesResName + */ + public void setLibraryResFolderPathRefid(String libraryResFolderPathRefid) { + mLibraryResFolderPathRefid = libraryResFolderPathRefid; } - public void setProjectLibrariesPackageName(String projectLibrariesPackageName) { - mProjectLibrariesPackageName = projectLibrariesPackageName; + public void setLibraryPackagesRefid(String libraryPackagesRefid) { + mLibraryPackagesRefid = libraryPackagesRefid; } - /** * Returns an object representing a nested <var>nocompress</var> element. */ @@ -344,11 +349,11 @@ public final class AaptExecTask extends SingleDependencyTask { */ @Override public void execute() throws BuildException { - if (mProjectLibrariesResName == null) { - throw new BuildException("Missing attribute projectLibrariesResName"); + if (mLibraryResFolderPathRefid == null) { + throw new BuildException("Missing attribute libraryResFolderPathRefid"); } - if (mProjectLibrariesPackageName == null) { - throw new BuildException("Missing attribute projectLibrariesPackageName"); + if (mLibraryPackagesRefid == null) { + throw new BuildException("Missing attribute libraryPackagesRefid"); } Project taskProject = getProject(); @@ -359,7 +364,7 @@ public final class AaptExecTask extends SingleDependencyTask { // more R classes need to be created for libraries, only if this project itself // is not a library if (mNonConstantId == false && mRFolder != null && new File(mRFolder).isDirectory()) { - libPkgProp = taskProject.getProperty(mProjectLibrariesPackageName); + libPkgProp = taskProject.getProperty(mLibraryPackagesRefid); if (libPkgProp != null) { // Replace ";" with ":" since that's what aapt expects libPkgProp = libPkgProp.replace(';', ':'); @@ -387,7 +392,7 @@ public final class AaptExecTask extends SingleDependencyTask { final boolean generateRClass = mRFolder != null && new File(mRFolder).isDirectory(); // Get whether we have libraries - Object libResRef = taskProject.getReference(mProjectLibrariesResName); + Object libResRef = taskProject.getReference(mLibraryResFolderPathRefid); // Set up our input paths that matter for dependency checks ArrayList<File> paths = new ArrayList<File>(); diff --git a/anttasks/src/com/android/ant/CheckEnvTask.java b/anttasks/src/com/android/ant/CheckEnvTask.java new file mode 100644 index 0000000..d6b6cc4 --- /dev/null +++ b/anttasks/src/com/android/ant/CheckEnvTask.java @@ -0,0 +1,105 @@ +/* + * Copyright (C) 2012 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 com.android.sdklib.SdkConstants; + +import org.apache.tools.ant.BuildException; +import org.apache.tools.ant.Project; +import org.apache.tools.ant.Task; +import org.apache.tools.ant.util.DeweyDecimal; + +import java.io.File; + +/** + * Checks the Ant environment to make sure Android builds + * can run. + * + * No parameters are neeed. + * + */ +public class CheckEnvTask extends Task { + + private final static String ANT_MIN_VERSION = "1.8.0"; + + @Override + public void execute() { + + Project antProject = getProject(); + + // check the Ant version + DeweyDecimal version = getVersion(antProject); + DeweyDecimal atLeast = new DeweyDecimal(ANT_MIN_VERSION); + if (atLeast.isGreaterThan(version)) { + throw new BuildException( + "The Android Ant-based build system requires Ant " + + ANT_MIN_VERSION + + " or later. Current version is " + + version); + } + + // get the SDK location + File sdkDir = TaskHelper.getSdkLocation(antProject); + + // detect that the platform tools is there. + File platformTools = new File(sdkDir, SdkConstants.FD_PLATFORM_TOOLS); + if (platformTools.isDirectory() == false) { + throw new BuildException(String.format( + "SDK Platform Tools component is missing. " + + "Please install it with the SDK Manager (%1$s%2$c%3$s)", + SdkConstants.FD_TOOLS, + File.separatorChar, + SdkConstants.androidCmdName())); + } + + // display SDK Tools revision + int toolsRevison = TaskHelper.getToolsRevision(sdkDir); + if (toolsRevison != -1) { + System.out.println("Android SDK Tools Revision " + toolsRevison); + System.out.println("Installed at " + sdkDir.getAbsolutePath()); + } + } + + /** + * Returns the Ant version as a {@link DeweyDecimal} object. + * + * This is based on the implementation of + * org.apache.tools.ant.taskdefs.condition.AntVersion.getVersion() + * + * @param antProject the current ant project. + * @return the ant version. + */ + private DeweyDecimal getVersion(Project antProject) { + char[] versionString = antProject.getProperty("ant.version").toCharArray(); + StringBuilder sb = new StringBuilder(); + boolean foundFirstDigit = false; + for (int i = 0; i < versionString.length; i++) { + if (Character.isDigit(versionString[i])) { + sb.append(versionString[i]); + foundFirstDigit = true; + } + if (versionString[i] == '.' && foundFirstDigit) { + sb.append(versionString[i]); + } + if (Character.isLetter(versionString[i]) && foundFirstDigit) { + break; + } + } + return new DeweyDecimal(sb.toString()); + } + +} diff --git a/anttasks/src/com/android/ant/ComputeDependencyTask.java b/anttasks/src/com/android/ant/ComputeDependencyTask.java new file mode 100644 index 0000000..17b68d6 --- /dev/null +++ b/anttasks/src/com/android/ant/ComputeDependencyTask.java @@ -0,0 +1,239 @@ +/* + * Copyright (C) 2012 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 com.android.ant.DependencyHelper.LibraryProcessorFor3rdPartyJars; +import com.android.io.FileWrapper; +import com.android.sdklib.SdkConstants; +import com.android.sdklib.internal.project.IPropertySource; +import com.android.sdklib.xml.AndroidManifest; + +import org.apache.tools.ant.BuildException; +import org.apache.tools.ant.Project; +import org.apache.tools.ant.types.Path; +import org.apache.tools.ant.types.Path.PathElement; + +import java.io.File; +import java.util.List; + +/** + * Computes the dependency of the current project. + * + * Out params: + * <code>libraryResFolderPathOut</code>: the Path object containing the res folder for all the + * library projects in the order needed by aapt. + * + * <code>libraryPackagesOut</code>: a simple property containing ;-separated package name from + * the library projects. + * + * <code>jarLibraryPathOut</code>: the Path object containing all the 3rd party jar files. + * + * <code>libraryNativeFolderPathOut</code>: the Path with all the native folder for the library + * projects. + * + * + * In params: + * <code>targetApi</code>: the compilation target api. + * <code>verbose</code>: whether the build is verbose. + * + */ +public class ComputeDependencyTask extends GetLibraryListTask { + + private String mLibraryResFolderPathOut; + private String mLibraryPackagesOut; + private String mJarLibraryPathOut; + private String mLibraryNativeFolderPathOut; + private int mTargetApi = -1; + private boolean mVerbose = false; + + public void setLibraryResFolderPathOut(String libraryResFolderPathOut) { + mLibraryResFolderPathOut = libraryResFolderPathOut; + } + + public void setLibraryPackagesOut(String libraryPackagesOut) { + mLibraryPackagesOut = libraryPackagesOut; + } + + public void setJarLibraryPathOut(String jarLibraryPathOut) { + mJarLibraryPathOut = jarLibraryPathOut; + } + + public void setLibraryNativeFolderPathOut(String libraryNativeFolderPathOut) { + mLibraryNativeFolderPathOut = libraryNativeFolderPathOut; + } + + public void setTargetApi(int targetApi) { + mTargetApi = targetApi; + } + + /** + * Sets the value of the "verbose" attribute. + * @param verbose the value. + */ + public void setVerbose(boolean verbose) { + mVerbose = verbose; + } + + @Override + public void execute() throws BuildException { + if (mLibraryResFolderPathOut == null) { + throw new BuildException("Missing attribute libraryResFolderPathOut"); + } + if (mLibraryPackagesOut == null) { + throw new BuildException("Missing attribute libraryPackagesOut"); + } + if (mJarLibraryPathOut == null) { + throw new BuildException("Missing attribute jarLibraryPathOut"); + } + if (mLibraryNativeFolderPathOut == null) { + throw new BuildException("Missing attribute libraryNativeFolderPathOut"); + } + if (mTargetApi == -1) { + throw new BuildException("Missing attribute targetApi"); + } + + final Project antProject = getProject(); + + // get the SDK location + File sdkDir = TaskHelper.getSdkLocation(antProject); + + // prepare several paths for future tasks + final Path resFolderPath = new Path(antProject); + final Path nativeFolderPath = new Path(antProject); + final StringBuilder packageStrBuilder = new StringBuilder(); + + LibraryProcessorFor3rdPartyJars processor = new LibraryProcessorFor3rdPartyJars() { + @Override + public void processLibrary(String libRootPath) { + // let the super class handle the jar files + super.processLibrary(libRootPath); + + // get the res path. Always $PROJECT/res as well as the crunch cache. + // FIXME: support renamed folder. + PathElement element = resFolderPath.createPathElement(); + element.setPath(libRootPath + "/" + SdkConstants.FD_OUTPUT + + "/" + SdkConstants.FD_RES); + element = resFolderPath.createPathElement(); + element.setPath(libRootPath + "/" + SdkConstants.FD_RESOURCES); + + + // get the folder for the native libraries. Always $PROJECT/libs + // FIXME: support renamed folder. + element = nativeFolderPath.createPathElement(); + element.setPath(libRootPath + "/" + SdkConstants.FD_NATIVE_LIBS); + + // get the package from the manifest. + FileWrapper manifest = new FileWrapper(libRootPath, + SdkConstants.FN_ANDROID_MANIFEST_XML); + + try { + String value = AndroidManifest.getPackage(manifest); + if (value != null) { // aapt will complain if it's missing. + packageStrBuilder.append(';'); + packageStrBuilder.append(value); + } + } catch (Exception e) { + throw new BuildException(e); + } + } + }; + + // list of all the jars that are on the classpath. This will receive the + // project's libs/*.jar files, the Library Projects output and their own libs/*.jar + List<File> jars = processor.getJars(); + + + // in case clean has been called before a build type target, the list of + // libraries has already been computed so we don't need to compute it again. + Path libraryFolderPath = (Path) antProject.getReference(getLibraryFolderPathOut()); + if (libraryFolderPath == null) { + execute(processor); + } else { + // this contains the list of library folder in reverse order (compilation order). + // We need to process it in the normal order (res order). + System.out.println("Ordered libraries:"); + + String[] libraries = libraryFolderPath.list(); + for (int i = libraries.length - 1 ; i >= 0 ; i--) { + String libRootPath = libraries[i]; + System.out.println(libRootPath); + + processor.processLibrary(libRootPath); + } + } + + boolean hasLibraries = jars.size() > 0; + + if (mTargetApi <= 15) { + System.out.println("\n------------------"); + System.out.println("API<=15: Adding annotations.jar to the classpath."); + + jars.add(new File(sdkDir, SdkConstants.FD_TOOLS + + "/" + SdkConstants.FD_SUPPORT + + "/" + SdkConstants.FN_ANNOTATIONS_JAR)); + + } + + // even with no libraries, always setup these so that various tasks in Ant don't complain + // (the task themselves can handle a ref to an empty Path) + antProject.addReference(mLibraryNativeFolderPathOut, nativeFolderPath); + + // the rest is done only if there's a library. + if (hasLibraries) { + antProject.addReference(mLibraryResFolderPathOut, resFolderPath); + antProject.setProperty(mLibraryPackagesOut, packageStrBuilder.toString()); + } + + File projectFolder = antProject.getBaseDir(); + + // add the project's own content of libs/*.jar + File libsFolder = new File(projectFolder, SdkConstants.FD_NATIVE_LIBS); + File[] jarFiles = libsFolder.listFiles(processor.getFilter()); + if (jarFiles != null) { + for (File jarFile : jarFiles) { + jars.add(jarFile); + } + } + + // now sanitize the path to remove dups + jars = DependencyHelper.sanitizePaths(projectFolder, new IPropertySource() { + @Override + public String getProperty(String name) { + return antProject.getProperty(name); + } + }, jars); + + // and create a Path object for them + Path jarsPath = new Path(antProject); + if (mVerbose) { + System.out.println("\n------------------\nSanitized jar list:"); + } + for (File f : jars) { + if (mVerbose) { + System.out.println("- " + f.getAbsolutePath()); + } + PathElement element = jarsPath.createPathElement(); + element.setPath(f.getAbsolutePath()); + } + antProject.addReference(mJarLibraryPathOut, jarsPath); + + if (mVerbose) { + System.out.println(); + } + + } +} diff --git a/anttasks/src/com/android/ant/ComputeProjectClasspathTask.java b/anttasks/src/com/android/ant/ComputeProjectClasspathTask.java new file mode 100644 index 0000000..4a89ec2 --- /dev/null +++ b/anttasks/src/com/android/ant/ComputeProjectClasspathTask.java @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2012 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 com.android.ant.DependencyHelper.LibraryProcessorFor3rdPartyJars; +import com.android.sdklib.SdkConstants; + +import org.apache.tools.ant.BuildException; +import org.apache.tools.ant.Project; +import org.apache.tools.ant.Task; +import org.apache.tools.ant.types.Path; +import org.apache.tools.ant.types.Path.PathElement; + +import java.io.File; +import java.util.List; + +public class ComputeProjectClasspathTask extends Task { + + private String mProjectLocation; + private String mProjectClassPathOut; + + public void setProjectLocation(String projectLocation) { + mProjectLocation = projectLocation; + } + + public void setProjectClassPathOut(String projectClassPathOut) { + mProjectClassPathOut = projectClassPathOut; + } + + @Override + public void execute() throws BuildException { + if (mProjectLocation == null) { + throw new BuildException("Missing attribute projectLocation"); + } + if (mProjectClassPathOut == null) { + throw new BuildException("Missing attribute projectClassPathOut"); + } + + DependencyHelper helper = new DependencyHelper(new File(mProjectLocation), + false /*verbose*/); + + LibraryProcessorFor3rdPartyJars processor = new LibraryProcessorFor3rdPartyJars(); + + helper.processLibraries(processor); + List<File> jars = processor.getJars(); + + // add the project's own content of libs/*.jar + File libsFolder = new File(mProjectLocation, SdkConstants.FD_NATIVE_LIBS); + File[] jarFiles = libsFolder.listFiles(processor.getFilter()); + if (jarFiles != null) { + for (File jarFile : jarFiles) { + jars.add(jarFile); + } + } + + jars = helper.sanitizePaths(jars); + + Project antProject = getProject(); + + System.out.println("Resolved classpath:"); + + // create a path with all the jars and the project's output as well. + Path path = new Path(antProject); + for (File jar : jars) { + PathElement element = path.createPathElement(); + String p = jar.getAbsolutePath(); + element.setPath(p); + System.out.println(p); + } + + File bin = new File(mProjectLocation, + helper.getOutDir() + File.separator + "classes"); + PathElement element = path.createPathElement(); + String p = bin.getAbsolutePath(); + element.setPath(p); + System.out.println(p); + + antProject.addReference(mProjectClassPathOut, path); + } +} diff --git a/anttasks/src/com/android/ant/DependencyHelper.java b/anttasks/src/com/android/ant/DependencyHelper.java new file mode 100644 index 0000000..c2a6694 --- /dev/null +++ b/anttasks/src/com/android/ant/DependencyHelper.java @@ -0,0 +1,301 @@ +/* + * Copyright (C) 2012 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 com.android.io.FolderWrapper; +import com.android.sdklib.SdkConstants; +import com.android.sdklib.build.JarListSanitizer; +import com.android.sdklib.build.JarListSanitizer.DifferentLibException; +import com.android.sdklib.build.JarListSanitizer.Sha1Exception; +import com.android.sdklib.internal.project.IPropertySource; +import com.android.sdklib.internal.project.ProjectProperties; +import com.android.sdklib.internal.project.ProjectProperties.PropertyType; + +import org.apache.tools.ant.BuildException; + +import java.io.File; +import java.io.FilenameFilter; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; + +/** + * Helper class to manage dependency for projects. + * + */ +public class DependencyHelper { + + private final boolean mVerbose; + private final File mProjectFolder; + private final IPropertySource mProperties; + private final List<File> mLibraries = new ArrayList<File>(); + + /** + * A Library Processor. Used in {@link DependencyHelper#processLibraries(LibraryProcessor)} + * + */ + protected interface LibraryProcessor { + void processLibrary(String libRootPath); + } + + /** + * Basic implementation of {@link LibraryProcessor} that builds a list of sanitized list + * of 3rd party jar files from all the Library Projects. + */ + public static class LibraryProcessorFor3rdPartyJars implements LibraryProcessor { + + private final List<File> mJars = new ArrayList<File>(); + + private final FilenameFilter mFilter = new FilenameFilter() { + @Override + public boolean accept(File dir, String name) { + return name.toLowerCase(Locale.US).endsWith(".jar"); + } + }; + + public List<File> getJars() { + return mJars; + } + + public FilenameFilter getFilter() { + return mFilter; + } + + @Override + public void processLibrary(String libRootPath) { + // get the library output + // FIXME: support renamed folder. + mJars.add(new File(libRootPath + "/" + SdkConstants.FD_OUTPUT + + "/" + SdkConstants.FN_CLASSES_JAR)); + + // Get the 3rd party jar files. + // FIXME: support renamed folder. + File libsFolder = new File(libRootPath, SdkConstants.FD_NATIVE_LIBS); + File[] jarFiles = libsFolder.listFiles(mFilter); + if (jarFiles != null) { + for (File jarFile : jarFiles) { + mJars.add(jarFile); + } + } + } + } + + public static List<File> sanitizePaths(File projectFolder, IPropertySource properties, + List<File> paths) { + // first get the non-files. + List<File> results = new ArrayList<File>(); + for (int i = 0 ; i < paths.size() ;) { + File f = paths.get(i); + // TEMP WORKAROUND: ignore classes.jar as all the output of libraries are + // called the same (in Ant) but are not actually the same jar file. + // TODO: Be aware of library output vs. regular jar dependency. + if (f.isFile() && f.getName().equals(SdkConstants.FN_CLASSES_JAR) == false) { + i++; + } else { + results.add(f); + paths.remove(i); + } + } + + + File outputFile = new File(projectFolder, getOutDir(properties)); + JarListSanitizer sanitizer = new JarListSanitizer(outputFile); + + try { + results.addAll(sanitizer.sanitize(paths)); + } catch (DifferentLibException e) { + String[] details = e.getDetails(); + for (String s : details) { + System.err.println(s); + } + throw new BuildException(e.getMessage(), e); + } catch (Sha1Exception e) { + throw new BuildException( + "Failed to compute sha1 for " + e.getJarFile().getAbsolutePath(), e); + } + + return results; + } + + /** + * + * @param projectFolder the project root folder. + */ + public DependencyHelper(File projectFolder, boolean verbose) { + mProjectFolder = projectFolder; + mVerbose = verbose; + + ProjectProperties properties = ProjectProperties.load(projectFolder.getAbsolutePath(), + PropertyType.ANT); + + if (properties == null) { + properties = ProjectProperties.load(projectFolder.getAbsolutePath(), + PropertyType.PROJECT); + } else { + properties.makeWorkingCopy().merge(PropertyType.PROJECT); + } + + mProperties = properties; + + init(projectFolder); + } + + /** + * + * @param projectFolder the project root folder. + * @param source an {@link IPropertySource} that can provide the project properties values. + */ + public DependencyHelper(File projectFolder, IPropertySource properties, boolean verbose) { + mProjectFolder = projectFolder; + mProperties = properties; + mVerbose = verbose; + + init(projectFolder); + } + + private void init(File projectFolder) { + // get the top level list of library dependencies. + List<File> topLevelLibraries = getDirectDependencies(projectFolder, mProperties); + + // process the libraries in case they depend on other libraries. + resolveFullLibraryDependencies(topLevelLibraries, mLibraries); + } + + public List<File> getLibraries() { + return mLibraries; + } + + public int getLibraryCount() { + return mLibraries.size(); + } + + public String getProperty(String name) { + return mProperties.getProperty(name); + } + + public void processLibraries(LibraryProcessor processor) { + // use that same order to process the libraries. + for (File library : mLibraries) { + // get the root path. + String libRootPath = library.getAbsolutePath(); + if (mVerbose) { + System.out.println(libRootPath); + } + + if (processor != null) { + processor.processLibrary(libRootPath); + } + } + } + + public List<File> sanitizePaths(List<File> paths) { + return sanitizePaths(mProjectFolder, mProperties, paths); + } + + public String getOutDir() { + return getOutDir(mProperties); + } + + + /** + * Returns the top level library dependencies of a given <var>source</var> representing a + * project properties. + * @param baseFolder the base folder of the project (to resolve relative paths) + * @param properties a source of project properties. + */ + private List<File> getDirectDependencies(File baseFolder, IPropertySource properties) { + ArrayList<File> libraries = new ArrayList<File>(); + + // first build the list. they are ordered highest priority first. + int index = 1; + while (true) { + String propName = ProjectProperties.PROPERTY_LIB_REF + Integer.toString(index++); + String rootPath = properties.getProperty(propName); + + if (rootPath == null) { + break; + } + + try { + File library = new File(baseFolder, rootPath).getCanonicalFile(); + + // check for validity + File projectProp = new File(library, PropertyType.PROJECT.getFilename()); + if (projectProp.isFile() == false) { + // error! + throw new BuildException(String.format( + "%1$s resolve to a path with no %2$s file for project %3$s", rootPath, + PropertyType.PROJECT.getFilename(), baseFolder.getAbsolutePath())); + } + + if (libraries.contains(library) == false) { + if (mVerbose) { + System.out.println(String.format("%1$s: %2$s => %3$s", + baseFolder.getAbsolutePath(), rootPath, library.getAbsolutePath())); + } + + libraries.add(library); + } + } catch (IOException e) { + throw new BuildException("Failed to resolve library path: " + rootPath, e); + } + } + + return libraries; + } + + /** + * Resolves a given list of libraries, finds out if they depend on other libraries, and + * returns a full list of all the direct and indirect dependencies in the proper order (first + * is higher priority when calling aapt). + * @param inLibraries the libraries to resolve + * @param outLibraries where to store all the libraries. + */ + private void resolveFullLibraryDependencies(List<File> inLibraries, List<File> outLibraries) { + // loop in the inverse order to resolve dependencies on the libraries, so that if a library + // is required by two higher level libraries it can be inserted in the correct place + for (int i = inLibraries.size() - 1 ; i >= 0 ; i--) { + File library = inLibraries.get(i); + + // get the default.property file for it + final ProjectProperties projectProp = ProjectProperties.load( + new FolderWrapper(library), PropertyType.PROJECT); + + // get its libraries + List<File> dependencies = getDirectDependencies(library, projectProp); + + // resolve the dependencies for those libraries + resolveFullLibraryDependencies(dependencies, outLibraries); + + // and add the current one (if needed) in front (higher priority) + if (outLibraries.contains(library) == false) { + outLibraries.add(0, library); + } + } + } + + private static String getOutDir(IPropertySource properties) { + String bin = properties.getProperty("out.dir"); + if (bin == null) { + return SdkConstants.FD_OUTPUT; + } + + return bin; + } + +} diff --git a/anttasks/src/com/android/ant/GetLibraryListTask.java b/anttasks/src/com/android/ant/GetLibraryListTask.java new file mode 100644 index 0000000..e2d5dd7 --- /dev/null +++ b/anttasks/src/com/android/ant/GetLibraryListTask.java @@ -0,0 +1,95 @@ +/* + * Copyright (C) 2012 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 com.android.ant.DependencyHelper.LibraryProcessor; +import com.android.sdklib.internal.project.IPropertySource; + +import org.apache.tools.ant.BuildException; +import org.apache.tools.ant.Project; +import org.apache.tools.ant.Task; +import org.apache.tools.ant.types.Path; +import org.apache.tools.ant.types.Path.PathElement; + +import java.io.File; +import java.util.List; + +/** + * Task to get the list of Library Project for the current project. + * + */ +public class GetLibraryListTask extends Task { + + private String mLibraryFolderPathOut; + + + public void setLibraryFolderPathOut(String libraryFolderPathOut) { + mLibraryFolderPathOut = libraryFolderPathOut; + } + + @Override + public void execute() throws BuildException { + execute(null); + } + + public void execute(LibraryProcessor processor) throws BuildException { + + if (mLibraryFolderPathOut == null) { + throw new BuildException("Missing attribute libraryFolderPathOut"); + } + + final Project antProject = getProject(); + + DependencyHelper helper = new DependencyHelper(antProject.getBaseDir(), + new IPropertySource() { + @Override + public String getProperty(String name) { + return antProject.getProperty(name); + } + }, + true /*verbose*/); + + System.out.println("Library dependencies:"); + + if (helper.getLibraryCount() > 0) { + System.out.println("\n------------------\nOrdered libraries:"); + + helper.processLibraries(processor); + + // Create a Path object of all the libraries in reverse order. + // This is important so that compilation of libraries happens + // in the reverse order. + Path rootPath = new Path(antProject); + + List<File> libraries = helper.getLibraries(); + + for (int i = libraries.size() - 1 ; i >= 0; i--) { + File library = libraries.get(i); + PathElement element = rootPath.createPathElement(); + element.setPath(library.getAbsolutePath()); + } + + antProject.addReference(mLibraryFolderPathOut, rootPath); + } else { + System.out.println("No Libraries"); + } + } + + protected String getLibraryFolderPathOut() { + return mLibraryFolderPathOut; + } +} diff --git a/anttasks/src/com/android/ant/GetTargetTask.java b/anttasks/src/com/android/ant/GetTargetTask.java new file mode 100644 index 0000000..f4578b2 --- /dev/null +++ b/anttasks/src/com/android/ant/GetTargetTask.java @@ -0,0 +1,294 @@ +/* + * Copyright (C) 2012 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 com.android.sdklib.AndroidVersion; +import com.android.sdklib.IAndroidTarget; +import com.android.sdklib.IAndroidTarget.IOptionalLibrary; +import com.android.sdklib.ISdkLog; +import com.android.sdklib.SdkConstants; +import com.android.sdklib.SdkManager; +import com.android.sdklib.internal.project.ProjectProperties; +import com.android.sdklib.xml.AndroidManifest; +import com.android.sdklib.xml.AndroidXPathFactory; + +import org.apache.tools.ant.BuildException; +import org.apache.tools.ant.Project; +import org.apache.tools.ant.Task; +import org.apache.tools.ant.types.Path; +import org.apache.tools.ant.types.Path.PathElement; +import org.xml.sax.InputSource; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.util.ArrayList; +import java.util.HashSet; + +import javax.xml.xpath.XPath; +import javax.xml.xpath.XPathExpressionException; + +/** + * Task to resolve the target of the current Android project. + * + * Out params: + * <code>bootClassPathOut</code>: The boot class path of the project. + * + * <code>androidJarFileOut</code>: the android.jar used by the project. + * + * <code>androidAidlFileOut</code>: the framework.aidl used by the project. + * + * <code>targetApiOut</code>: the build API level. + * + * <code>minSdkVersionOut</code>: the app's minSdkVersion. + * + */ +public class GetTargetTask extends Task { + + private String mBootClassPathOut; + private String mAndroidJarFileOut; + private String mAndroidAidlFileOut; + private String mTargetApiOut; + private String mMinSdkVersionOut; + + public void setBootClassPathOut(String bootClassPathOut) { + mBootClassPathOut = bootClassPathOut; + } + + public void setAndroidJarFileOut(String androidJarFileOut) { + mAndroidJarFileOut = androidJarFileOut; + } + + public void setAndroidAidlFileOut(String androidAidlFileOut) { + mAndroidAidlFileOut = androidAidlFileOut; + } + + public void setTargetApiOut(String targetApiOut) { + mTargetApiOut = targetApiOut; + } + + public void setMinSdkVersionOut(String minSdkVersionOut) { + mMinSdkVersionOut = minSdkVersionOut; + } + + @Override + public void execute() throws BuildException { + if (mBootClassPathOut == null) { + throw new BuildException("Missing attribute bootClassPathOut"); + } + if (mAndroidJarFileOut == null) { + throw new BuildException("Missing attribute androidJarFileOut"); + } + if (mAndroidAidlFileOut == null) { + throw new BuildException("Missing attribute androidAidlFileOut"); + } + if (mTargetApiOut == null) { + throw new BuildException("Missing attribute targetApiOut"); + } + if (mMinSdkVersionOut == null) { + throw new BuildException("Missing attribute mMinSdkVersionOut"); + } + + Project antProject = getProject(); + + // get the SDK location + File sdkDir = TaskHelper.getSdkLocation(antProject); + + // get the target property value + String targetHashString = antProject.getProperty(ProjectProperties.PROPERTY_TARGET); + + if (targetHashString == null) { + throw new BuildException("Android Target is not set."); + } + + // load up the sdk targets. + final ArrayList<String> messages = new ArrayList<String>(); + SdkManager manager = SdkManager.createManager(sdkDir.getPath(), new ISdkLog() { + @Override + public void error(Throwable t, String errorFormat, Object... args) { + if (errorFormat != null) { + messages.add(String.format("Error: " + errorFormat, args)); + } + if (t != null) { + messages.add("Error: " + t.getMessage()); + } + } + + @Override + public void printf(String msgFormat, Object... args) { + messages.add(String.format(msgFormat, args)); + } + + @Override + public void warning(String warningFormat, Object... args) { + messages.add(String.format("Warning: " + warningFormat, args)); + } + }); + + if (manager == null) { + // since we failed to parse the SDK, lets display the parsing output. + for (String msg : messages) { + System.out.println(msg); + } + throw new BuildException("Failed to parse SDK content."); + } + + // resolve it + IAndroidTarget androidTarget = manager.getTargetFromHashString(targetHashString); + + if (androidTarget == null) { + throw new BuildException(String.format( + "Unable to resolve project target '%s'", targetHashString)); + } + + // display the project info + System.out.println( "Project Target: " + androidTarget.getName()); + if (androidTarget.isPlatform() == false) { + System.out.println("Vendor: " + androidTarget.getVendor()); + System.out.println("Platform Version: " + androidTarget.getVersionName()); + } + System.out.println( "API level: " + androidTarget.getVersion().getApiString()); + + antProject.setProperty(mMinSdkVersionOut, + Integer.toString(androidTarget.getVersion().getApiLevel())); + + // always check the manifest minSdkVersion. + checkManifest(antProject, androidTarget.getVersion()); + + // sets up the properties to find android.jar/framework.aidl/target tools + String androidJar = androidTarget.getPath(IAndroidTarget.ANDROID_JAR); + antProject.setProperty(mAndroidJarFileOut, androidJar); + + String androidAidl = androidTarget.getPath(IAndroidTarget.ANDROID_AIDL); + antProject.setProperty(mAndroidAidlFileOut, androidAidl); + + // sets up the boot classpath + + // create the Path object + Path bootclasspath = new Path(antProject); + + // create a PathElement for the framework jar + PathElement element = bootclasspath.createPathElement(); + element.setPath(androidJar); + + // create PathElement for each optional library. + IOptionalLibrary[] libraries = androidTarget.getOptionalLibraries(); + if (libraries != null) { + HashSet<String> visitedJars = new HashSet<String>(); + for (IOptionalLibrary library : libraries) { + String jarPath = library.getJarPath(); + if (visitedJars.contains(jarPath) == false) { + visitedJars.add(jarPath); + + element = bootclasspath.createPathElement(); + element.setPath(library.getJarPath()); + } + } + } + + // sets the path in the project with a reference + antProject.addReference(mBootClassPathOut, bootclasspath); + } + + /** + * Checks the manifest <code>minSdkVersion</code> attribute. + * @param antProject the ant project + * @param androidVersion the version of the platform the project is compiling against. + */ + private void checkManifest(Project antProject, AndroidVersion androidVersion) { + try { + File manifest = new File(antProject.getBaseDir(), SdkConstants.FN_ANDROID_MANIFEST_XML); + + XPath xPath = AndroidXPathFactory.newXPath(); + + // check the package name. + 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. + // only need to check that the package has 2 segments + if (value.indexOf('.') == -1) { + throw new BuildException(String.format( + "Application package '%1$s' must have a minimum of 2 segments.", + value)); + } + } + + // check the minSdkVersion value + value = xPath.evaluate( + "/" + AndroidManifest.NODE_MANIFEST + + "/" + AndroidManifest.NODE_USES_SDK + + "/@" + AndroidXPathFactory.DEFAULT_NS_PREFIX + ":" + + AndroidManifest.ATTRIBUTE_MIN_SDK_VERSION, + new InputSource(new FileInputStream(manifest))); + + if (androidVersion.isPreview()) { + // in preview mode, the content of the minSdkVersion must match exactly the + // platform codename. + String codeName = androidVersion.getCodename(); + if (codeName.equals(value) == false) { + throw new BuildException(String.format( + "For '%1$s' SDK Preview, attribute minSdkVersion in AndroidManifest.xml must be '%1$s' (current: %2$s)", + codeName, value)); + } + + // set the API level to the previous API level (which is actually the value in + // androidVersion.) + antProject.setProperty(mTargetApiOut, + Integer.toString(androidVersion.getApiLevel())); + + } else if (value.length() > 0) { + // for normal platform, we'll only display warnings if the value is lower or higher + // than the target api level. + // First convert to an int. + int minSdkValue = -1; + try { + minSdkValue = Integer.parseInt(value); + } catch (NumberFormatException e) { + // looks like it's not a number: error! + throw new BuildException(String.format( + "Attribute %1$s in AndroidManifest.xml must be an Integer!", + AndroidManifest.ATTRIBUTE_MIN_SDK_VERSION)); + } + + // set the target api to the value + antProject.setProperty(mTargetApiOut, value); + + int projectApiLevel = androidVersion.getApiLevel(); + if (minSdkValue > androidVersion.getApiLevel()) { + System.out.println(String.format( + "WARNING: Attribute %1$s in AndroidManifest.xml (%2$d) is higher than the project target API level (%3$d)", + AndroidManifest.ATTRIBUTE_MIN_SDK_VERSION, + minSdkValue, projectApiLevel)); + } + } else { + // no minSdkVersion? display a warning + System.out.println( + "WARNING: No minSdkVersion value set. Application will install on all Android versions."); + + // set the target api to 1 + antProject.setProperty(mTargetApiOut, "1"); + } + + } catch (XPathExpressionException e) { + throw new BuildException(e); + } catch (FileNotFoundException e) { + throw new BuildException(e); + } + } +} diff --git a/anttasks/src/com/android/ant/GetTypeTask.java b/anttasks/src/com/android/ant/GetTypeTask.java new file mode 100644 index 0000000..b11e9f2 --- /dev/null +++ b/anttasks/src/com/android/ant/GetTypeTask.java @@ -0,0 +1,109 @@ +/* + * Copyright (C) 2012 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 com.android.sdklib.SdkConstants; +import com.android.sdklib.internal.project.ProjectProperties; +import com.android.sdklib.xml.AndroidManifest; +import com.android.sdklib.xml.AndroidXPathFactory; + +import org.apache.tools.ant.BuildException; +import org.apache.tools.ant.Project; +import org.apache.tools.ant.Task; +import org.xml.sax.InputSource; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; + +import javax.xml.xpath.XPath; +import javax.xml.xpath.XPathExpressionException; + +/** + * Task to query the type of the current project. + * + * Out params: + * + * <code>projectTypeOut</code>: String value containing the type of the project. Possible values + * are 'app', 'library', 'test', 'test-app' + * + */ +public class GetTypeTask extends Task { + + private String mProjectTypeOut; + + public void setProjectTypeOut(String projectTypeOut) { + mProjectTypeOut = projectTypeOut; + } + + @Override + public void execute() throws BuildException { + if (mProjectTypeOut == null) { + throw new BuildException("Missing attribute projectTypeOut"); + } + + Project antProject = getProject(); + + String libraryProp = antProject.getProperty(ProjectProperties.PROPERTY_LIBRARY); + if (libraryProp != null) { + if (Boolean.valueOf(libraryProp).booleanValue()) { + System.out.println("Project Type: Android Library"); + + antProject.setProperty(mProjectTypeOut, "library"); + return; + } + } + + if (antProject.getProperty(ProjectProperties.PROPERTY_TESTED_PROJECT) != null) { + System.out.println("Project Type: Test Application"); + + antProject.setProperty(mProjectTypeOut, "test"); + return; + } + + // we also need to check if the Manifest doesn't have some instrumentation which + // means the app is a self-contained test project. + try { + File manifest = new File(antProject.getBaseDir(), SdkConstants.FN_ANDROID_MANIFEST_XML); + XPath xPath = AndroidXPathFactory.newXPath(); + + // check the present of /manifest/instrumentation/ + String value = xPath.evaluate( + "/" + AndroidManifest.NODE_MANIFEST + + "/" + AndroidManifest.NODE_INSTRUMENTATION + + "/@" + AndroidXPathFactory.DEFAULT_NS_PREFIX + + ":" + AndroidManifest.ATTRIBUTE_TARGET_PACKAGE, + new InputSource(new FileInputStream(manifest))); + + if (value != null && value.length() > 0) { + System.out.println("Project Type: Self-Tested Application"); + + antProject.setProperty(mProjectTypeOut, "test-app"); + return; + } + } catch (XPathExpressionException e) { + throw new BuildException(e); + } catch (FileNotFoundException e) { + throw new BuildException(e); + } + + // default case + System.out.println("Project Type: Application"); + + antProject.setProperty(mProjectTypeOut, "app"); + } +} diff --git a/anttasks/src/com/android/ant/NewSetupTask.java b/anttasks/src/com/android/ant/NewSetupTask.java deleted file mode 100644 index c74b946..0000000 --- a/anttasks/src/com/android/ant/NewSetupTask.java +++ /dev/null @@ -1,764 +0,0 @@ -/* - * Copyright (C) 2009 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 com.android.io.FileWrapper; -import com.android.io.FolderWrapper; -import com.android.sdklib.AndroidVersion; -import com.android.sdklib.IAndroidTarget; -import com.android.sdklib.IAndroidTarget.IOptionalLibrary; -import com.android.sdklib.ISdkLog; -import com.android.sdklib.SdkConstants; -import com.android.sdklib.SdkManager; -import com.android.sdklib.build.JarListSanitizer; -import com.android.sdklib.build.JarListSanitizer.DifferentLibException; -import com.android.sdklib.build.JarListSanitizer.Sha1Exception; -import com.android.sdklib.internal.project.ProjectProperties; -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; -import org.apache.tools.ant.Task; -import org.apache.tools.ant.types.Path; -import org.apache.tools.ant.types.Path.PathElement; -import org.apache.tools.ant.util.DeweyDecimal; -import org.xml.sax.InputSource; - -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.FilenameFilter; -import java.io.IOException; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Locale; - -import javax.xml.xpath.XPath; -import javax.xml.xpath.XPathExpressionException; - -/** - * Setup Ant task. This task accomplishes: - * <ul> - * <li>Gets the project target hash string from {@link ProjectProperties#PROPERTY_TARGET}, - * and resolves it to get the project's {@link IAndroidTarget}.</li> - * - * <li>Sets up properties so that aapt can find the android.jar and other files/folders in - * the resolved target.</li> - * - * <li>Sets up the boot classpath ref so that the <code>javac</code> task knows where to find - * the libraries. This includes the default android.jar from the resolved target but also optional - * libraries provided by the target (if any, when the target is an add-on).</li> - * - * <li>Resolve library dependencies and setup various Path references for them</li> - * </ul> - * - * This is used in the main rules file only. - * - */ -public class NewSetupTask extends Task { - private final static String ANT_MIN_VERSION = "1.8.0"; - - private String mProjectTypeOut; - private String mAndroidJarFileOut; - private String mAndroidAidlFileOut; - private String mRenderScriptExeOut; - private String mRenderScriptIncludeDirOut; - private String mBootclasspathrefOut; - private String mProjectLibrariesRootOut; - private String mProjectLibrariesResOut; - private String mProjectLibrariesPackageOut; - private String mProjectLibrariesJarsOut; - private String mProjectLibrariesLibsOut; - private String mTargetApiOut; - private boolean mVerbose = false; - - public void setProjectTypeOut(String projectTypeOut) { - mProjectTypeOut = projectTypeOut; - } - - public void setAndroidJarFileOut(String androidJarFileOut) { - mAndroidJarFileOut = androidJarFileOut; - } - - public void setAndroidAidlFileOut(String androidAidlFileOut) { - mAndroidAidlFileOut = androidAidlFileOut; - } - - public void setRenderScriptExeOut(String renderScriptExeOut) { - mRenderScriptExeOut = renderScriptExeOut; - } - - public void setRenderScriptIncludeDirOut(String renderScriptIncludeDirOut) { - mRenderScriptIncludeDirOut = renderScriptIncludeDirOut; - } - - public void setBootclasspathrefOut(String bootclasspathrefOut) { - mBootclasspathrefOut = bootclasspathrefOut; - } - - public void setProjectLibrariesRootOut(String projectLibrariesRootOut) { - mProjectLibrariesRootOut = projectLibrariesRootOut; - } - - public void setProjectLibrariesResOut(String projectLibrariesResOut) { - mProjectLibrariesResOut = projectLibrariesResOut; - } - - public void setProjectLibrariesPackageOut(String projectLibrariesPackageOut) { - mProjectLibrariesPackageOut = projectLibrariesPackageOut; - } - - public void setProjectLibrariesJarsOut(String projectLibrariesJarsOut) { - mProjectLibrariesJarsOut = projectLibrariesJarsOut; - } - - public void setProjectLibrariesLibsOut(String projectLibrariesLibsOut) { - mProjectLibrariesLibsOut = projectLibrariesLibsOut; - } - - public void setTargetApiOut(String targetApiOut) { - mTargetApiOut = targetApiOut; - } - - /** - * Sets the value of the "verbose" attribute. - * @param verbose the value. - */ - public void setVerbose(boolean verbose) { - mVerbose = verbose; - } - - @Override - public void execute() throws BuildException { - if (mProjectTypeOut == null) { - throw new BuildException("Missing attribute projectTypeOut"); - } - if (mAndroidJarFileOut == null) { - throw new BuildException("Missing attribute androidJarFileOut"); - } - if (mAndroidAidlFileOut == null) { - throw new BuildException("Missing attribute androidAidlFileOut"); - } - if (mRenderScriptExeOut == null) { - throw new BuildException("Missing attribute renderScriptExeOut"); - } - if (mRenderScriptIncludeDirOut == null) { - throw new BuildException("Missing attribute renderScriptIncludeDirOut"); - } - if (mBootclasspathrefOut == null) { - throw new BuildException("Missing attribute bootclasspathrefOut"); - } - if (mProjectLibrariesRootOut == null) { - throw new BuildException("Missing attribute projectLibrariesRootOut"); - } - if (mProjectLibrariesResOut == null) { - throw new BuildException("Missing attribute projectLibrariesResOut"); - } - if (mProjectLibrariesPackageOut == null) { - throw new BuildException("Missing attribute projectLibrariesPackageOut"); - } - if (mProjectLibrariesJarsOut == null) { - throw new BuildException("Missing attribute projectLibrariesJarsOut"); - } - if (mProjectLibrariesLibsOut == null) { - throw new BuildException("Missing attribute projectLibrariesLibsOut"); - } - if (mTargetApiOut == null) { - throw new BuildException("Missing attribute targetApiOut"); - } - - - Project antProject = getProject(); - - // check the Ant version - DeweyDecimal version = getVersion(antProject); - DeweyDecimal atLeast = new DeweyDecimal(ANT_MIN_VERSION); - if (atLeast.isGreaterThan(version)) { - throw new BuildException( - "The Android Ant-based build system requires Ant " + - ANT_MIN_VERSION + - " or later. Current version is " + - version); - } - - // get the SDK location - File sdkDir = TaskHelper.getSdkLocation(antProject); - String sdkOsPath = sdkDir.getPath(); - - // Make sure the OS sdk path ends with a directory separator - if (sdkOsPath.length() > 0 && !sdkOsPath.endsWith(File.separator)) { - sdkOsPath += File.separator; - } - - // display SDK Tools revision - int toolsRevison = TaskHelper.getToolsRevision(sdkDir); - if (toolsRevison != -1) { - System.out.println("Android SDK Tools Revision " + toolsRevison); - } - - // detect that the platform tools is there. - File platformTools = new File(sdkDir, SdkConstants.FD_PLATFORM_TOOLS); - if (platformTools.isDirectory() == false) { - throw new BuildException(String.format( - "SDK Platform Tools component is missing. " + - "Please install it with the SDK Manager (%1$s%2$c%3$s)", - SdkConstants.FD_TOOLS, - File.separatorChar, - SdkConstants.androidCmdName())); - } - - // get the target property value - String targetHashString = antProject.getProperty(ProjectProperties.PROPERTY_TARGET); - - boolean isTestProject = false; - - if (antProject.getProperty(ProjectProperties.PROPERTY_TESTED_PROJECT) != null) { - isTestProject = true; - } - - if (targetHashString == null) { - throw new BuildException("Android Target is not set."); - } - - // load up the sdk targets. - final ArrayList<String> messages = new ArrayList<String>(); - SdkManager manager = SdkManager.createManager(sdkOsPath, new ISdkLog() { - @Override - public void error(Throwable t, String errorFormat, Object... args) { - if (errorFormat != null) { - messages.add(String.format("Error: " + errorFormat, args)); - } - if (t != null) { - messages.add("Error: " + t.getMessage()); - } - } - - @Override - public void printf(String msgFormat, Object... args) { - messages.add(String.format(msgFormat, args)); - } - - @Override - public void warning(String warningFormat, Object... args) { - messages.add(String.format("Warning: " + warningFormat, args)); - } - }); - - if (manager == null) { - // since we failed to parse the SDK, lets display the parsing output. - for (String msg : messages) { - System.out.println(msg); - } - throw new BuildException("Failed to parse SDK content."); - } - - // resolve it - IAndroidTarget androidTarget = manager.getTargetFromHashString(targetHashString); - - if (androidTarget == null) { - throw new BuildException(String.format( - "Unable to resolve target '%s'", targetHashString)); - } - - // display the project info - System.out.println("Project Target: " + androidTarget.getName()); - if (androidTarget.isPlatform() == false) { - System.out.println("Vendor: " + androidTarget.getVendor()); - System.out.println("Platform Version: " + androidTarget.getVersionName()); - } - System.out.println("API level: " + androidTarget.getVersion().getApiString()); - - // 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(); - } - - if (isLibrary) { - System.out.println("Project Type: Android Library"); - } - - // look for referenced libraries. - processReferencedLibraries(antProject, androidTarget, sdkOsPath); - - // always check the manifest minSdkVersion. - checkManifest(antProject, androidTarget.getVersion()); - - // sets up the properties to find android.jar/framework.aidl/target tools - String androidJar = androidTarget.getPath(IAndroidTarget.ANDROID_JAR); - antProject.setProperty(mAndroidJarFileOut, androidJar); - - String androidAidl = androidTarget.getPath(IAndroidTarget.ANDROID_AIDL); - antProject.setProperty(mAndroidAidlFileOut, androidAidl); - - Path includePath = new Path(antProject); - PathElement element = includePath.createPathElement(); - element.setPath(androidTarget.getPath(IAndroidTarget.ANDROID_RS)); - element = includePath.createPathElement(); - element.setPath(androidTarget.getPath(IAndroidTarget.ANDROID_RS_CLANG)); - antProject.setProperty(mRenderScriptIncludeDirOut, includePath.toString()); - - // TODO: figure out the actual compiler to use based on the minSdkVersion - antProject.setProperty(mRenderScriptExeOut, - sdkOsPath + SdkConstants.OS_SDK_PLATFORM_TOOLS_FOLDER + - SdkConstants.FN_RENDERSCRIPT); - - // sets up the boot classpath - - // create the Path object - Path bootclasspath = new Path(antProject); - - // create a PathElement for the framework jar - element = bootclasspath.createPathElement(); - element.setPath(androidJar); - - // create PathElement for each optional library. - IOptionalLibrary[] libraries = androidTarget.getOptionalLibraries(); - if (libraries != null) { - HashSet<String> visitedJars = new HashSet<String>(); - for (IOptionalLibrary library : libraries) { - String jarPath = library.getJarPath(); - if (visitedJars.contains(jarPath) == false) { - visitedJars.add(jarPath); - - element = bootclasspath.createPathElement(); - element.setPath(library.getJarPath()); - } - } - } - - // sets the path in the project with a reference - antProject.addReference(mBootclasspathrefOut, bootclasspath); - - // finally set the project type. - if (isLibrary) { - antProject.setProperty(mProjectTypeOut, "library"); - } else if (isTestProject) { - antProject.setProperty(mProjectTypeOut, "test"); - } else { - antProject.setProperty(mProjectTypeOut, "project"); - } - } - - /** - * Checks the manifest <code>minSdkVersion</code> attribute. - * @param antProject the ant project - * @param androidVersion the version of the platform the project is compiling against. - */ - private void checkManifest(Project antProject, AndroidVersion androidVersion) { - try { - File manifest = new File(antProject.getBaseDir(), SdkConstants.FN_ANDROID_MANIFEST_XML); - - XPath xPath = AndroidXPathFactory.newXPath(); - - // check the package name. - 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. - // only need to check that the package has 2 segments - if (value.indexOf('.') == -1) { - throw new BuildException(String.format( - "Application package '%1$s' must have a minimum of 2 segments.", - value)); - } - } - - // check the minSdkVersion value - value = xPath.evaluate( - "/" + AndroidManifest.NODE_MANIFEST + - "/" + AndroidManifest.NODE_USES_SDK + - "/@" + AndroidXPathFactory.DEFAULT_NS_PREFIX + ":" + - AndroidManifest.ATTRIBUTE_MIN_SDK_VERSION, - new InputSource(new FileInputStream(manifest))); - - if (androidVersion.isPreview()) { - // in preview mode, the content of the minSdkVersion must match exactly the - // platform codename. - String codeName = androidVersion.getCodename(); - if (codeName.equals(value) == false) { - throw new BuildException(String.format( - "For '%1$s' SDK Preview, attribute minSdkVersion in AndroidManifest.xml must be '%1$s' (current: %2$s)", - codeName, value)); - } - - // set the API level to the previous API level (which is actually the value in - // androidVersion.) - antProject.setProperty(mTargetApiOut, - Integer.toString(androidVersion.getApiLevel())); - - } else if (value.length() > 0) { - // for normal platform, we'll only display warnings if the value is lower or higher - // than the target api level. - // First convert to an int. - int minSdkValue = -1; - try { - minSdkValue = Integer.parseInt(value); - } catch (NumberFormatException e) { - // looks like it's not a number: error! - throw new BuildException(String.format( - "Attribute %1$s in AndroidManifest.xml must be an Integer!", - AndroidManifest.ATTRIBUTE_MIN_SDK_VERSION)); - } - - // set the target api to the value - antProject.setProperty(mTargetApiOut, value); - - int projectApiLevel = androidVersion.getApiLevel(); - if (minSdkValue > androidVersion.getApiLevel()) { - System.out.println(String.format( - "WARNING: Attribute %1$s in AndroidManifest.xml (%2$d) is higher than the project target API level (%3$d)", - AndroidManifest.ATTRIBUTE_MIN_SDK_VERSION, - minSdkValue, projectApiLevel)); - } - } else { - // no minSdkVersion? display a warning - System.out.println( - "WARNING: No minSdkVersion value set. Application will install on all Android versions."); - - // set the target api to 1 - antProject.setProperty(mTargetApiOut, "1"); - } - - } catch (XPathExpressionException e) { - throw new BuildException(e); - } catch (FileNotFoundException e) { - throw new BuildException(e); - } - } - - private void processReferencedLibraries(Project antProject, IAndroidTarget androidTarget, - String sdkLocation) { - // prepare several paths for future tasks - Path rootPath = new Path(antProject); - Path resPath = new Path(antProject); - Path libsPath = new Path(antProject); - StringBuilder packageStrBuilder = new StringBuilder(); - - // list of all the jars that are on the classpath. This will receive the - // project's libs/*.jar files, the Library Projects output and their own libs/*.jar - List<File> jars = new ArrayList<File>(); - - FilenameFilter filter = new FilenameFilter() { - @Override - public boolean accept(File dir, String name) { - return name.toLowerCase(Locale.US).endsWith(".jar"); - } - }; - - System.out.println("\n------------------\nResolving library dependencies:"); - - // get the list of ordered libraries. - ArrayList<File> libraries = getProjectLibraries(antProject); - - if (libraries.size() > 0) { - System.out.println("------------------\nOrdered libraries:"); - - // use that same order to return ordered res folders, as well as jars and output. - for (File library : libraries) { - // get the root path. - String libRootPath = library.getAbsolutePath(); - System.out.println(libRootPath); - - // get the res path. Always $PROJECT/res as well as the crunch cache. - PathElement element = resPath.createPathElement(); - element.setPath(libRootPath + "/" + SdkConstants.FD_OUTPUT + - "/" + SdkConstants.FD_RES); - element = resPath.createPathElement(); - element.setPath(libRootPath + "/" + SdkConstants.FD_RESOURCES); - - // get the libs path. Always $PROJECT/libs - element = libsPath.createPathElement(); - element.setPath(libRootPath + "/" + SdkConstants.FD_NATIVE_LIBS); - - // get the jars from it too. - // 1. the library code jar - jars.add(new File(libRootPath + "/" + SdkConstants.FD_OUTPUT + - "/" + SdkConstants.FN_CLASSES_JAR)); - - // 2. the 3rd party jar files - File libsFolder = new File(library, SdkConstants.FD_NATIVE_LIBS); - File[] jarFiles = libsFolder.listFiles(filter); - if (jarFiles != null) { - for (File jarFile : jarFiles) { - jars.add(jarFile); - } - } - - // get the package from the manifest. - FileWrapper manifest = new FileWrapper(library, - SdkConstants.FN_ANDROID_MANIFEST_XML); - - try { - String value = AndroidManifest.getPackage(manifest); - if (value != null) { // aapt will complain if it's missing. - packageStrBuilder.append(';'); - packageStrBuilder.append(value); - } - } catch (Exception e) { - throw new BuildException(e); - } - } - - // now use the reverse order to get the full list of library project. - // This is used to compile all the libraries, direct or indirect dependencies, - // in a single pass. - final int count = libraries.size(); - for (int i = count - 1 ; i >= 0 ; i--) { - File library = libraries.get(i); - - PathElement element = rootPath.createPathElement(); - element.setPath(library.getAbsolutePath()); - } - System.out.println(); - - } else { - System.out.println("No library dependencies.\n"); - } - - System.out.println("------------------"); - - boolean hasLibraries = jars.size() > 0; - - if (androidTarget.getVersion().getApiLevel() <= 15) { - System.out.println("API<=15: Adding annotations.jar to the classpath.\n"); - - jars.add(new File(sdkLocation + "/" + SdkConstants.FD_TOOLS + - "/" + SdkConstants.FD_SUPPORT + - "/" + SdkConstants.FN_ANNOTATIONS_JAR)); - - System.out.println("------------------"); - } - - // even with no libraries, always setup these so that various tasks in Ant don't complain - // (the task themselves can handle a ref to an empty Path) - antProject.addReference(mProjectLibrariesLibsOut, libsPath); - - // the rest is done only if there's a library. - if (hasLibraries) { - antProject.addReference(mProjectLibrariesRootOut, rootPath); - antProject.addReference(mProjectLibrariesResOut, resPath); - antProject.setProperty(mProjectLibrariesPackageOut, packageStrBuilder.toString()); - } - - // add the project's own content of libs/*.jar - File libsFolder = new File(antProject.getBaseDir(), SdkConstants.FD_NATIVE_LIBS); - File[] jarFiles = libsFolder.listFiles(filter); - if (jarFiles != null) { - for (File jarFile : jarFiles) { - jars.add(jarFile); - } - } - - // now sanitize the path to remove dups - jars = sanitizePaths(antProject, jars); - - // and create a Path object for them - Path jarsPath = new Path(antProject); - if (mVerbose) { - System.out.println("Sanitized jar list:"); - } - for (File f : jars) { - if (mVerbose) { - System.out.println("- " + f.getAbsolutePath()); - } - PathElement element = jarsPath.createPathElement(); - element.setPath(f.getAbsolutePath()); - } - antProject.addReference(mProjectLibrariesJarsOut, jarsPath); - - if (mVerbose) { - System.out.println(); - } - } - - /** - * Returns all the library dependencies of a given Ant project. - * @param antProject the Ant project - * @return a list of properties, sorted from highest priority to lowest. - */ - private ArrayList<File> getProjectLibraries(final Project antProject) { - ArrayList<File> libraries = new ArrayList<File>(); - File baseDir = antProject.getBaseDir(); - - // get the top level list of library dependencies. - List<File> topLevelLibraries = getDirectDependencies(baseDir, new IPropertySource() { - @Override - public String getProperty(String name) { - return antProject.getProperty(name); - } - }); - - // process the libraries in case they depend on other libraries. - resolveFullLibraryDependencies(topLevelLibraries, libraries); - - return libraries; - } - - /** - * Resolves a given list of libraries, finds out if they depend on other libraries, and - * returns a full list of all the direct and indirect dependencies in the proper order (first - * is higher priority when calling aapt). - * @param inLibraries the libraries to resolve - * @param outLibraries where to store all the libraries. - */ - private void resolveFullLibraryDependencies(List<File> inLibraries, List<File> outLibraries) { - // loop in the inverse order to resolve dependencies on the libraries, so that if a library - // is required by two higher level libraries it can be inserted in the correct place - for (int i = inLibraries.size() - 1 ; i >= 0 ; i--) { - File library = inLibraries.get(i); - - // get the default.property file for it - final ProjectProperties projectProp = ProjectProperties.load( - new FolderWrapper(library), PropertyType.PROJECT); - - // get its libraries - List<File> dependencies = getDirectDependencies(library, new IPropertySource() { - @Override - public String getProperty(String name) { - return projectProp.getProperty(name); - } - }); - - // resolve the dependencies for those libraries - resolveFullLibraryDependencies(dependencies, outLibraries); - - // and add the current one (if needed) in front (higher priority) - if (outLibraries.contains(library) == false) { - outLibraries.add(0, library); - } - } - } - - public interface IPropertySource { - String getProperty(String name); - } - - /** - * Returns the top level library dependencies of a given <var>source</var> representing a - * project properties. - * @param baseFolder the base folder of the project (to resolve relative paths) - * @param source a source of project properties. - */ - private List<File> getDirectDependencies(File baseFolder, IPropertySource source) { - ArrayList<File> libraries = new ArrayList<File>(); - - // first build the list. they are ordered highest priority first. - int index = 1; - while (true) { - String propName = ProjectProperties.PROPERTY_LIB_REF + Integer.toString(index++); - String rootPath = source.getProperty(propName); - - if (rootPath == null) { - break; - } - - try { - File library = new File(baseFolder, rootPath).getCanonicalFile(); - - // check for validity - File projectProp = new File(library, PropertyType.PROJECT.getFilename()); - if (projectProp.isFile() == false) { - // error! - throw new BuildException(String.format( - "%1$s resolve to a path with no %2$s file for project %3$s", rootPath, - PropertyType.PROJECT.getFilename(), baseFolder.getAbsolutePath())); - } - - if (libraries.contains(library) == false) { - System.out.println(String.format("%1$s: %2$s => %3$s", - baseFolder.getAbsolutePath(), rootPath, library.getAbsolutePath())); - - libraries.add(library); - } - } catch (IOException e) { - throw new BuildException("Failed to resolve library path: " + rootPath, e); - } - } - - return libraries; - } - - /** - * Returns the Ant version as a {@link DeweyDecimal} object. - * - * This is based on the implementation of - * org.apache.tools.ant.taskdefs.condition.AntVersion.getVersion() - * - * @param antProject the current ant project. - * @return the ant version. - */ - private DeweyDecimal getVersion(Project antProject) { - char[] versionString = antProject.getProperty("ant.version").toCharArray(); - StringBuilder sb = new StringBuilder(); - boolean foundFirstDigit = false; - for (int i = 0; i < versionString.length; i++) { - if (Character.isDigit(versionString[i])) { - sb.append(versionString[i]); - foundFirstDigit = true; - } - if (versionString[i] == '.' && foundFirstDigit) { - sb.append(versionString[i]); - } - if (Character.isLetter(versionString[i]) && foundFirstDigit) { - break; - } - } - return new DeweyDecimal(sb.toString()); - } - - private List<File> sanitizePaths(Project antProject, List<File> paths) { - // first get the non-files. - List<File> results = new ArrayList<File>(); - for (int i = 0 ; i < paths.size() ;) { - File f = paths.get(i); - // TEMP WORKAROUND: ignore classes.jar as all the output of libraries are - // called the same (in Ant) but are not actually the same jar file. - // TODO: Be aware of library output vs. regular jar dependency. - if (f.isFile() && f.getName().equals(SdkConstants.FN_CLASSES_JAR) == false) { - i++; - } else { - results.add(f); - paths.remove(i); - } - } - - File outputFile = new File(antProject.getProperty("out.absolute.dir")); - JarListSanitizer sanitizer = new JarListSanitizer(outputFile); - - try { - results.addAll(sanitizer.sanitize(paths)); - } catch (DifferentLibException e) { - String[] details = e.getDetails(); - for (String s : details) { - System.err.println(s); - } - throw new BuildException(e.getMessage(), e); - } catch (Sha1Exception e) { - throw new BuildException( - "Failed to compute sha1 for " + e.getJarFile().getAbsolutePath(), e); - } - - return results; - } -} diff --git a/anttasks/src/com/android/ant/RenderScriptTask.java b/anttasks/src/com/android/ant/RenderScriptTask.java index 937ceac..b64a731 100644 --- a/anttasks/src/com/android/ant/RenderScriptTask.java +++ b/anttasks/src/com/android/ant/RenderScriptTask.java @@ -43,7 +43,7 @@ import java.util.List; public class RenderScriptTask extends MultiFilesTask { private String mExecutable; - private Path mFramework; + private Path mIncludePath; private String mGenFolder; private String mResFolder; private final List<Path> mPaths = new ArrayList<Path>(); @@ -79,7 +79,7 @@ public class RenderScriptTask extends MultiFilesTask { task.setExecutable(mExecutable); task.setFailonerror(true); - for (String path : mFramework.list()) { + for (String path : mIncludePath.list()) { File res = new File(path); if (res.isDirectory()) { task.createArg().setValue("-I"); @@ -163,8 +163,8 @@ public class RenderScriptTask extends MultiFilesTask { mExecutable = TaskHelper.checkSinglePath("executable", executable); } - public void setFramework(Path value) { - mFramework = value; + public void setIncludePath(Path value) { + mIncludePath = value; } public void setGenFolder(Path value) { @@ -208,8 +208,8 @@ public class RenderScriptTask extends MultiFilesTask { if (mExecutable == null) { throw new BuildException("RenderScriptTask's 'executable' is required."); } - if (mFramework == null) { - throw new BuildException("RenderScriptTask's 'framework' is required."); + if (mIncludePath == null) { + throw new BuildException("RenderScriptTask's 'includePath' is required."); } if (mGenFolder == null) { throw new BuildException("RenderScriptTask's 'genFolder' is required."); diff --git a/anttasks/src/com/android/ant/SetupTask.java b/anttasks/src/com/android/ant/SetupTask.java deleted file mode 100644 index c0bc55d..0000000 --- a/anttasks/src/com/android/ant/SetupTask.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (C) 2009 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.Task; -import org.apache.tools.ant.taskdefs.ImportTask; - -/** - * Legacy setupTask class used by older build system. - * - * If this is used it actually only display an error about the need to update the build file. - */ -public final class SetupTask extends Task { - - /** - * @param b unused. - * - * @deprecated only present because the original {@link SetupTask} extends {@link ImportTask}. - */ - @Deprecated - public void setImport(boolean b) { - // do nothing - } - - @Override - public void execute() throws BuildException { - throw new BuildException("\n\nError. You are using an obsolete build.xml\n" + - "You need to delete it and regenerate it using\n" + - "\tandroid update project\n"); - } -} diff --git a/changes.txt b/changes.txt index d60be8e..67f6cf2 100644 --- a/changes.txt +++ b/changes.txt @@ -1,6 +1,14 @@ Change log for Android SDK Tools. +Revision 20: +- Ant build system: + * the location of the SDK can now be set through the ANDROID_HOME + environment variable (requires updating the project's build.xml file) + * Fixed issues with compilation, deployment of test projects and running tests. + Both separate test projects and self-contained app+test projects now work. + Revision 19: +- Fix GPU rendering Revision 18: * Fix Ant issues where some jar libraries in libs/ are not picked in some diff --git a/files/ant/build.xml b/files/ant/build.xml index 7d2a6d7..856a501 100644 --- a/files/ant/build.xml +++ b/files/ant/build.xml @@ -27,7 +27,7 @@ <!-- **************** Overridable Properties *************** --> <!-- ******************************************************* --> - <!-- You can override these values in your build.xml or build.properties. + <!-- You can override these values in your build.xml or ant.properties. Overriding any other properties may result in broken build. --> <!-- Tells adb which device to target. You can change this from the command line @@ -72,8 +72,28 @@ </path> <!-- Custom tasks --> - <taskdef name="setup" - classname="com.android.ant.NewSetupTask" + <taskdef name="checkenv" + classname="com.android.ant.CheckEnvTask" + classpathref="android.antlibs" /> + + <taskdef name="gettype" + classname="com.android.ant.GetTypeTask" + classpathref="android.antlibs" /> + + <taskdef name="gettarget" + classname="com.android.ant.GetTargetTask" + classpathref="android.antlibs" /> + + <taskdef name="getlibs" + classname="com.android.ant.GetLibraryListTask" + classpathref="android.antlibs" /> + + <taskdef name="dependency" + classname="com.android.ant.ComputeDependencyTask" + classpathref="android.antlibs" /> + + <taskdef name="testedprojectclasspath" + classname="com.android.ant.ComputeProjectClasspathTask" classpathref="android.antlibs" /> <taskdef name="aapt" @@ -163,8 +183,13 @@ <property name="aidl" location="${android.platform.tools.dir}/aidl${exe}" /> <property name="aapt" location="${android.platform.tools.dir}/aapt${exe}" /> <property name="dx" location="${android.platform.tools.dir}/dx${bat}" /> - <!-- renderscript location is set by NewSetupTask since we have a choice of - several executables based on minSdkVersion --> + <property name="renderscript" location="${android.platform.tools.dir}/llvm-rs-cc${exe}"/> + + <!-- Renderscript include Path --> + <path id="android.renderscript.include.path"> + <pathelement location="${android.platform.tools.dir}/renderscript/include" /> + <pathelement location="${android.platform.tools.dir}/renderscript/clang-include" /> + </path> <!-- Intermediate files --> <property name="dex.file.name" value="classes.dex" /> @@ -276,7 +301,7 @@ </condition> <else> <path id="out.dex.jar.input.ref"> - <path refid="project.libraries.jars" /> + <path refid="project.all.jars.path" /> </path> </else> </if> @@ -316,9 +341,9 @@ buildType="${build.is.packaging.debug}/${build.is.signing.debug}"> <dex path="${intermediate.dex.file}"/> <sourcefolder path="${source.absolute.dir}"/> - <jarfile refid="project.libraries.jars" /> + <jarfile refid="project.all.jars.path" /> <nativefolder path="${native.libs.absolute.dir}" /> - <nativefolder refid="project.libraries.libs" /> + <nativefolder refid="project.library.native.folder.path" /> <extra-jars/> </apkbuilder> </sequential> @@ -353,7 +378,7 @@ <arg value="coverage" /> <arg value="@{emma.enabled}" /> <extra-instrument-args /> - <arg value="${manifest.package}/${test.runner}" /> + <arg value="${project.app.package}/${test.runner}" /> </exec> </sequential> </macrodef> @@ -393,104 +418,86 @@ <!-- ******************** Build Targets ******************** --> <!-- ******************************************************* --> + <!-- Basic Ant + SDK check --> + <target name="-check-env"> + <checkenv /> + </target> + <!-- target to disable building dependencies --> <target name="nodeps"> <property name="dont.do.deps" value="true" /> </target> - <!-- this target simply force running -setup making - the project info be read. To be used as - ant all clean - to clean the main project as well as the libraries and tested project --> - <target name="all" depends="-setup"/> + <!-- generic setup --> + <target name="-setup" depends="-check-env"> + <echo level="info">Project Name: ${ant.project.name}</echo> + <gettype projectTypeOut="project.type" /> + + <!-- sets a few boolean based on project.type + to make the if task easier --> + <condition property="project.is.library" value="true" else="false"> + <equals arg1="${project.type}" arg2="library" /> + </condition> + <condition property="project.is.test" value="true" else="false"> + <equals arg1="${project.type}" arg2="test" /> + </condition> + <condition property="project.is.testapp" value="true" else="false"> + <equals arg1="${project.type}" arg2="test-app" /> + </condition> + + <!-- If a test project, resolve absolute path to tested project. --> + <if condition="${project.is.test}"> + <then> + <property name="tested.project.absolute.dir" location="${tested.project.dir}" /> + </then> + </if> + + <!-- get the project manifest package --> + <xpath input="AndroidManifest.xml" + expression="/manifest/@package" output="project.app.package" /> + + </target> <!-- empty default pre-clean target. Create a similar target in your build.xml and it'll be called instead of this one. --> <target name="-pre-clean"/> <!-- clean target --> - <target name="clean" depends="-pre-clean" + <target name="clean" depends="-setup, -pre-clean" description="Removes output files created by other targets."> <delete dir="${out.absolute.dir}" verbose="${verbose}" /> <delete dir="${gen.absolute.dir}" verbose="${verbose}" /> - <!-- if we know about a tested project or libraries, we clean them too. This - will only work if the target 'all' was called first --> + <!-- if we know about a tested project or libraries, we clean them too. --> <if condition="${project.is.test}"> <then> <property name="tested.project.absolute.dir" location="${tested.project.dir}" /> <subant failonerror="true"> <fileset dir="${tested.project.absolute.dir}" includes="build.xml" /> - <target name="all" /> - <target name="clean" /> - </subant> - </then> - </if> - - <if> - <condition> - <isreference refid="project.libraries" /> - <not><isset property="dont.do.deps" /></not> - </condition> - <then> - <subant - buildpathref="project.libraries" - antfile="build.xml" - failonerror="true"> - <target name="nodeps" /> <target name="clean" /> </subant> </then> </if> - </target> - <!-- generic setup --> - <target name="-setup"> + <!-- get all the libraries --> <if> - <condition> - <not><isset property="setup.done" /></not> - </condition> + <condition><not><isset property="dont.do.deps" /></not></condition> <then> - <echo level="info">Creating output directories if needed...</echo> - <mkdir dir="${resource.absolute.dir}" /> - <mkdir dir="${jar.libs.absolute.dir}" /> - <mkdir dir="${out.absolute.dir}" /> - <mkdir dir="${out.res.absolute.dir}" /> - - <property name="setup.done" value="true" /> - <echo level="info">Gathering info for ${ant.project.name}...</echo> - <!-- load project properties, resolve Android target, library dependencies - and set some properties with the results. - All property names are passed as parameters ending in -Out --> - <setup - projectTypeOut="android.project.type" - androidJarFileOut="android.jar" - androidAidlFileOut="android.aidl" - renderScriptExeOut="renderscript" - renderScriptIncludeDirOut="android.rs" - bootclasspathrefOut="android.target.classpath" - projectLibrariesRootOut="project.libraries" - projectLibrariesJarsOut="project.libraries.jars" - projectLibrariesResOut="project.libraries.res" - projectLibrariesPackageOut="project.libraries.package" - projectLibrariesLibsOut="project.libraries.libs" - targetApiOut="target.api" - verbose="${verbose}" - /> - - <!-- sets a few boolean based on android.project.type - to make the if task easier --> - <condition property="project.is.library" else="false"> - <equals arg1="${android.project.type}" arg2="library" /> - </condition> - <condition property="project.is.test" else="false"> - <equals arg1="${android.project.type}" arg2="test" /> - </condition> - - <!-- If a test project, resolve absolute path to tested project. --> - <if condition="${project.is.test}"> + <getlibs libraryFolderPathOut="project.library.folder.path" /> + <if> + <condition> + <isreference refid="project.library.folder.path" /> + </condition> <then> - <property name="tested.project.absolute.dir" location="${tested.project.dir}" /> + <!-- clean the libraries with nodeps since we already + know about all the libraries even the indirect one --> + <subant + buildpathref="project.library.folder.path" + antfile="build.xml" + failonerror="true"> + <target name="nodeps" /> + <target name="clean" /> + </subant> </then> </if> </then> @@ -509,26 +516,69 @@ <property name="build.last.is.packaging.debug" value="" /> <property name="build.last.is.signing.debug" value="" /> + <echo level="info">Resolving Build Target for ${ant.project.name}...</echo> + <!-- load project properties, resolve Android target, library dependencies + and set some properties with the results. + All property names are passed as parameters ending in -Out --> + <gettarget + androidJarFileOut="project.target.android.jar" + androidAidlFileOut="project.target.framework.aidl" + bootClassPathOut="project.target.class.path" + targetApiOut="project.target.apilevel" + minSdkVersionOut="project.minSdkVersion" /> + + <!-- Value of the hasCode attribute (Application node) extracted from manifest file --> + <xpath input="AndroidManifest.xml" expression="/manifest/application/@android:hasCode" + output="manifest.hasCode" default="true"/> + + <echo level="info">----------</echo> + <echo level="info">Creating output directories if needed...</echo> + <mkdir dir="${resource.absolute.dir}" /> + <mkdir dir="${jar.libs.absolute.dir}" /> + <mkdir dir="${out.absolute.dir}" /> + <mkdir dir="${out.res.absolute.dir}" /> + <do-only-if-manifest-hasCode> + <mkdir dir="${gen.absolute.dir}" /> + <mkdir dir="${out.classes.absolute.dir}" /> + </do-only-if-manifest-hasCode> + + <echo level="info">----------</echo> + <echo level="info">Resolving Dependencies for ${ant.project.name}...</echo> + <dependency + libraryFolderPathOut="project.library.folder.path" + libraryPackagesOut="project.library.packages" + libraryResFolderPathOut="project.library.res.folder.path" + libraryNativeFolderPathOut="project.library.native.folder.path" + jarLibraryPathOut="project.all.jars.path" + targetApi="${project.target.apilevel}" + verbose="${verbose}" /> + <!-- compile the libraries if any --> <if> <condition> <and> - <isreference refid="project.libraries" /> + <isreference refid="project.library.folder.path" /> <not><isset property="dont.do.deps" /></not> </and> </condition> <then> - <echo level="info">Building Libraries</echo> + <!-- figure out which target must be used to build the library projects. + If emma is enabled, then use 'instrument' otherwise, use 'debug' --> + <condition property="project.libraries.target" value="instrument" else="${build.target}"> + <istrue value="${build.is.instrumented}" /> + </condition> + + <echo level="info">----------</echo> + <echo level="info">Building Libraries with '${project.libraries.target}'...</echo> + + <!-- no need to build the deps as we have already + the full list of libraries --> <subant failonerror="true" - buildpathref="project.libraries" + buildpathref="project.library.folder.path" antfile="build.xml"> <target name="nodeps" /> - <target name="${build.target}" /> + <target name="${project.libraries.target}" /> </subant> - <echo level="info"></echo> - <echo level="info">############################################</echo> - <echo level="info">**** Back to project ${ant.project.name} ****</echo> - <echo level="info">############################################</echo> </then> </if> @@ -541,20 +591,25 @@ <isset property="emma.enabled" /> </condition> - <echo level="info">Building tested project at ${tested.project.absolute.dir}</echo> + <echo level="info">----------</echo> + <echo level="info">Building tested project at ${tested.project.absolute.dir} with '${tested.project.target}'...</echo> <subant target="${tested.project.target}" failonerror="true"> <fileset dir="${tested.project.absolute.dir}" includes="build.xml" /> </subant> - <echo level="info"></echo> - <echo level="info">############################################</echo> - <echo level="info">**** Back to project ${ant.project.name} ****</echo> - <echo level="info">############################################</echo> + + <!-- get the tested project full classpath to be able to build + the test project --> + <testedprojectclasspath + projectLocation="${tested.project.absolute.dir}" + projectClassPathOut="tested.project.classpath"/> </then> + <else> + <!-- no tested project, make an empty Path object so that javac doesn't + complain --> + <path id="tested.project.classpath" /> + </else> </if> - <!-- Value of the hasCode attribute (Application node) extracted from manifest file --> - <xpath input="AndroidManifest.xml" expression="/manifest/application/@android:hasCode" - output="manifest.hasCode" default="true"/> <!-- If the "debug" build type changed, clear out the compiled code. This is to make sure the new BuildConfig.DEBUG value is picked up @@ -590,11 +645,6 @@ </if> </else> </if> - - <do-only-if-manifest-hasCode> - <mkdir dir="${gen.absolute.dir}" /> - <mkdir dir="${out.classes.absolute.dir}" /> - </do-only-if-manifest-hasCode> </target> <!-- empty default pre-build target. Create a similar target in @@ -605,9 +655,8 @@ <target name="-code-gen"> <do-only-if-manifest-hasCode elseText="hasCode = false. Skipping aidl/renderscript/R.java"> - <echo level="info">----------</echo> <echo level="info">Handling aidl files...</echo> - <aidl executable="${aidl}" framework="${android.aidl}" + <aidl executable="${aidl}" framework="${project.target.framework.aidl}" genFolder="${gen.absolute.dir}"> <source path="${source.absolute.dir}"/> </aidl> @@ -616,10 +665,10 @@ <echo level="info">----------</echo> <echo level="info">Handling RenderScript files...</echo> <renderscript executable="${renderscript}" - framework="${android.rs}" + includePath="${android.renderscript.include.path}" genFolder="${gen.absolute.dir}" resFolder="${out.res.absolute.dir}/raw" - targetApi="${target.api}" + targetApi="${project.minSdkVersion}" optLevel="${renderscript.opt.level}" buildType="${build.is.packaging.debug}" previousBuildType="${build.last.is.packaging.debug}"> @@ -632,22 +681,20 @@ command="package" verbose="${verbose}" manifest="AndroidManifest.xml" - androidjar="${android.jar}" + androidjar="${project.target.android.jar}" rfolder="${gen.absolute.dir}" nonConstantId="${android.library}" - projectLibrariesResName="project.libraries.res" - projectLibrariesPackageName="project.libraries.package"> + libraryResFolderPathRefid="project.library.res.folder.path" + libraryPackagesRefid="project.library.packages"> <res path="${out.res.absolute.dir}" /> <res path="${resource.absolute.dir}" /> </aapt> <echo level="info">----------</echo> <echo level="info">Handling BuildConfig class...</echo> - <xpath input="AndroidManifest.xml" expression="/manifest/@package" - output="manifest.package" /> <buildconfig genFolder="${gen.absolute.dir}" - package="${manifest.package}" + package="${project.app.package}" buildType="${build.is.packaging.debug}" previousBuildType="${build.last.is.packaging.debug}"/> @@ -661,34 +708,41 @@ <!-- Compiles this project's .java files into .class files. --> <target name="-compile" depends="-build-setup, -pre-build, -code-gen, -pre-compile"> <do-only-if-manifest-hasCode elseText="hasCode = false. Skipping..."> - <!-- If android rules are used for a test project, its classpath should include - tested project's location --> - <condition property="extensible.classpath" - value="${tested.project.absolute.dir}/bin/classes" - else="."> - <isset property="tested.project.absolute.dir" /> - </condition> - <condition property="extensible.libs.classpath" - value="${tested.project.absolute.dir}/${jar.libs.dir}" - else="${jar.libs.dir}"> - <isset property="tested.project.absolute.dir" /> - </condition> + <!-- merge the project's own classpath and the tested project's classpath --> + <path id="project.javac.classpath"> + <path refid="project.all.jars.path" /> + <path refid="tested.project.classpath" /> + </path> <javac encoding="${java.encoding}" source="${java.source}" target="${java.target}" debug="true" extdirs="" includeantruntime="false" destdir="${out.classes.absolute.dir}" - bootclasspathref="android.target.classpath" + bootclasspathref="project.target.class.path" verbose="${verbose}" - classpath="${extensible.classpath}" - classpathref="project.libraries.jars" + classpathref="project.javac.classpath" fork="${need.javac.fork}"> <src path="${source.absolute.dir}" /> <src path="${gen.absolute.dir}" /> - <classpath> - <fileset dir="${extensible.libs.classpath}" includes="*.jar" /> - </classpath> <compilerarg line="${java.compilerargs}" /> </javac> + + <!-- if the project is instrumented, intrument the classes --> + <if condition="${build.is.instrumented}"> + <then> + <echo level="info">Instrumenting classes from ${out.absolute.dir}/classes...</echo> + <!-- It only instruments class files, not any external libs --> + <emma enabled="true"> + <instr verbosity="${verbosity}" + mode="overwrite" + instrpath="${out.absolute.dir}/classes" + outdir="${out.absolute.dir}/classes"> + <filter excludes="${project.app.package}.R,${project.app.package}.R$$*,${project.app.package}.BuildConfig" /> + <filter value="${emma.filter}" /> + </instr> + </emma> + </then> + </if> + <!-- if the project is a library then we generate a jar file --> <if condition="${project.is.library}"> <then> @@ -703,33 +757,17 @@ </then> </if> - <propertybyreplace name="manifest.package.path" input="${manifest.package}" replace="." with="/" /> + <propertybyreplace name="project.app.package.path" input="${project.app.package}" replace="." with="/" /> <jar destfile="${out.library.jar.file}"> <fileset dir="${out.classes.absolute.dir}" includes="**/*.class" - excludes="${manifest.package.path}/R.class ${manifest.package.path}/R$*.class ${manifest.package.path}/Manifest.class ${manifest.package.path}/Manifest$*.class ${manifest.package.path}/BuildConfig.class"/> + excludes="${project.app.package.path}/R.class ${project.app.package.path}/R$*.class ${project.app.package.path}/Manifest.class ${project.app.package.path}/Manifest$*.class ${project.app.package.path}/BuildConfig.class"/> <fileset dir="${source.absolute.dir}" excludes="**/*.java ${android.package.excludes}" /> </jar> </then> </if> - <!-- if the project is instrumented, intrument the classes --> - <if condition="${build.is.instrumented}"> - <then> - <echo level="info">Instrumenting classes from ${out.absolute.dir}/classes...</echo> - <!-- It only instruments class files, not any external libs --> - <emma enabled="true"> - <instr verbosity="${verbosity}" - mode="overwrite" - instrpath="${out.absolute.dir}/classes" - outdir="${out.absolute.dir}/classes"> - <filter excludes="${manifest.package}.R,${manifest.package}.R$$*,${manifest.package}.BuildConfig" /> - <filter value="${emma.filter}" /> - </instr> - </emma> - </then> - </if> </do-only-if-manifest-hasCode> </target> @@ -770,7 +808,7 @@ all the jar files separated by a platform path-separator. Each path must be quoted if it contains spaces. --> - <pathconvert property="android.libraryjars" refid="android.target.classpath"> + <pathconvert property="project.target.classpath.value" refid="project.target.class.path"> <firstmatchmapper> <regexpmapper from='^([^ ]*)( .*)$$' to='"\1\2"'/> <identitymapper/> @@ -780,15 +818,15 @@ <!-- Build a path object with all the jar files that must be obfuscated. This include the project compiled source code and any 3rd party jar files. --> - <path id="project.jars.ref"> + <path id="project.all.classes.path"> <pathelement location="${preobfuscate.jar.file}" /> - <path refid="project.libraries.jars" /> + <path refid="project.all.jars.path" /> </path> <!-- Set the project jar files Path object into a single property. It'll be all the jar files separated by a platform path-separator. Each path must be quoted if it contains spaces. --> - <pathconvert property="project.jars" refid="project.jars.ref"> + <pathconvert property="project.all.classes.value" refid="project.all.classes.path"> <firstmatchmapper> <regexpmapper from='^([^ ]*)( .*)$$' to='"\1\2"'/> <identitymapper/> @@ -813,9 +851,9 @@ destfile="${preobfuscate.jar.file}" /> <proguard> -include "${proguard.configcmd}" - -injars ${project.jars} + -injars ${project.all.classes.value} -outjars "${obfuscated.jar.file}" - -libraryjars ${android.libraryjars} + -libraryjars ${project.target.classpath.value} -dump "${obfuscate.absolute.dir}/dump.txt" -printseeds "${obfuscate.absolute.dir}/seeds.txt" -printusage "${obfuscate.absolute.dir}/usage.txt" @@ -875,13 +913,13 @@ debug="${build.is.packaging.debug}" manifest="AndroidManifest.xml" assets="${asset.absolute.dir}" - androidjar="${android.jar}" + androidjar="${project.target.android.jar}" apkfolder="${out.absolute.dir}" nocrunch="${build.packaging.nocrunch}" resourcefilename="${resource.package.file.name}" resourcefilter="${aapt.resource.filter}" - projectLibrariesResName="project.libraries.res" - projectLibrariesPackageName="project.libraries.package" + libraryResFolderPathRefid="project.library.res.folder.path" + libraryPackagesRefid="project.library.packages" previousBuildType="${build.last.target}" buildType="${build.target}"> <res path="${out.res.absolute.dir}" /> @@ -932,11 +970,24 @@ </target> - <target name="-set-debug-mode"> + <target name="-set-debug-mode" depends="-setup"> <!-- record the current build target --> <property name="build.target" value="debug" /> - <property name="build.is.instrumented" value="false" /> + <if> + <condition> + <and> + <istrue value="${project.is.testapp}" /> + <istrue value="${emma.enabled}" /> + </and> + </condition> + <then> + <property name="build.is.instrumented" value="true" /> + </then> + <else> + <property name="build.is.instrumented" value="false" /> + </else> + </if> <!-- whether the build is a debug build. always set. --> <property name="build.is.packaging.debug" value="true" /> @@ -1131,33 +1182,40 @@ </target> <!-- fails if the project is not a test project --> - <target name="-test-project-check"> - <!-- can't use project.is.test since the setup target is not run --> + <target name="-test-project-check" depends="-setup"> <if> <condition> - <isset property="tested.project.dir" /> + <and> + <isfalse value="${project.is.test}" /> + <isfalse value="${project.is.testapp}" /> + </and> </condition> - <else> + <then> <fail message="Project is not a test project." /> - </else> + </then> </if> </target> <target name="test" depends="-test-project-check" description="Runs tests from the package defined in test.package property"> - - <property name="tested.project.absolute.dir" location="${tested.project.dir}" /> - <property name="test.runner" value="android.test.InstrumentationTestRunner" /> - <!-- Application package of the tested project extracted from its manifest file --> - <xpath input="${tested.project.absolute.dir}/AndroidManifest.xml" - expression="/manifest/@package" output="tested.manifest.package" /> - <xpath input="AndroidManifest.xml" - expression="/manifest/@package" output="manifest.package" /> + <if condition="${project.is.test}"> + <then> + <property name="tested.project.absolute.dir" location="${tested.project.dir}" /> + + <!-- Application package of the tested project extracted from its manifest file --> + <xpath input="${tested.project.absolute.dir}/AndroidManifest.xml" + expression="/manifest/@package" output="tested.project.app.package" /> + </then> + <else> + <!-- this is a test app, the tested package is the app's own package --> + <property name="tested.project.app.package" value="${project.app.package}" /> + </else> + </if> <property name="emma.dump.file" - value="/data/data/${tested.manifest.package}/coverage.ec" /> + value="/data/data/${tested.project.app.package}/coverage.ec" /> <if condition="${emma.enabled}"> <then> @@ -1294,18 +1352,14 @@ <!-- Uninstalls the package from the default emulator/device --> - <target name="uninstall" + <target name="uninstall" depends="-setup" description="Uninstalls the application from a running emulator or device."> - <!-- Name of the application package extracted from manifest file --> - <xpath input="AndroidManifest.xml" expression="/manifest/@package" - output="manifest.package" /> - <if> <condition> - <isset property="manifest.package" /> + <isset property="project.app.package" /> </condition> <then> - <uninstall-helper app.package="${manifest.package}" /> + <uninstall-helper app.package="${project.app.package}" /> </then> <else> <fail message="Could not find application package in manifest. Cannot run 'adb uninstall'." /> @@ -1313,11 +1367,10 @@ </if> <!-- Now uninstall the tested project, if applicable --> - <!-- can't use project.is.test since the setup target might not have run --> <if> <condition> <and> - <isset property="tested.project.dir" /> + <istrue value="${project.is.test}" /> <not> <isset property="dont.do.deps" /> </not> @@ -1328,13 +1381,13 @@ <!-- Application package of the tested project extracted from its manifest file --> <xpath input="${tested.project.absolute.dir}/AndroidManifest.xml" - expression="/manifest/@package" output="tested.manifest.package" /> + expression="/manifest/@package" output="tested.project.app.package" /> <if> <condition> - <isset property="tested.manifest.package" /> + <isset property="tested.project.app.package" /> </condition> <then> - <uninstall-helper app.package="${tested.manifest.package}" /> + <uninstall-helper app.package="${tested.project.app.package}" /> </then> <else> <fail message="Could not find tested application package in manifest. Cannot run 'adb uninstall'." /> @@ -1372,7 +1425,7 @@ <echo> debug key.</echo> <echo> test: Runs the tests. Project must be a test project and</echo> <echo> must have been built. Typical usage would be:</echo> - <echo> ant [emma] debug installt test</echo> + <echo> ant [emma] debug install test</echo> <echo> emma: Transiently enables code coverage for subsequent</echo> <echo> targets.</echo> <echo> install: Installs the newly build package. Must either be used</echo> diff --git a/files/ant/pre_setup.xml b/files/ant/pre_setup.xml deleted file mode 100644 index 1c86109..0000000 --- a/files/ant/pre_setup.xml +++ /dev/null @@ -1,6 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<project name="imported" basedir="."> - - <fail message="Your build.xml file is outdated. Delete it and regenerate it with 'android update project'"/> - -</project> diff --git a/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/project/IPropertySource.java b/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/project/IPropertySource.java new file mode 100644 index 0000000..360c755 --- /dev/null +++ b/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/project/IPropertySource.java @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.sdklib.internal.project; + +/** + * A source able to return properties by name. + * + */ +public interface IPropertySource { + String getProperty(String name); +} diff --git a/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/project/ProjectProperties.java b/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/project/ProjectProperties.java index 2bb6b71..17d3ccf 100644 --- a/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/project/ProjectProperties.java +++ b/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/project/ProjectProperties.java @@ -55,7 +55,7 @@ import java.util.regex.Pattern; * {@link #makeWorkingCopy()}. * */ -public class ProjectProperties { +public class ProjectProperties implements IPropertySource { protected final static Pattern PATTERN_PROP = Pattern.compile( "^([a-zA-Z0-9._-]+)\\s*=\\s*(.*)\\s*$"); @@ -343,6 +343,7 @@ public class ProjectProperties { * @param name the name of the property. * @return the property value or null if the property is not set. */ + @Override public synchronized String getProperty(String name) { return mProperties.get(name); } diff --git a/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/project/ProjectPropertiesWorkingCopy.java b/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/project/ProjectPropertiesWorkingCopy.java index 13c8f6a..797b505 100644 --- a/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/project/ProjectPropertiesWorkingCopy.java +++ b/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/project/ProjectPropertiesWorkingCopy.java @@ -90,18 +90,15 @@ public class ProjectPropertiesWorkingCopy extends ProjectProperties { * <p/> * Typical usage: * <ul> - * <li>Create a ProjectProperties with {@code PropertyType#BUILD} - * <li>Merge in values using {@code PropertyType#DEFAULT} + * <li>Create a ProjectProperties with {@code PropertyType#ANT} + * <li>Merge in values using {@code PropertyType#PROJECT} * <li>The result is that this contains all the properties from default plus those * overridden by the build.properties file. * </ul> * * @param type One the possible {@link PropertyType}s. * @return this object, for chaining. - * - * @deprecated FIXME this method is not referenced anywhere. */ - @Deprecated public synchronized ProjectPropertiesWorkingCopy merge(PropertyType type) { if (mProjectFolder.exists() && mType != type) { IAbstractFile propFile = mProjectFolder.getFile(type.getFilename()); diff --git a/sdkmanager/libs/sdklib/src/com/android/sdklib/xml/AndroidXPathFactory.java b/sdkmanager/libs/sdklib/src/com/android/sdklib/xml/AndroidXPathFactory.java index 8373d8a..d6b2a6b 100644 --- a/sdkmanager/libs/sdklib/src/com/android/sdklib/xml/AndroidXPathFactory.java +++ b/sdkmanager/libs/sdklib/src/com/android/sdklib/xml/AndroidXPathFactory.java @@ -18,7 +18,7 @@ package com.android.sdklib.xml; import com.android.sdklib.SdkConstants; -import java.util.ArrayList; +import java.util.Collections; import java.util.Iterator; import java.util.List; @@ -42,7 +42,7 @@ public class AndroidXPathFactory { DEFAULT_NS_PREFIX); private final String mAndroidPrefix; - private final List<String> mAndroidPrefixes = new ArrayList<String>(); + private final List<String> mAndroidPrefixes; /** * Returns the default {@link AndroidNamespaceContext}. @@ -57,7 +57,7 @@ public class AndroidXPathFactory { */ public AndroidNamespaceContext(String androidPrefix) { mAndroidPrefix = androidPrefix; - mAndroidPrefixes.add(mAndroidPrefix); + mAndroidPrefixes = Collections.singletonList(mAndroidPrefix); } @Override diff --git a/templates/build.template b/templates/build.template index 3c0ffc8..1ab7ea2 100644 --- a/templates/build.template +++ b/templates/build.template @@ -39,9 +39,16 @@ application and should be checked into Version Control Systems. --> <loadproperties srcFile="project.properties" /> + <!-- if sdk.dir was not set from one of the property file, then + get it from the ANDROID_HOME env var. --> + <property environment="env" /> + <condition property="sdk.dir" value="${env.ANDROID_HOME}"> + <isset property="env.ANDROID_HOME" /> + </condition> + <!-- quick check on sdk.dir --> <fail - message="sdk.dir is missing. Make sure to generate local.properties using 'android update project' or to inject it through an env var" + message="sdk.dir is missing. Make sure to generate local.properties using 'android update project' or to inject it through the ANDROID_HOME environment variable." unless="sdk.dir" /> diff --git a/testapps/.gitignore b/testapps/.gitignore index 74f2472..3d82821 100644 --- a/testapps/.gitignore +++ b/testapps/.gitignore @@ -1,4 +1,5 @@ bin +coverage local.properties gen proguard diff --git a/testapps/customViewTest/libWithCustomView/local.properties b/testapps/customViewTest/libWithCustomView/local.properties deleted file mode 100644 index 613788a..0000000 --- a/testapps/customViewTest/libWithCustomView/local.properties +++ /dev/null @@ -1,10 +0,0 @@ -# This file is automatically generated by Android Tools. -# Do not modify this file -- YOUR CHANGES WILL BE ERASED! -# -# This file must *NOT* be checked in Version Control Systems, -# as it contains information specific to your local configuration. - -# location of the SDK. This is only used by Ant -# For customization when using a Version Control System, please read the -# header note. -sdk.dir=/android-sdk-dev diff --git a/testapps/customViewTest/mainProject/local.properties b/testapps/customViewTest/mainProject/local.properties deleted file mode 100644 index 613788a..0000000 --- a/testapps/customViewTest/mainProject/local.properties +++ /dev/null @@ -1,10 +0,0 @@ -# This file is automatically generated by Android Tools. -# Do not modify this file -- YOUR CHANGES WILL BE ERASED! -# -# This file must *NOT* be checked in Version Control Systems, -# as it contains information specific to your local configuration. - -# location of the SDK. This is only used by Ant -# For customization when using a Version Control System, please read the -# header note. -sdk.dir=/android-sdk-dev diff --git a/testapps/libsAndJarTest/lib1/src/com/android/tests/javaprojecttest/lib1/Main.java b/testapps/libsAndJarTest/lib1/src/com/android/tests/javaprojecttest/lib1/Main.java index f09e1cd..1c3ed35 100644 --- a/testapps/libsAndJarTest/lib1/src/com/android/tests/javaprojecttest/lib1/Main.java +++ b/testapps/libsAndJarTest/lib1/src/com/android/tests/javaprojecttest/lib1/Main.java @@ -3,6 +3,8 @@ package com.android.tests.javaprojecttest.lib1; import android.app.Activity; import android.os.Bundle; +import com.android.tests.javaprojecttest.lib2.Lib2; + public class Main extends Activity { /** Called when the activity is first created. */ @@ -11,5 +13,8 @@ public class Main extends Activity { super.onCreate(savedInstanceState); setContentView(R.layout.main); + + //Access some class from Lib2 to make sure we can access them. + String foo = Lib2.getContent(); } } diff --git a/testapps/testProjectTest/app/build.xml b/testapps/testProjectTest/app/build.xml new file mode 100644 index 0000000..a6975a4 --- /dev/null +++ b/testapps/testProjectTest/app/build.xml @@ -0,0 +1,90 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project name="LibActivity" default="help"> + + <!-- The local.properties file is created and updated by the 'android' tool. + It contains the path to the SDK. It should *NOT* be checked into + Version Control Systems. --> + <property file="local.properties" /> + + <!-- The ant.properties file can be created by you. It is only edited by the + 'android' tool to add properties to it. + This is the place to change some Ant specific build properties. + Here are some properties you may want to change/update: + + source.dir + The name of the source directory. Default is 'src'. + out.dir + The name of the output directory. Default is 'bin'. + + For other overridable properties, look at the beginning of the rules + files in the SDK, at tools/ant/build.xml + + Properties related to the SDK location or the project target should + be updated using the 'android' tool with the 'update' action. + + This file is an integral part of the build system for your + application and should be checked into Version Control Systems. + + --> + <property file="ant.properties" /> + + <!-- The project.properties file is created and updated by the 'android' + tool, as well as ADT. + + This contains project specific properties such as project target, and library + dependencies. Lower level build properties are stored in ant.properties + (or in .classpath for Eclipse projects). + + This file is an integral part of the build system for your + application and should be checked into Version Control Systems. --> + <loadproperties srcFile="project.properties" /> + + <!-- if sdk.dir was not set from one of the property file, then + get it from the ANDROID_HOME env var. --> + <property environment="env" /> + <condition property="sdk.dir" value="${env.ANDROID_HOME}"> + <isset property="env.ANDROID_HOME" /> + </condition> + + <!-- quick check on sdk.dir --> + <fail + message="sdk.dir is missing. Make sure to generate local.properties using 'android update project' or to inject it through the ANDROID_HOME environment variable." + unless="sdk.dir" + /> + + <!-- + Import per project custom build rules if present at the root of the project. + This is the place to put custom intermediary targets such as: + -pre-build + -pre-compile + -post-compile (This is typically used for code obfuscation. + Compiled code location: ${out.classes.absolute.dir} + If this is not done in place, override ${out.dex.input.absolute.dir}) + -post-package + -post-build + -pre-clean + --> + <import file="custom_rules.xml" optional="true" /> + + <!-- Import the actual build file. + + To customize existing targets, there are two options: + - Customize only one target: + - copy/paste the target into this file, *before* the + <import> task. + - customize it to your needs. + - Customize the whole content of build.xml + - copy/paste the content of the rules files (minus the top node) + into this file, replacing the <import> task. + - customize to your needs. + + *********************** + ****** IMPORTANT ****** + *********************** + In all cases you must update the value of version-tag below to read 'custom' instead of an integer, + in order to avoid having your file be overridden by tools such as "android update project" + --> + <!-- version-tag: 1 --> + <import file="${sdk.dir}/tools/ant/build.xml" /> + +</project> diff --git a/testapps/testProjectTest/app/src/readme.txt b/testapps/testProjectTest/app/src/readme.txt new file mode 100644 index 0000000..103fd76 --- /dev/null +++ b/testapps/testProjectTest/app/src/readme.txt @@ -0,0 +1 @@ +Just there so that the src folder doesn't disappear.
\ No newline at end of file diff --git a/testapps/testProjectTest/lib/build.xml b/testapps/testProjectTest/lib/build.xml new file mode 100644 index 0000000..aaf0ab1 --- /dev/null +++ b/testapps/testProjectTest/lib/build.xml @@ -0,0 +1,90 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project name="lib" default="help"> + + <!-- The local.properties file is created and updated by the 'android' tool. + It contains the path to the SDK. It should *NOT* be checked into + Version Control Systems. --> + <property file="local.properties" /> + + <!-- The ant.properties file can be created by you. It is only edited by the + 'android' tool to add properties to it. + This is the place to change some Ant specific build properties. + Here are some properties you may want to change/update: + + source.dir + The name of the source directory. Default is 'src'. + out.dir + The name of the output directory. Default is 'bin'. + + For other overridable properties, look at the beginning of the rules + files in the SDK, at tools/ant/build.xml + + Properties related to the SDK location or the project target should + be updated using the 'android' tool with the 'update' action. + + This file is an integral part of the build system for your + application and should be checked into Version Control Systems. + + --> + <property file="ant.properties" /> + + <!-- The project.properties file is created and updated by the 'android' + tool, as well as ADT. + + This contains project specific properties such as project target, and library + dependencies. Lower level build properties are stored in ant.properties + (or in .classpath for Eclipse projects). + + This file is an integral part of the build system for your + application and should be checked into Version Control Systems. --> + <loadproperties srcFile="project.properties" /> + + <!-- if sdk.dir was not set from one of the property file, then + get it from the ANDROID_HOME env var. --> + <property environment="env" /> + <condition property="sdk.dir" value="${env.ANDROID_HOME}"> + <isset property="env.ANDROID_HOME" /> + </condition> + + <!-- quick check on sdk.dir --> + <fail + message="sdk.dir is missing. Make sure to generate local.properties using 'android update project' or to inject it through the ANDROID_HOME environment variable." + unless="sdk.dir" + /> + + <!-- + Import per project custom build rules if present at the root of the project. + This is the place to put custom intermediary targets such as: + -pre-build + -pre-compile + -post-compile (This is typically used for code obfuscation. + Compiled code location: ${out.classes.absolute.dir} + If this is not done in place, override ${out.dex.input.absolute.dir}) + -post-package + -post-build + -pre-clean + --> + <import file="custom_rules.xml" optional="true" /> + + <!-- Import the actual build file. + + To customize existing targets, there are two options: + - Customize only one target: + - copy/paste the target into this file, *before* the + <import> task. + - customize it to your needs. + - Customize the whole content of build.xml + - copy/paste the content of the rules files (minus the top node) + into this file, replacing the <import> task. + - customize to your needs. + + *********************** + ****** IMPORTANT ****** + *********************** + In all cases you must update the value of version-tag below to read 'custom' instead of an integer, + in order to avoid having your file be overridden by tools such as "android update project" + --> + <!-- version-tag: 1 --> + <import file="${sdk.dir}/tools/ant/build.xml" /> + +</project> diff --git a/testapps/testProjectTest/test/res/drawable-hdpi/ic_launcher.png b/testapps/testProjectTest/test/res/drawable-hdpi/ic_launcher.png Binary files differdeleted file mode 100644 index 96a442e..0000000 --- a/testapps/testProjectTest/test/res/drawable-hdpi/ic_launcher.png +++ /dev/null diff --git a/testapps/testProjectTest/test/res/drawable-ldpi/ic_launcher.png b/testapps/testProjectTest/test/res/drawable-ldpi/ic_launcher.png Binary files differdeleted file mode 100644 index 9923872..0000000 --- a/testapps/testProjectTest/test/res/drawable-ldpi/ic_launcher.png +++ /dev/null diff --git a/testapps/testProjectTest/test/res/drawable-mdpi/ic_launcher.png b/testapps/testProjectTest/test/res/drawable-mdpi/ic_launcher.png Binary files differdeleted file mode 100644 index 359047d..0000000 --- a/testapps/testProjectTest/test/res/drawable-mdpi/ic_launcher.png +++ /dev/null diff --git a/testapps/testProjectTest/test/res/drawable-xhdpi/ic_launcher.png b/testapps/testProjectTest/test/res/drawable-xhdpi/ic_launcher.png Binary files differdeleted file mode 100644 index 71c6d76..0000000 --- a/testapps/testProjectTest/test/res/drawable-xhdpi/ic_launcher.png +++ /dev/null diff --git a/testapps/testProjectTest/test/res/layout/main.xml b/testapps/testProjectTest/test/res/layout/main.xml deleted file mode 100644 index bc12cd8..0000000 --- a/testapps/testProjectTest/test/res/layout/main.xml +++ /dev/null @@ -1,12 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" - android:layout_width="fill_parent" - android:layout_height="fill_parent" - android:orientation="vertical" > - - <TextView - android:layout_width="fill_parent" - android:layout_height="wrap_content" - android:text="@string/hello" /> - -</LinearLayout>
\ No newline at end of file diff --git a/testapps/testProjectTest/test/.classpath b/testapps/testProjectTest/testapp/.classpath index 9afbc38..9afbc38 100644 --- a/testapps/testProjectTest/test/.classpath +++ b/testapps/testProjectTest/testapp/.classpath diff --git a/testapps/testProjectTest/test/.project b/testapps/testProjectTest/testapp/.project index bffbba0..796ccc1 100644 --- a/testapps/testProjectTest/test/.project +++ b/testapps/testProjectTest/testapp/.project @@ -1,6 +1,6 @@ <?xml version="1.0" encoding="UTF-8"?> <projectDescription> - <name>testProjectTest-test</name> + <name>testProjectTest-testapp</name> <comment></comment> <projects> <project>testProjectTest-app</project> diff --git a/testapps/testProjectTest/test/AndroidManifest.xml b/testapps/testProjectTest/testapp/AndroidManifest.xml index 8ac5dbe..5252972 100644 --- a/testapps/testProjectTest/test/AndroidManifest.xml +++ b/testapps/testProjectTest/testapp/AndroidManifest.xml @@ -11,7 +11,7 @@ this package needs to link against the android.test library, which is needed when building test cases. --> - <application> + <application android:label="testProjectTest-testapp"> <uses-library android:name="android.test.runner" /> </application> diff --git a/testapps/testProjectTest/testapp/build.xml b/testapps/testProjectTest/testapp/build.xml new file mode 100644 index 0000000..2682e1c --- /dev/null +++ b/testapps/testProjectTest/testapp/build.xml @@ -0,0 +1,90 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project name="testapp" default="help"> + + <!-- The local.properties file is created and updated by the 'android' tool. + It contains the path to the SDK. It should *NOT* be checked into + Version Control Systems. --> + <property file="local.properties" /> + + <!-- The ant.properties file can be created by you. It is only edited by the + 'android' tool to add properties to it. + This is the place to change some Ant specific build properties. + Here are some properties you may want to change/update: + + source.dir + The name of the source directory. Default is 'src'. + out.dir + The name of the output directory. Default is 'bin'. + + For other overridable properties, look at the beginning of the rules + files in the SDK, at tools/ant/build.xml + + Properties related to the SDK location or the project target should + be updated using the 'android' tool with the 'update' action. + + This file is an integral part of the build system for your + application and should be checked into Version Control Systems. + + --> + <property file="ant.properties" /> + + <!-- The project.properties file is created and updated by the 'android' + tool, as well as ADT. + + This contains project specific properties such as project target, and library + dependencies. Lower level build properties are stored in ant.properties + (or in .classpath for Eclipse projects). + + This file is an integral part of the build system for your + application and should be checked into Version Control Systems. --> + <loadproperties srcFile="project.properties" /> + + <!-- if sdk.dir was not set from one of the property file, then + get it from the ANDROID_HOME env var. --> + <property environment="env" /> + <condition property="sdk.dir" value="${env.ANDROID_HOME}"> + <isset property="env.ANDROID_HOME" /> + </condition> + + <!-- quick check on sdk.dir --> + <fail + message="sdk.dir is missing. Make sure to generate local.properties using 'android update project' or to inject it through the ANDROID_HOME environment variable." + unless="sdk.dir" + /> + + <!-- + Import per project custom build rules if present at the root of the project. + This is the place to put custom intermediary targets such as: + -pre-build + -pre-compile + -post-compile (This is typically used for code obfuscation. + Compiled code location: ${out.classes.absolute.dir} + If this is not done in place, override ${out.dex.input.absolute.dir}) + -post-package + -post-build + -pre-clean + --> + <import file="custom_rules.xml" optional="true" /> + + <!-- Import the actual build file. + + To customize existing targets, there are two options: + - Customize only one target: + - copy/paste the target into this file, *before* the + <import> task. + - customize it to your needs. + - Customize the whole content of build.xml + - copy/paste the content of the rules files (minus the top node) + into this file, replacing the <import> task. + - customize to your needs. + + *********************** + ****** IMPORTANT ****** + *********************** + In all cases you must update the value of version-tag below to read 'custom' instead of an integer, + in order to avoid having your file be overridden by tools such as "android update project" + --> + <!-- version-tag: 1 --> + <import file="${sdk.dir}/tools/ant/build.xml" /> + +</project> diff --git a/testapps/testProjectTest/test/proguard-project.txt b/testapps/testProjectTest/testapp/proguard-project.txt index f2fe155..f2fe155 100644 --- a/testapps/testProjectTest/test/proguard-project.txt +++ b/testapps/testProjectTest/testapp/proguard-project.txt diff --git a/testapps/testProjectTest/test/project.properties b/testapps/testProjectTest/testapp/project.properties index 4c13b85..4c13b85 100644 --- a/testapps/testProjectTest/test/project.properties +++ b/testapps/testProjectTest/testapp/project.properties diff --git a/testapps/testProjectTest/test/src/com/android/tests/testprojecttest/lib/LibActivityTest.java b/testapps/testProjectTest/testapp/src/com/android/tests/testprojecttest/lib/LibActivityTest.java index 9be6f97..9be6f97 100644 --- a/testapps/testProjectTest/test/src/com/android/tests/testprojecttest/lib/LibActivityTest.java +++ b/testapps/testProjectTest/testapp/src/com/android/tests/testprojecttest/lib/LibActivityTest.java diff --git a/testapps/testProjectTest/test/src/com/android/tests/testprojecttest/test/AllTests.java b/testapps/testProjectTest/testapp/src/com/android/tests/testprojecttest/test/AllTests.java index a77b53c..a77b53c 100644 --- a/testapps/testProjectTest/test/src/com/android/tests/testprojecttest/test/AllTests.java +++ b/testapps/testProjectTest/testapp/src/com/android/tests/testprojecttest/test/AllTests.java diff --git a/testapps/testProjectTest/testlib/.classpath b/testapps/testProjectTest/testlib/.classpath new file mode 100644 index 0000000..9afbc38 --- /dev/null +++ b/testapps/testProjectTest/testlib/.classpath @@ -0,0 +1,9 @@ +<?xml version="1.0" encoding="UTF-8"?> +<classpath> + <classpathentry kind="src" path="src"/> + <classpathentry kind="src" path="gen"/> + <classpathentry combineaccessrules="false" kind="src" path="/testProjectTest-app"/> + <classpathentry kind="con" path="com.android.ide.eclipse.adt.ANDROID_FRAMEWORK"/> + <classpathentry kind="con" path="com.android.ide.eclipse.adt.LIBRARIES"/> + <classpathentry kind="output" path="bin/classes"/> +</classpath> diff --git a/testapps/testProjectTest/testlib/.project b/testapps/testProjectTest/testlib/.project new file mode 100644 index 0000000..8450217 --- /dev/null +++ b/testapps/testProjectTest/testlib/.project @@ -0,0 +1,34 @@ +<?xml version="1.0" encoding="UTF-8"?> +<projectDescription> + <name>testProjectTest-testlib</name> + <comment></comment> + <projects> + <project>testProjectTest-app</project> + </projects> + <buildSpec> + <buildCommand> + <name>com.android.ide.eclipse.adt.ResourceManagerBuilder</name> + <arguments> + </arguments> + </buildCommand> + <buildCommand> + <name>com.android.ide.eclipse.adt.PreCompilerBuilder</name> + <arguments> + </arguments> + </buildCommand> + <buildCommand> + <name>org.eclipse.jdt.core.javabuilder</name> + <arguments> + </arguments> + </buildCommand> + <buildCommand> + <name>com.android.ide.eclipse.adt.ApkBuilder</name> + <arguments> + </arguments> + </buildCommand> + </buildSpec> + <natures> + <nature>com.android.ide.eclipse.adt.AndroidNature</nature> + <nature>org.eclipse.jdt.core.javanature</nature> + </natures> +</projectDescription> diff --git a/testapps/testProjectTest/testlib/AndroidManifest.xml b/testapps/testProjectTest/testlib/AndroidManifest.xml new file mode 100644 index 0000000..acfe650 --- /dev/null +++ b/testapps/testProjectTest/testlib/AndroidManifest.xml @@ -0,0 +1,38 @@ +<?xml version="1.0" encoding="utf-8"?> +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.android.tests.testprojecttest.testlib" + android:versionCode="1" + android:versionName="1.0" > + + <uses-sdk android:minSdkVersion="15" /> + + <!-- + We add an application tag here just so that we can indicate that + this package needs to link against the android.test library, + which is needed when building test cases. + --> + <application android:label="testProjectTest-testlib"> + <uses-library android:name="android.test.runner" /> + + <activity + android:name="com.android.tests.testprojecttest.lib.LibActivity" + android:label="@string/app_name" > + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + + <category android:name="android.intent.category.LAUNCHER" /> + </intent-filter> + </activity> + + </application> + + <!-- + This declares that this app uses the instrumentation test runner targeting + the package of com.android.tests.testprojecttest.testlib. To run the tests use the command: + "adb shell am instrument -w com.android.tests.testprojecttest.testlib/android.test.InstrumentationTestRunner" + --> + <instrumentation + android:name="android.test.InstrumentationTestRunner" + android:targetPackage="com.android.tests.testprojecttest.testlib" /> + +</manifest>
\ No newline at end of file diff --git a/testapps/testProjectTest/testlib/build.xml b/testapps/testProjectTest/testlib/build.xml new file mode 100644 index 0000000..7771647 --- /dev/null +++ b/testapps/testProjectTest/testlib/build.xml @@ -0,0 +1,90 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project name="testlib" default="help"> + + <!-- The local.properties file is created and updated by the 'android' tool. + It contains the path to the SDK. It should *NOT* be checked into + Version Control Systems. --> + <property file="local.properties" /> + + <!-- The ant.properties file can be created by you. It is only edited by the + 'android' tool to add properties to it. + This is the place to change some Ant specific build properties. + Here are some properties you may want to change/update: + + source.dir + The name of the source directory. Default is 'src'. + out.dir + The name of the output directory. Default is 'bin'. + + For other overridable properties, look at the beginning of the rules + files in the SDK, at tools/ant/build.xml + + Properties related to the SDK location or the project target should + be updated using the 'android' tool with the 'update' action. + + This file is an integral part of the build system for your + application and should be checked into Version Control Systems. + + --> + <property file="ant.properties" /> + + <!-- The project.properties file is created and updated by the 'android' + tool, as well as ADT. + + This contains project specific properties such as project target, and library + dependencies. Lower level build properties are stored in ant.properties + (or in .classpath for Eclipse projects). + + This file is an integral part of the build system for your + application and should be checked into Version Control Systems. --> + <loadproperties srcFile="project.properties" /> + + <!-- if sdk.dir was not set from one of the property file, then + get it from the ANDROID_HOME env var. --> + <property environment="env" /> + <condition property="sdk.dir" value="${env.ANDROID_HOME}"> + <isset property="env.ANDROID_HOME" /> + </condition> + + <!-- quick check on sdk.dir --> + <fail + message="sdk.dir is missing. Make sure to generate local.properties using 'android update project' or to inject it through the ANDROID_HOME environment variable." + unless="sdk.dir" + /> + + <!-- + Import per project custom build rules if present at the root of the project. + This is the place to put custom intermediary targets such as: + -pre-build + -pre-compile + -post-compile (This is typically used for code obfuscation. + Compiled code location: ${out.classes.absolute.dir} + If this is not done in place, override ${out.dex.input.absolute.dir}) + -post-package + -post-build + -pre-clean + --> + <import file="custom_rules.xml" optional="true" /> + + <!-- Import the actual build file. + + To customize existing targets, there are two options: + - Customize only one target: + - copy/paste the target into this file, *before* the + <import> task. + - customize it to your needs. + - Customize the whole content of build.xml + - copy/paste the content of the rules files (minus the top node) + into this file, replacing the <import> task. + - customize to your needs. + + *********************** + ****** IMPORTANT ****** + *********************** + In all cases you must update the value of version-tag below to read 'custom' instead of an integer, + in order to avoid having your file be overridden by tools such as "android update project" + --> + <!-- version-tag: 1 --> + <import file="${sdk.dir}/tools/ant/build.xml" /> + +</project> diff --git a/testapps/testProjectTest/testlib/proguard-project.txt b/testapps/testProjectTest/testlib/proguard-project.txt new file mode 100644 index 0000000..f2fe155 --- /dev/null +++ b/testapps/testProjectTest/testlib/proguard-project.txt @@ -0,0 +1,20 @@ +# To enable ProGuard in your project, edit project.properties +# to define the proguard.config property as described in that file. +# +# Add project specific ProGuard rules here. +# By default, the flags in this file are appended to flags specified +# in ${sdk.dir}/tools/proguard/proguard-android.txt +# You can edit the include path and order by changing the ProGuard +# include property in project.properties. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# Add any project specific keep options here: + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} diff --git a/testapps/testProjectTest/testlib/project.properties b/testapps/testProjectTest/testlib/project.properties new file mode 100644 index 0000000..60765b6 --- /dev/null +++ b/testapps/testProjectTest/testlib/project.properties @@ -0,0 +1,15 @@ +# This file is automatically generated by Android Tools. +# Do not modify this file -- YOUR CHANGES WILL BE ERASED! +# +# This file must be checked in Version Control Systems. +# +# To customize properties used by the Ant build system edit +# "ant.properties", and override values to adapt the script to your +# project structure. +# +# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home): +#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt + +# Project target. +target=android-15 +android.library.reference.1=../lib diff --git a/testapps/testProjectTest/test/res/values/strings.xml b/testapps/testProjectTest/testlib/res/values/strings.xml index ef42478..ef42478 100644 --- a/testapps/testProjectTest/test/res/values/strings.xml +++ b/testapps/testProjectTest/testlib/res/values/strings.xml diff --git a/testapps/testProjectTest/testlib/src/com/android/tests/testprojecttest/lib/LibActivityTest.java b/testapps/testProjectTest/testlib/src/com/android/tests/testprojecttest/lib/LibActivityTest.java new file mode 100644 index 0000000..6632c58 --- /dev/null +++ b/testapps/testProjectTest/testlib/src/com/android/tests/testprojecttest/lib/LibActivityTest.java @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.tests.testprojecttest.lib; + +import android.test.ActivityInstrumentationTestCase2; +import android.test.suitebuilder.annotation.MediumTest; +import android.widget.TextView; + +import com.android.tests.testprojecttest.lib.R; + +/** + * An example of an {@link ActivityInstrumentationTestCase2} of a specific activity {@link Focus2}. + * By virtue of extending {@link ActivityInstrumentationTestCase2}, the target activity is automatically + * launched and finished before and after each test. This also extends + * {@link android.test.InstrumentationTestCase}, which provides + * access to methods for sending events to the target activity, such as key and + * touch events. See {@link #sendKeys}. + * + * In general, {@link android.test.InstrumentationTestCase}s and {@link ActivityInstrumentationTestCase2}s + * are heavier weight functional tests available for end to end testing of your + * user interface. When run via a {@link android.test.InstrumentationTestRunner}, + * the necessary {@link android.app.Instrumentation} will be injected for you to + * user via {@link #getInstrumentation} in your tests. + * + * See {@link com.example.android.apis.AllTests} for documentation on running + * all tests and individual tests in this application. + */ +public class LibActivityTest extends ActivityInstrumentationTestCase2<LibActivity> { + + private TextView mTextView; + + /** + * Creates an {@link ActivityInstrumentationTestCase2} that tests the {@link Focus2} activity. + */ + public LibActivityTest() { + super(LibActivity.class); + } + + @Override + protected void setUp() throws Exception { + super.setUp(); + final LibActivity a = getActivity(); + // ensure a valid handle to the activity has been returned + assertNotNull(a); + mTextView = (TextView) a.findViewById(R.id.text); + } + + /** + * The name 'test preconditions' is a convention to signal that if this + * test doesn't pass, the test case was not set up properly and it might + * explain any and all failures in other tests. This is not guaranteed + * to run before other tests, as junit uses reflection to find the tests. + */ + @MediumTest + public void testPreconditions() { + assertNotNull(mTextView); + } +} diff --git a/testapps/testProjectTest/testlib/src/com/android/tests/testprojecttest/test/AllTests.java b/testapps/testProjectTest/testlib/src/com/android/tests/testprojecttest/test/AllTests.java new file mode 100644 index 0000000..a77b53c --- /dev/null +++ b/testapps/testProjectTest/testlib/src/com/android/tests/testprojecttest/test/AllTests.java @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.tests.testprojecttest.test; + +import junit.framework.Test; +import junit.framework.TestSuite; + +import android.test.suitebuilder.TestSuiteBuilder; + +/** + * A test suite containing all tests for ApiDemos. + * + * To run all suites found in this apk: + * $ adb shell am instrument -w \ + * com.example.android.apis.tests/android.test.InstrumentationTestRunner + * + * To run just this suite from the command line: + * $ adb shell am instrument -w \ + * -e class com.example.android.apis.AllTests \ + * com.example.android.apis.tests/android.test.InstrumentationTestRunner + * + * To run an individual test case, e.g. {@link com.example.android.apis.os.MorseCodeConverterTest}: + * $ adb shell am instrument -w \ + * -e class com.example.android.apis.os.MorseCodeConverterTest \ + * com.example.android.apis.tests/android.test.InstrumentationTestRunner + * + * To run an individual test, e.g. {@link com.example.android.apis.os.MorseCodeConverterTest#testCharacterS()}: + * $ adb shell am instrument -w \ + * -e class com.example.android.apis.os.MorseCodeConverterTest#testCharacterS \ + * com.example.android.apis.tests/android.test.InstrumentationTestRunner + */ +public class AllTests extends TestSuite { + + public static Test suite() { + return new TestSuiteBuilder(AllTests.class) + .includeAllPackagesUnderHere() + .build(); + } +} |