Add ant-based code coverage support to Android SDK

Target 'run-tests' launches all the unit tests against the tested project.
Target 'coverage' emma-instruments the tested project's classes,
runs the tests against instrumented classes, collects code coverage data
and extracts it to human-readable form as report.html.
android_test_rules.xml contain additional rules for test projects.
Test projects are auto-recognized by presence of the tested.project.dir
property, which will be auto-generated for tests projects. Temporarily,
please add this property manually to the build.properties file.
Current version is mainly tested with default, android generated test projects.
This version includes also fixing relative to absolute paths for
properties which are most likely to be changed by user in external
property file.
diff --git a/build/sdk.atree b/build/sdk.atree
index 16d65de..d3cfced 100644
--- a/build/sdk.atree
+++ b/build/sdk.atree
@@ -59,6 +59,7 @@
 development/tools/scripts/layout.template platforms/${PLATFORM_NAME}/templates/layout.template
 development/tools/scripts/strings.template platforms/${PLATFORM_NAME}/templates/strings.template
 development/tools/scripts/android_rules.xml platforms/${PLATFORM_NAME}/templates/android_rules.xml
+development/tools/scripts/android_test_rules.xml platforms/${PLATFORM_NAME}/templates/android_test_rules.xml
 development/tools/scripts/build.template tools/lib/build.template
 
 # emacs support
@@ -125,6 +126,11 @@
 bin/traceview tools/traceview
 framework/traceview.jar tools/lib/traceview.jar
 
+# emma lib for code coverage support
+framework/emmalib.jar tools/lib/emma_device.jar
+external/emma/lib/emma.jar tools/lib/emma.jar
+external/emma/lib/emma_ant.jar tools/lib/emma_ant.jar
+
 # custom ant tasks
 framework/anttasks.jar tools/lib/anttasks.jar
 
