aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--anttasks/src/com/android/ant/AaptExecTask.java31
-rw-r--r--anttasks/src/com/android/ant/CheckEnvTask.java105
-rw-r--r--anttasks/src/com/android/ant/ComputeDependencyTask.java239
-rw-r--r--anttasks/src/com/android/ant/ComputeProjectClasspathTask.java94
-rw-r--r--anttasks/src/com/android/ant/DependencyHelper.java301
-rw-r--r--anttasks/src/com/android/ant/GetLibraryListTask.java95
-rw-r--r--anttasks/src/com/android/ant/GetTargetTask.java294
-rw-r--r--anttasks/src/com/android/ant/GetTypeTask.java109
-rw-r--r--anttasks/src/com/android/ant/NewSetupTask.java764
-rw-r--r--anttasks/src/com/android/ant/RenderScriptTask.java12
-rw-r--r--anttasks/src/com/android/ant/SetupTask.java46
-rw-r--r--changes.txt8
-rw-r--r--files/ant/build.xml421
-rw-r--r--files/ant/pre_setup.xml6
-rw-r--r--sdkmanager/libs/sdklib/src/com/android/sdklib/internal/project/IPropertySource.java25
-rw-r--r--sdkmanager/libs/sdklib/src/com/android/sdklib/internal/project/ProjectProperties.java3
-rw-r--r--sdkmanager/libs/sdklib/src/com/android/sdklib/internal/project/ProjectPropertiesWorkingCopy.java7
-rw-r--r--sdkmanager/libs/sdklib/src/com/android/sdklib/xml/AndroidXPathFactory.java6
-rw-r--r--templates/build.template9
-rw-r--r--testapps/.gitignore1
-rw-r--r--testapps/customViewTest/libWithCustomView/local.properties10
-rw-r--r--testapps/customViewTest/mainProject/local.properties10
-rw-r--r--testapps/libsAndJarTest/lib1/src/com/android/tests/javaprojecttest/lib1/Main.java5
-rw-r--r--testapps/testProjectTest/app/build.xml90
-rw-r--r--testapps/testProjectTest/app/src/readme.txt1
-rw-r--r--testapps/testProjectTest/lib/build.xml90
-rw-r--r--testapps/testProjectTest/test/res/drawable-hdpi/ic_launcher.pngbin9397 -> 0 bytes
-rw-r--r--testapps/testProjectTest/test/res/drawable-ldpi/ic_launcher.pngbin2729 -> 0 bytes
-rw-r--r--testapps/testProjectTest/test/res/drawable-mdpi/ic_launcher.pngbin5237 -> 0 bytes
-rw-r--r--testapps/testProjectTest/test/res/drawable-xhdpi/ic_launcher.pngbin14383 -> 0 bytes
-rw-r--r--testapps/testProjectTest/test/res/layout/main.xml12
-rw-r--r--testapps/testProjectTest/testapp/.classpath (renamed from testapps/testProjectTest/test/.classpath)0
-rw-r--r--testapps/testProjectTest/testapp/.project (renamed from testapps/testProjectTest/test/.project)2
-rw-r--r--testapps/testProjectTest/testapp/AndroidManifest.xml (renamed from testapps/testProjectTest/test/AndroidManifest.xml)2
-rw-r--r--testapps/testProjectTest/testapp/build.xml90
-rw-r--r--testapps/testProjectTest/testapp/proguard-project.txt (renamed from testapps/testProjectTest/test/proguard-project.txt)0
-rw-r--r--testapps/testProjectTest/testapp/project.properties (renamed from testapps/testProjectTest/test/project.properties)0
-rw-r--r--testapps/testProjectTest/testapp/src/com/android/tests/testprojecttest/lib/LibActivityTest.java (renamed from testapps/testProjectTest/test/src/com/android/tests/testprojecttest/lib/LibActivityTest.java)0
-rw-r--r--testapps/testProjectTest/testapp/src/com/android/tests/testprojecttest/test/AllTests.java (renamed from testapps/testProjectTest/test/src/com/android/tests/testprojecttest/test/AllTests.java)0
-rw-r--r--testapps/testProjectTest/testlib/.classpath9
-rw-r--r--testapps/testProjectTest/testlib/.project34
-rw-r--r--testapps/testProjectTest/testlib/AndroidManifest.xml38
-rw-r--r--testapps/testProjectTest/testlib/build.xml90
-rw-r--r--testapps/testProjectTest/testlib/proguard-project.txt20
-rw-r--r--testapps/testProjectTest/testlib/project.properties15
-rw-r--r--testapps/testProjectTest/testlib/res/values/strings.xml (renamed from testapps/testProjectTest/test/res/values/strings.xml)0
-rw-r--r--testapps/testProjectTest/testlib/src/com/android/tests/testprojecttest/lib/LibActivityTest.java72
-rw-r--r--testapps/testProjectTest/testlib/src/com/android/tests/testprojecttest/test/AllTests.java53
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
deleted file mode 100644
index 96a442e..0000000
--- a/testapps/testProjectTest/test/res/drawable-hdpi/ic_launcher.png
+++ /dev/null
Binary files differ
diff --git a/testapps/testProjectTest/test/res/drawable-ldpi/ic_launcher.png b/testapps/testProjectTest/test/res/drawable-ldpi/ic_launcher.png
deleted file mode 100644
index 9923872..0000000
--- a/testapps/testProjectTest/test/res/drawable-ldpi/ic_launcher.png
+++ /dev/null
Binary files differ
diff --git a/testapps/testProjectTest/test/res/drawable-mdpi/ic_launcher.png b/testapps/testProjectTest/test/res/drawable-mdpi/ic_launcher.png
deleted file mode 100644
index 359047d..0000000
--- a/testapps/testProjectTest/test/res/drawable-mdpi/ic_launcher.png
+++ /dev/null
Binary files differ
diff --git a/testapps/testProjectTest/test/res/drawable-xhdpi/ic_launcher.png b/testapps/testProjectTest/test/res/drawable-xhdpi/ic_launcher.png
deleted file mode 100644
index 71c6d76..0000000
--- a/testapps/testProjectTest/test/res/drawable-xhdpi/ic_launcher.png
+++ /dev/null
Binary files differ
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();
+ }
+}