diff --git a/tools/anttasks/src/com/android/ant/SetupTask.java b/tools/anttasks/src/com/android/ant/SetupTask.java
index ffe8314..27d73d6 100644
--- a/tools/anttasks/src/com/android/ant/SetupTask.java
+++ b/tools/anttasks/src/com/android/ant/SetupTask.java
@@ -58,7 +58,8 @@
  */
 public final class SetupTask extends ImportTask {
     private final static String ANDROID_RULES = "android_rules.xml";
-
+    // additional android rules for test project - depends on android_rules.xml
+    private final static String ANDROID_TEST_RULES = "android_test_rules.xml";
     // ant property with the path to the android.jar
     private final static String PROPERTY_ANDROID_JAR = "android.jar";
     // LEGACY - compatibility with 1.6 and before
@@ -103,6 +104,13 @@
 
         // get the target property value
         String targetHashString = antProject.getProperty(ProjectProperties.PROPERTY_TARGET);
+
+        boolean isTestProject = false;
+
+        if (antProject.getProperty("tested.project.dir") != null) {
+            isTestProject = true;
+        }
+
         if (targetHashString == null) {
             throw new BuildException("Android Target is not set.");
         }
@@ -215,17 +223,21 @@
         if (mDoImport) {
             // make sure the file exists.
             File templates = new File(templateFolder);
+
             if (templates.isDirectory() == false) {
                 throw new BuildException(String.format("Template directory '%s' is missing.",
                         templateFolder));
             }
 
+            String importedRulesFileName = isTestProject ? ANDROID_TEST_RULES : ANDROID_RULES;
+
             // now check the rules file exists.
-            File rules = new File(templateFolder, ANDROID_RULES);
+            File rules = new File(templateFolder, importedRulesFileName);
+
             if (rules.isFile() == false) {
                 throw new BuildException(String.format("Build rules file '%s' is missing.",
                         templateFolder));
-           }
+            }
 
             // set the file location to import
             setFile(rules.getAbsolutePath());
diff --git a/tools/scripts/android_rules.xml b/tools/scripts/android_rules.xml
index 64f0e39..bdb9834 100644
--- a/tools/scripts/android_rules.xml
+++ b/tools/scripts/android_rules.xml
@@ -27,36 +27,46 @@
     <property name="android.tools.dir" location="${sdk.dir}/tools" />
 
     <!-- Input directories -->
-    <property name="source.dir" location="src" />
-    <property name="gen.dir" location="gen" />
-    <property name="resource.dir" location="res" />
-    <property name="asset.dir" location="assets" />
+    <property name="source.dir" value="src" />
+    <property name="source.absolute.dir" location="${source.dir}" />
+    <property name="gen.dir" value="gen" />
+    <property name="gen.absolute.dir" location="${gen.dir}" />
+    <property name="resource.dir" value="res" />
+    <property name="resource.absolute.dir" location="${resource.dir}" />
+    <property name="asset.dir" value="assets" />
+    <property name="asset.absolute.dir" location="${asset.dir}" />
 
-    <!-- Directory for the 3rd party java libraries -->
-    <property name="external.libs.dir" location="libs" />
+    <!-- Directory for the third party java libraries -->
+    <property name="external.libs.dir" value="libs" />
+    <property name="external.libs.absolute.dir" location="${external.libs.dir}" />
+
+    <!-- In this file it is just alias for external.libs.absolute.dir. It is used for
+         reusability though, when calling ant targets in this file from other files.
+         However, it is a temporary solution. -->
+    <property name="external.jars" location="${external.libs.absolute.dir}" />
 
     <!-- Directory for the native libraries -->
-    <property name="native.libs.dir" location="libs" />
+    <property name="native.libs.dir" value="libs" />
+    <property name="native.libs.absolute.dir" location="${native.libs.dir}" />
 
     <!-- Output directories -->
-    <property name="gen.dir" location="gen" />
-    <property name="out.dir" location="bin" />
-    <property name="out.classes.dir" location="${out.dir}/classes" />
-
-    <!-- Out directory for a parent project if this project is an instrumentation project -->
-    <property name="main.out.dir" location="../${out.dir}" />
-    <property name="main.out.classes.dir" location="${main.out.dir}/classes" />
+    <property name="out.dir" value="bin" />
+    <property name="out.absolute.dir" location="${out.dir}" />
+    <property name="out.classes.dir" value="${out.dir}/classes" />
+    <property name="out.classes.absolute.dir" location="${out.classes.dir}" />
 
     <!-- Intermediate files -->
     <property name="dex.file.name" value="classes.dex" />
-    <property name="intermediate.dex.file" location="${out.dir}/${dex.file.name}" />
+    <property name="intermediate.dex.file" location="${out.absolute.dir}/${dex.file.name}" />
 
     <!-- The final package file to generate -->
-    <property name="out.debug.unaligned.package" location="${out.dir}/${ant.project.name}-debug-unaligned.apk" />
-    <property name="out.debug.package" location="${out.dir}/${ant.project.name}-debug.apk" />
-    <property name="out.unsigned.package" location="${out.dir}/${ant.project.name}-unsigned.apk" />
-    <property name="out.unaligned.package" location="${out.dir}/${ant.project.name}-unaligned.apk" />
-    <property name="out.release.package" location="${out.dir}/${ant.project.name}-release.apk" />
+    <property name="out.debug.unaligned.package"
+                  location="${out.absolute.dir}/${ant.project.name}-debug-unaligned.apk" />
+    <property name="out.debug.package" location="${out.absolute.dir}/${ant.project.name}-debug.apk" />
+    <property name="out.unsigned.package" location="${out.absolute.dir}/${ant.project.name}-unsigned.apk" />
+    <property name="out.unaligned.package"
+                  location="${out.absolute.dir}/${ant.project.name}-unaligned.apk" />
+    <property name="out.release.package" location="${out.absolute.dir}/${ant.project.name}-release.apk" />
 
     <!-- Tools -->
     <condition property="exe" value=".exe" else=""><os family="windows" /></condition>
@@ -68,11 +78,11 @@
     <!-- Creates the output directories if they don't exist yet. -->
     <target name="-dirs">
         <echo>Creating output directories if needed...</echo>
-        <mkdir dir="${resource.dir}" />
-        <mkdir dir="${external.libs.dir}" />
-        <mkdir dir="${gen.dir}" />
-        <mkdir dir="${out.dir}" />
-        <mkdir dir="${out.classes.dir}" />
+        <mkdir dir="${resource.absolute.dir}" />
+        <mkdir dir="${external.libs.absolute.dir}" />
+        <mkdir dir="${gen.absolute.dir}" />
+        <mkdir dir="${out.absolute.dir}" />
+        <mkdir dir="${out.classes.absolute.dir}" />
     </target>
 
     <!-- Generates the R.java file for this project's resources. -->
@@ -82,11 +92,11 @@
             <arg value="package" />
             <arg value="-m" />
             <arg value="-J" />
-            <arg path="${gen.dir}" />
+            <arg path="${gen.absolute.dir}" />
             <arg value="-M" />
             <arg path="AndroidManifest.xml" />
             <arg value="-S" />
-            <arg path="${resource.dir}" />
+            <arg path="${resource.absolute.dir}" />
             <arg value="-I" />
             <arg path="${android.jar}" />
         </exec>
@@ -97,9 +107,9 @@
         <echo>Compiling aidl files into Java classes...</echo>
         <apply executable="${aidl}" failonerror="true">
             <arg value="-p${android.aidl}" />
-            <arg value="-I${source.dir}" />
-            <arg value="-o${gen.dir}" />
-            <fileset dir="${source.dir}">
+            <arg value="-I${source.absolute.dir}" />
+            <arg value="-o${gen.absolute.dir}" />
+            <fileset dir="${source.absolute.dir}">
                 <include name="**/*.aidl" />
             </fileset>
         </apply>
@@ -108,27 +118,48 @@
     <!-- Compiles this project's .java files into .class files. -->
     <target name="compile" depends="-resource-src, -aidl"
                 description="Compiles project's .java files into .class files">
+        <!-- Allows to inject additional classpath from another (build|property) file.
+             As ant properties are immutable, the injected value will have priority
+             over the one defined below -->
+        <property name="extensible.classpath" value="." />
         <javac encoding="ascii" target="1.5" debug="true" extdirs=""
-                destdir="${out.classes.dir}"
-                bootclasspathref="android.target.classpath">
-            <src path="${source.dir}" />
-            <src path="${gen.dir}" />
+                destdir="${out.classes.absolute.dir}"
+                bootclasspathref="android.target.classpath"
+                verbose="false" classpath="${extensible.classpath}">
+            <src path="${source.absolute.dir}" />
+            <src path="${gen.absolute.dir}" />
             <classpath>
-                <fileset dir="${external.libs.dir}" includes="*.jar" />
-                <pathelement path="${main.out.classes.dir}" />
+                <fileset dir="${external.libs.absolute.dir}" includes="*.jar" />
             </classpath>
-         </javac>
+        </javac>
     </target>
 
+    <!-- Configurable macro, which allows to pass as parameters output directory,
+         output dex filename and external libraries to dex (optional) -->
+    <macrodef name="dex-helper">
+       <attribute name="out.absolute.dir" />
+       <attribute name="out.dex.file" />
+       <element name="external-libs" optional="yes" />
+       <sequential>
+         <echo>Converting compiled files and external libraries into @{out.dex.file}...</echo>
+         <apply executable="${dx}" failonerror="true" parallel="true">
+             <arg value="--dex" />
+             <arg value="--output=@{out.dex.file}" />
+             <arg path="@{out.absolute.dir}" />
+             <external-libs />
+         </apply>
+       </sequential>
+    </macrodef>
+
     <!-- Converts this project's .class files into .dex files -->
     <target name="-dex" depends="compile">
-        <echo>Converting compiled files and external libraries into ${out.dir}/${dex.file.name}...</echo>
-        <apply executable="${dx}" failonerror="true" parallel="true">
-            <arg value="--dex" />
-            <arg value="--output=${intermediate.dex.file}" />
-            <arg path="${out.classes.dir}" />
-            <fileset dir="${external.libs.dir}" includes="*.jar" />
-        </apply>
+        <dex-helper out.absolute.dir="${out.absolute.dir}/classes"
+                out.dex.file="${intermediate.dex.file}">
+            <external-libs>
+                <!-- Temporary solution, before <jarfile> in <apkbuilder> is ready -->
+                <fileset dir="${external.jars}" includes="*.jar" />
+            </external-libs>
+        </dex-helper>
     </target>
 
     <!-- Puts the project's resources into the output package file
@@ -141,10 +172,10 @@
         <aaptexec executable="${aapt}"
                 command="package"
                 manifest="AndroidManifest.xml"
-                resources="${resource.dir}"
-                assets="${asset.dir}"
+                resources="${resource.absolute.dir}"
+                assets="${asset.absolute.dir}"
                 androidjar="${android.jar}"
-                outfolder="${out.dir}"
+                outfolder="${out.absolute.dir}"
                 basename="${ant.project.name}" />
     </target>
 
@@ -152,14 +183,14 @@
          This requires the property sign.package to be set to true or false. -->
     <target name="-package">
         <apkbuilder
-                outfolder="${out.dir}"
+                outfolder="${out.absolute.dir}"
                 basename="${ant.project.name}"
                 signed="${sign.package}"
                 verbose="true">
             <file path="${intermediate.dex.file}" />
-            <sourcefolder path="${source.dir}" />
-            <jarfolder path="${external.libs.dir}" />
-            <nativefolder path="${native.libs.dir}" />
+            <sourcefolder path="${source.absolute.dir}" />
+            <jarfolder path="${external.jars}" />
+            <nativefolder path="${native.libs.absolute.dir}" />
         </apkbuilder>
     </target>
 
@@ -171,8 +202,8 @@
        <property name="sign.package" value="true" />
     </target>
 
-    <target name="debug" depends="-dex, -package-resources, -debug-sign, -package"
-                description="Builds the application and signs it with a debug key.">
+    <!-- Builds debug output package, provided all the necessary files are already dexed -->
+    <target name="-debug-no-dex" depends="-package-resources, -debug-sign, -package">
         <echo>Running zip align on final apk...</echo>
         <exec executable="${zipalign}" failonerror="true">
             <arg value="-f" />
@@ -183,8 +214,10 @@
         <echo>Debug Package: ${out.debug.package}</echo>
     </target>
 
-    <target name="-release-package" depends="-dex, -package-resources, -no-sign, -package">
-    </target>
+    <target name="debug" depends="-dex, -debug-no-dex"
+                description="Builds the application and signs it with a debug key." />
+
+    <target name="-release-package" depends="-dex, -package-resources, -no-sign, -package" />
 
     <target name="-release-check">
         <condition property="release.sign">
@@ -202,8 +235,8 @@
     </target>
 
     <target name="release" depends="-release-package, -release-nosign" if="release-sign"
-                description="Builds the application. The generated apk file must be signed before it is published.">
-
+                description="Builds the application. The generated apk file must be signed before
+                            it is published.">
         <!-- Gets passwords -->
         <input
                 message="Please enter keystore password (store:${key.store}):"
@@ -234,8 +267,7 @@
     </target>
 
     <!-- Installs the package on the default emulator/device -->
-    <target name="install" depends="debug"
-                description="Installs/reinstalls the debug package onto a running emulator or device. This can only be used if the application has not yet been installed.">
+    <target name="-install-no-deps">
         <echo>Installing ${out.debug.package} onto default emulator or device...</echo>
         <exec executable="${adb}" failonerror="true">
             <arg value="install" />
@@ -244,6 +276,13 @@
         </exec>
     </target>
 
+    <target name="install" depends="debug, -install-no-deps"
+                description="Installs/reinstalls the debug package onto a running
+                            emulator or device. If the application was previously installed,
+                            the signatures must match." />
+
+    <target name="-install-no-dex" depends="-debug-no-dex, -install-no-deps" />
+
     <target name="-uninstall-check">
         <condition property="uninstall.run">
            <isset property="application.package" />
@@ -251,11 +290,14 @@
     </target>
 
     <target name="-uninstall-error" depends="-uninstall-check" unless="uninstall.run">
-        <echo>Unable to run 'ant uninstall', application.package is not defined in build.properties</echo>
+        <echo>
+        Unable to run 'ant uninstall', application.package is not defined in build.properties
+        </echo>
     </target>
 
     <!-- Uninstalls the package from the default emulator/device -->
-    <target name="uninstall" depends="-uninstall-error" if="uninstall.run" description="Uninstalls the application from a running emulator or device.">
+    <target name="uninstall" depends="-uninstall-error" if="uninstall.run"
+                description="Uninstalls the application from a running emulator or device.">
         <echo>Uninstalling ${application.package} from the default emulator or device...</echo>
         <exec executable="${adb}" failonerror="true">
             <arg value="uninstall" />
@@ -264,8 +306,8 @@
     </target>
 
     <target name="clean" description="Removes output files created by other targets.">
-        <delete dir="${out.dir}" />
-        <delete dir="${gen.dir}" />
+        <delete dir="${out.absolute.dir}" />
+        <delete dir="${gen.absolute.dir}" />
     </target>
 
     <target name="help">
@@ -278,7 +320,7 @@
         <echo>   debug:     Builds the application and signs it with a debug key.</echo>
         <echo>   release:   Builds the application. The generated apk file must be</echo>
         <echo>              signed before it is published.</echo>
-        <echo>   install:   Installs/reinstall the debug package onto a running</echo>
+        <echo>   install:   Installs/reinstalls the debug package onto a running</echo>
         <echo>              emulator or device.</echo>
         <echo>              If the application was previously installed, the</echo>
         <echo>              signatures must match.</echo>
diff --git a/tools/scripts/android_test_rules.xml b/tools/scripts/android_test_rules.xml
new file mode 100644
index 0000000..dbad32d
--- /dev/null
+++ b/tools/scripts/android_test_rules.xml
@@ -0,0 +1,131 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project name="android_test_rules" default="run-tests">
+
+    <import file="android_rules.xml" />
+
+    <!-- Existence of this property in build.properties or build.xml is an assertion for the test
+         project
+         <property name="tested.project.dir" value=".." /> -->
+    <property name="tested.project.absolute.dir" location="${tested.project.dir}" />
+    <property name="instrumentation.dir" value="instru" />
+    <property name="instrumentation.absolute.dir" location="${instrumentation.dir}" />
+
+    <property name="test.runner" value="android.test.InstrumentationTestRunner" />
+    <property name="application.package.to.instrument" value="${application.package}.tests" />
+
+    <!-- Enables adding tested project classes location to test project classpath -->
+    <property name="extensible.classpath" value="${tested.project.absolute.dir}/bin/classes" />
+
+    <!-- TODO: make it more configurable in the next CL's - now it is default for auto-generated
+         project -->
+    <property name="emma.dump.file" value="/data/data/${application.package}/files/coverage.ec" />
+
+    <!-- Emma configuration -->
+    <property name="emma.dir" value="${sdk.dir}/tools/lib" />
+        <path id="emma.lib">
+             <pathelement location="${emma.dir}/emma.jar" />
+             <pathelement location="${emma.dir}/emma_ant.jar" />
+        </path>
+    <taskdef resource="emma_ant.properties" classpathref="emma.lib" />
+    <!-- End of emma configuration -->
+
+    <!-- Runs 'compile' target for tested project -->
+    <target name="-compile-tested-project">
+        <subant target="compile">
+           <fileset dir="${tested.project.absolute.dir}" includes="build.xml" />
+        </subant>
+    </target>
+
+    <!-- Emma-instruments tested project classes (compiles the tested project if necessary)
+         and writes instrumented classes to ${instrumentation.absolute.dir}/classes -->
+    <target name="-emma-instrument" depends="-compile-tested-project">
+        <echo>Instrumenting classes from ${instrumentation.dir}/${out.dir}/classes...</echo>
+        <!-- It only instruments class files, not any external libs -->
+        <emma enabled="true">
+            <instr verbosity="verbose"
+                   mode="copy"
+                   instrpath="${tested.project.absolute.dir}/${out.dir}/classes"
+                   outdir="${instrumentation.absolute.dir}/classes">
+            </instr>
+            <!-- TODO: exclusion filters on R*.class and allowing custom exclusion from
+                 user defined file -->
+        </emma>
+    </target>
+
+    <!-- Dexes emma-instrumented classes -->
+    <target name="-dex-instrumented" depends="-emma-instrument">
+       <dex-helper out.absolute.dir="${instrumentation.absolute.dir}/classes"
+                                   out.dex.file="${instrumentation.absolute.dir}/${dex.file.name}">
+          <external-libs>
+            <fileset dir="${external.libs.dir}" includes="*.jar" />
+            <fileset dir="${emma.dir}">
+                <include name="emma_device.jar" />
+            </fileset>
+          </external-libs>
+       </dex-helper>
+    </target>
+
+    <!-- Installs instrumented package on the default emulator/device -->
+    <target name="-install-instrumented" depends="-dex-instrumented">
+        <subant target="-install-no-dex">
+            <property name="out.absolute.dir" value="${instrumentation.absolute.dir}" />
+            <property name="external.jars" location="${emma.dir}/emma_device.jar" />
+            <fileset dir="${tested.project.absolute.dir}" includes="build.xml" />
+        </subant>
+    </target>
+
+    <macrodef name="run-tests-helper">
+        <attribute name="emma.enabled" default="false" />
+        <sequential>
+            <echo>Running tests ...</echo>
+            <exec executable="${adb}" failonerror="true">
+                <arg value="shell" />
+                    <arg value="am" />
+                <arg value="instrument" />
+                   <arg value="-w" />
+                <arg value="-e" />
+                   <arg value="coverage" />
+                <arg value="@{emma.enabled}" />
+                   <arg value="${application.package.to.instrument}/${test.runner}" />
+            </exec>
+        </sequential>
+    </macrodef>
+
+    <!-- Ensures that tested project is installed on the device before we run the tests.
+         Used for ordinary tests, without coverage measurement -->
+    <target name="-install-tested-project">
+        <subant target="install">
+            <fileset dir="${tested.project.absolute.dir}" includes="build.xml" />
+        </subant>
+    </target>
+
+    <target name="run-tests" depends="-install-tested-project, install"
+                description="Runs tests from the package defined in test.package property">
+        <run-tests-helper />
+    </target>
+
+    <target name="coverage" depends="-install-instrumented, install"
+                description="Runs test on instrumented code and generates code coverage report">
+        <run-tests-helper emma.enabled="true" />
+        <echo>Downloading coverage file into project directory...</echo>
+        <exec executable="${adb}" failonerror="true">
+            <arg value="pull" />
+            <arg value="${emma.dump.file}" />
+            <arg value="coverage.ec" />
+        </exec>
+        <echo>Extracting coverage report...</echo>
+        <emma>
+            <report sourcepath="${tested.project.absolute.dir}/${source.dir}"
+                              verbosity="verbose">
+                <!-- TODO: report.dir or something like should be introduced if necessary -->
+                <infileset dir=".">
+                    <include name="coverage.ec" />
+                    <include name="coverage.em" />
+                </infileset>
+                <!-- TODO: reports in other, indicated by user formats -->
+                <html outfile="coverage.html" />
+           </report>
+        </emma>
+    </target>
+
+</project>
diff --git a/tools/scripts/build.template b/tools/scripts/build.template
index ca15954..3959c57 100644
--- a/tools/scripts/build.template
+++ b/tools/scripts/build.template
@@ -63,4 +63,5 @@
          build steps are used.
     -->
     <setup />
+
 </project>