Change the jtreg tool to perform both building and running steps.
diff --git a/libcore/tools/dalvik_jtreg/Android.mk b/libcore/tools/dalvik_jtreg/Android.mk
index d70a969..f65db2a 100644
--- a/libcore/tools/dalvik_jtreg/Android.mk
+++ b/libcore/tools/dalvik_jtreg/Android.mk
@@ -3,10 +3,14 @@
 include $(CLEAR_VARS)
 
 LOCAL_SRC_FILES := \
+        java/dalvik/jtreg/Adb.java \
         java/dalvik/jtreg/Command.java \
         java/dalvik/jtreg/CommandFailedException.java \
         java/dalvik/jtreg/Dx.java \
+        java/dalvik/jtreg/Dalvikvm.java \
         java/dalvik/jtreg/Javac.java \
+        java/dalvik/jtreg/JtregRunner.java \
+        java/dalvik/jtreg/Run.java \
         java/dalvik/jtreg/TestDescriptions.java \
         java/dalvik/jtreg/TestRunner.java \
         java/dalvik/jtreg/TestToDex.java \
diff --git a/libcore/tools/dalvik_jtreg/java/dalvik/jtreg/Adb.java b/libcore/tools/dalvik_jtreg/java/dalvik/jtreg/Adb.java
new file mode 100644
index 0000000..71ea690
--- /dev/null
+++ b/libcore/tools/dalvik_jtreg/java/dalvik/jtreg/Adb.java
@@ -0,0 +1,35 @@
+/*
+ * 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 dalvik.jtreg;
+
+import java.io.File;
+
+/**
+ * An adb command.
+ */
+final class Adb {
+
+    public void mkdir(File name) {
+        new Command("adb", "shell", "mkdir", name.toString())
+                .execute();
+    }
+
+    public void push(File local, File remote) {
+        new Command("adb", "push", local.toString(), remote.toString())
+                .execute();
+    }
+}
\ No newline at end of file
diff --git a/libcore/tools/dalvik_jtreg/java/dalvik/jtreg/Command.java b/libcore/tools/dalvik_jtreg/java/dalvik/jtreg/Command.java
index 5749dac..5558ced 100644
--- a/libcore/tools/dalvik_jtreg/java/dalvik/jtreg/Command.java
+++ b/libcore/tools/dalvik_jtreg/java/dalvik/jtreg/Command.java
@@ -27,7 +27,7 @@
 /**
  * An out of process executable.
  */
-class Command {
+final class Command {
 
     private final List<String> args;
     private final boolean permitNonZeroExitStatus;
diff --git a/libcore/tools/dalvik_jtreg/java/dalvik/jtreg/CommandFailedException.java b/libcore/tools/dalvik_jtreg/java/dalvik/jtreg/CommandFailedException.java
index cbfffdc..ebbb42e 100644
--- a/libcore/tools/dalvik_jtreg/java/dalvik/jtreg/CommandFailedException.java
+++ b/libcore/tools/dalvik_jtreg/java/dalvik/jtreg/CommandFailedException.java
@@ -21,7 +21,7 @@
 /**
  * Thrown when an out of process executable does not return normally.
  */
-public class CommandFailedException extends RuntimeException {
+class CommandFailedException extends RuntimeException {
 
     private final List<String> args;
     private final List<String> outputLines;
diff --git a/libcore/tools/dalvik_jtreg/java/dalvik/jtreg/Dalvikvm.java b/libcore/tools/dalvik_jtreg/java/dalvik/jtreg/Dalvikvm.java
new file mode 100644
index 0000000..9137703
--- /dev/null
+++ b/libcore/tools/dalvik_jtreg/java/dalvik/jtreg/Dalvikvm.java
@@ -0,0 +1,49 @@
+/*
+ * 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 dalvik.jtreg;
+
+import java.io.File;
+import java.util.List;
+
+/**
+ * A dalvikvm command.
+ */
+final class Dalvikvm {
+
+    private final Command.Builder builder = new Command.Builder();
+
+    public Dalvikvm() {
+        builder.args("adb", "shell", "dalvikvm");
+    }
+
+    Dalvikvm classpath(File... files) {
+        builder.args("-classpath");
+        builder.args(Command.path(files));
+        return this;
+    }
+
+    List<String> exec(String classname, String... args) {
+        builder.args(classname);
+        builder.args(args);
+        return builder.execute();
+    }
+
+    public Dalvikvm args(String... args) {
+        builder.args(args);
+        return this;
+    }
+}
diff --git a/libcore/tools/dalvik_jtreg/java/dalvik/jtreg/Dx.java b/libcore/tools/dalvik_jtreg/java/dalvik/jtreg/Dx.java
index 1a49d73..0e50ef6 100644
--- a/libcore/tools/dalvik_jtreg/java/dalvik/jtreg/Dx.java
+++ b/libcore/tools/dalvik_jtreg/java/dalvik/jtreg/Dx.java
@@ -21,7 +21,7 @@
 /**
  * A dx command.
  */
-public class Dx {
+final class Dx {
 
     public void dex(String output, File... inputs) {
         new Command.Builder()
diff --git a/libcore/tools/dalvik_jtreg/java/dalvik/jtreg/Javac.java b/libcore/tools/dalvik_jtreg/java/dalvik/jtreg/Javac.java
index f5ed09f..4a66abb 100644
--- a/libcore/tools/dalvik_jtreg/java/dalvik/jtreg/Javac.java
+++ b/libcore/tools/dalvik_jtreg/java/dalvik/jtreg/Javac.java
@@ -22,20 +22,25 @@
 /**
  * A javac command.
  */
-class Javac {
+final class Javac {
 
     private final Command.Builder builder = new Command.Builder();
 
     Javac() {
-        builder.args("javac");
+        builder.args("javac", "-Xmaxerrs", "1");
     }
 
-    public Javac classPath(File... path) {
+    public Javac bootClasspath(File... path) {
+        builder.args("-bootclasspath", Command.path(path));
+        return this;
+    }
+
+    public Javac classpath(File... path) {
         builder.args("-classpath", Command.path(path));
         return this;
     }
 
-    public Javac sourcePath(File... path) {
+    public Javac sourcepath(File... path) {
         builder.args("-sourcepath", Command.path(path));
         return this;
     }
@@ -47,7 +52,6 @@
 
     public List<String> compile(File... files) {
         return builder.args(Command.objectsToStrings(files))
-                .permitNonZeroExitStatus()
                 .execute();
     }
 }
diff --git a/libcore/tools/dalvik_jtreg/java/dalvik/jtreg/JtregRunner.java b/libcore/tools/dalvik_jtreg/java/dalvik/jtreg/JtregRunner.java
new file mode 100644
index 0000000..7fc23f0
--- /dev/null
+++ b/libcore/tools/dalvik_jtreg/java/dalvik/jtreg/JtregRunner.java
@@ -0,0 +1,164 @@
+// Copyright 2009 Google Inc. All Rights Reserved.
+
+package dalvik.jtreg;
+
+import com.sun.javatest.TestDescription;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.UUID;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+
+/**
+ * Runs a directory's worth of jtreg tests on a device.
+ */
+public final class JtregRunner {
+
+    private final File localTemp = new File("/tmp/" + UUID.randomUUID());
+    private final File deviceTemp = new File("/data/jtreg" + UUID.randomUUID());
+
+    private final Adb adb = new Adb();
+    private final File directoryToScan;
+    private final TestToDex testToDex;
+
+    private File deviceTestRunner;
+
+    public JtregRunner(File sdkJar, File directoryToScan) {
+        this.directoryToScan = directoryToScan;
+        this.testToDex = new TestToDex(sdkJar, localTemp);
+    }
+
+    public void buildAndRunAllTests() throws Exception {
+        localTemp.mkdirs();
+
+        prepareDevice();
+        List<TestDescription> tests = testToDex.findTests(directoryToScan);
+
+        // TODO: investigate why tests don't work when run in parallel on device
+        ExecutorService executor = Executors.newFixedThreadPool(1);
+        List<Future<Run>> futures = new ArrayList<Future<Run>>();
+        for (final TestDescription testDescription : tests) {
+            futures.add(executor.submit(new Callable<Run>() {
+                public Run call() throws Exception {
+                    return buildAndRunTest(testDescription);
+                }
+            }));
+        }
+
+        for (Future<Run> future : futures) {
+            try {
+                System.out.println(future.get());
+                System.out.println();
+            } catch (ExecutionException e) {
+                throw new RuntimeException(e);
+            } catch (InterruptedException e) {
+                throw new RuntimeException(e);
+            }
+        }
+
+        executor.shutdown();
+    }
+
+    /**
+     * Initializes the temporary directories and test harness necessary to run
+     * tests on a device.
+     */
+    private void prepareDevice() {
+        System.out.print("Preparing device...");
+        adb.mkdir(deviceTemp);
+        File testRunnerJar = testToDex.writeTestRunnerJar();
+        adb.push(testRunnerJar, deviceTemp);
+        deviceTestRunner = new File(deviceTemp, testRunnerJar.getName());
+        System.out.println("done.");
+    }
+
+    /**
+     * Creates a dex file for the given test, pushes it out to the device, and
+     * runs it, returning the test's result.
+     */
+    private Run buildAndRunTest(TestDescription testDescription)
+            throws IOException {
+        String qualifiedName = TestDescriptions.qualifiedName(testDescription);
+        File base = new File(deviceTemp, qualifiedName);
+        adb.mkdir(base);
+
+        File dex;
+        try {
+            dex = testToDex.dexify(testDescription);
+            if (dex == null) {
+                return new Run(testDescription, Run.Result.SKIPPED, Collections.<String>emptyList());
+            }
+        } catch (CommandFailedException e) {
+            return new Run(testDescription, Run.Result.COMPILE_FAILED, e.getOutputLines());
+        } catch (IOException e) {
+            return new Run(testDescription, Run.Result.ERROR, e);
+        }
+
+        adb.push(testDescription.getDir(), base);
+        adb.push(dex, deviceTemp);
+        File deviceDex = new File(deviceTemp, dex.getName());
+
+        return runTest(testDescription, base, deviceDex);
+    }
+
+    /**
+     * Runs the specified test on the device.
+     *
+     * @param base the test's base directory, from which local files can be
+     *      read by the test.
+     * @param dex the jar file containing the test code.
+     * @return the result of executing the test.
+     */
+    private Run runTest(TestDescription testDescription, File base, File dex) {
+        List<String> output = new Dalvikvm()
+                .classpath(dex, deviceTestRunner)
+                .args("-Duser.dir=" + base)
+                .exec("dalvik.jtreg.TestRunner");
+
+        if (output.isEmpty()) {
+            return new Run(testDescription, Run.Result.ERROR,
+                    Collections.singletonList("No output returned!"));
+        }
+
+        Run.Result result = "SUCCESS".equals(output.get(output.size() - 1))
+                ? Run.Result.SUCCESS
+                : Run.Result.EXEC_FAILED;
+        return new Run(testDescription, result, output.subList(0, output.size() - 1));
+    }
+
+    public static void main(String[] args) throws Exception {
+        if (args.length != 2) {
+            System.out.println("Usage: JTRegRunner <android_jar> <directoryWithTests>");
+            System.out.println();
+            System.out.println("  android_jar: the API jar file to compile against. Usually");
+            System.out.println("      this is <SDK>/platforms/android-<X.X>/android.jar where");
+            System.out.println("      <SDK> is the path to an Android SDK path and <X.X> is a");
+            System.out.println("      release version like 1.5.");
+            System.out.println();
+            System.out.println("  directoryWithTests: a directory to scan for test cases;");
+            System.out.println("      typically this is 'platform_v6/jdk/test' if 'platform_v6'");
+            System.out.println("      contains the sources of a platform implementation.");
+            System.out.println();
+            return;
+        }
+
+        File sdkJar = new File(args[0]);
+        if (!sdkJar.exists()) {
+            throw new RuntimeException("No such file: " + sdkJar);
+        }
+
+        File directoryToScan = new File(args[1]);
+        if (!directoryToScan.exists()) {
+            throw new RuntimeException("No such directory: " + directoryToScan);
+        }
+
+        new JtregRunner(sdkJar, directoryToScan).buildAndRunAllTests();
+    }
+}
diff --git a/libcore/tools/dalvik_jtreg/java/dalvik/jtreg/Run.java b/libcore/tools/dalvik_jtreg/java/dalvik/jtreg/Run.java
new file mode 100644
index 0000000..2755d93
--- /dev/null
+++ b/libcore/tools/dalvik_jtreg/java/dalvik/jtreg/Run.java
@@ -0,0 +1,62 @@
+// Copyright 2009 Google Inc. All Rights Reserved.
+
+package dalvik.jtreg;
+
+import com.sun.javatest.TestDescription;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * The outcome of a test run.
+ */
+public final class Run {
+
+    private final String qualifiedName;
+    private final String title;
+    private final Result result;
+    private final List<String> outputLines;
+
+    public Run(TestDescription testDescription, Result result, List<String> outputLines) {
+        this.qualifiedName = TestDescriptions.qualifiedName(testDescription);
+        this.title = testDescription.getTitle();
+        this.result = result;
+        this.outputLines = outputLines;
+    }
+
+    public Run(TestDescription testDescription, Result result, Exception e) {
+        this.qualifiedName = TestDescriptions.qualifiedName(testDescription);
+        this.title = testDescription.getTitle();
+        this.result = result;
+        this.outputLines = throwableToLines(e);
+    }
+
+    private static List<String> throwableToLines(Throwable t) {
+        StringWriter writer = new StringWriter();
+        PrintWriter out = new PrintWriter(writer);
+        t.printStackTrace(out);
+        return Arrays.asList(writer.toString().split("\\n"));
+    }
+
+    @Override public String toString() {
+        StringBuilder builder = new StringBuilder()
+                .append(qualifiedName).append(" ").append(result)
+                .append("\n  \"").append(title).append("\"");
+
+        for (String output : outputLines) {
+            builder.append("\n  ").append(output);
+        }
+
+        return builder.toString();
+    }
+
+    public enum Result {
+        SKIPPED,
+        COMPILE_FAILED,
+        EXEC_FAILED,
+        ERROR,
+        SUCCESS
+    }
+}
diff --git a/libcore/tools/dalvik_jtreg/java/dalvik/jtreg/TestDescriptions.java b/libcore/tools/dalvik_jtreg/java/dalvik/jtreg/TestDescriptions.java
index 74028dd..d0be8d2 100644
--- a/libcore/tools/dalvik_jtreg/java/dalvik/jtreg/TestDescriptions.java
+++ b/libcore/tools/dalvik_jtreg/java/dalvik/jtreg/TestDescriptions.java
@@ -23,7 +23,7 @@
 /**
  * Utility methods for manipulating {@link TestDescription} instances.
  */
-public class TestDescriptions {
+class TestDescriptions {
 
     /**
      * The subpath of a platform implementation under which tests live. Used to
@@ -39,31 +39,10 @@
         Properties result = new Properties();
         result.setProperty(TestRunner.CLASS_NAME, testDescription.getName());
         result.setProperty(TestRunner.QUALIFIED_NAME, qualifiedName(testDescription));
-        result.setProperty(TestRunner.TITLE, testDescription.getTitle());
-        result.setProperty(TestRunner.KEYWORDS, join(testDescription.getKeywords()));
-        result.setProperty(TestRunner.DIR, testDescription.getDir().toString());
-        result.setProperty(TestRunner.SOURCES, join(testDescription.getSources()));
         return result;
     }
 
     /**
-     * Concatenates the objects using ", " as a delimiter.
-     */
-    private static String join(Object[] objects) {
-        if (objects.length == 0) {
-            return "";
-        }
-
-        StringBuilder result = new StringBuilder(16 * objects.length);
-        result.append(objects[0]);
-        for (int i = 1; i < objects.length; i++) {
-            result.append(", ");
-            result.append(objects[i]);
-        }
-        return result.toString();
-    }
-
-    /**
      * Returns a fully qualified name of the form {@code
      * java_lang_Math_PowTests} from the given test description. The returned
      * name is appropriate for use in a filename.
diff --git a/libcore/tools/dalvik_jtreg/java/dalvik/jtreg/TestRunner.java b/libcore/tools/dalvik_jtreg/java/dalvik/jtreg/TestRunner.java
index 6aa3bd5..f1b5577 100644
--- a/libcore/tools/dalvik_jtreg/java/dalvik/jtreg/TestRunner.java
+++ b/libcore/tools/dalvik_jtreg/java/dalvik/jtreg/TestRunner.java
@@ -25,7 +25,7 @@
 /**
  * Runs a jtreg test that was prepared with {@link TestToDex}.
  */
-public class TestRunner {
+public final class TestRunner {
 
     /**
      * The name of the test properties file within the {@code .jar} file.
@@ -44,49 +44,20 @@
      */
     static final String QUALIFIED_NAME = "qualifiedName";
 
-    /**
-     * Property identifier for the test's title, such as {@code Some exponent
-     * over/undeflow tests for the pow method}.
-     */
-    static final String TITLE = "title";
-
-    /**
-     * Property identifier for the comma-separated list of keywords, such as
-     * { "bug4916097" }.
-     */
-    static final String KEYWORDS = "keywords";
-
-    /**
-     * Property identifier for the test's source directory, such as {@code
-     * platform_v6/jdk/test/java/math/BigDecimal}.
-     */
-    static final String DIR = "dir";
-
-    /**
-     * The comma-separated source files, such as { "PowTests.java" }.
-     */
-    static final String SOURCES = "sources";
-
     private String className;
     private String qualifiedName;
-    private String title;
-    private String keywords;
-    private String dir;
 
     private Method main;
 
     public void test(String[] args)
             throws InvocationTargetException, IllegalAccessException {
-        System.err.println("Executing " + qualifiedName);
+        System.out.println("Executing " + qualifiedName);
         try {
             main.invoke(null, new Object[] { args });
-            System.err.println("SUCCESS.");
+            System.out.println("SUCCESS");
         } catch (Throwable failure) {
             failure.printStackTrace();
-            System.err.println("FAILURE!");
-            System.err.println("  " + title);
-            System.err.println("  " + keywords);
-            System.err.println("  " + dir);
+            System.out.println("FAILURE");
         }
     }
 
@@ -106,9 +77,6 @@
 
         className = properties.getProperty(CLASS_NAME);
         qualifiedName = properties.getProperty(QUALIFIED_NAME);
-        title = properties.getProperty(TITLE);
-        keywords = properties.getProperty(KEYWORDS);
-        dir = properties.getProperty(DIR);
 
         if (className == null || qualifiedName == null) {
             throw new RuntimeException(TEST_PROPERTIES_FILE + " missing required values!");
@@ -125,13 +93,11 @@
     }
 
     public static void main(String[] args) throws Exception {
-        // Usage: TestRunner [test args]
+        // Usage: TestRunner [optional test args]...
 
         TestRunner testRunner = new TestRunner();
         testRunner.loadProperties();
         testRunner.prepareTest();
         testRunner.test(args);
-
-        // TODO: report the results out as an XML file in JUnit format
     }
 }
diff --git a/libcore/tools/dalvik_jtreg/java/dalvik/jtreg/TestToDex.java b/libcore/tools/dalvik_jtreg/java/dalvik/jtreg/TestToDex.java
index bf5525d..245ec75 100644
--- a/libcore/tools/dalvik_jtreg/java/dalvik/jtreg/TestToDex.java
+++ b/libcore/tools/dalvik_jtreg/java/dalvik/jtreg/TestToDex.java
@@ -25,28 +25,20 @@
 
 import java.io.File;
 import java.io.FileOutputStream;
-import java.io.FileWriter;
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Properties;
-import java.util.UUID;
-import java.util.concurrent.Callable;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-import java.util.concurrent.Future;
 import java.util.regex.Pattern;
 
 /**
  * Scans a directory of jtreg tests and creates Dalvik-friendly {@code .jar}
- * files for each test. These tests will be executed by {@link TestRunner} when
- * their jar file is on the classpath. Because of the heavy use of the default
- * package by jtreg tests, it is not generally possible to run multiple tests
- * in the same dalvik VM.
+ * files for them. These tests can be executed by {@link TestRunner}. Because of
+ * the heavy use of the default package by jtreg tests, it is not generally
+ * possible to run multiple tests in the same dalvik VM.
  */
-public class TestToDex {
+final class TestToDex {
 
     private static final String DALVIK_JTREG_HOME
             = "dalvik/libcore/tools/dalvik_jtreg";
@@ -57,44 +49,18 @@
 
     private final Pattern JAVA_TEST_PATTERN = Pattern.compile("\\/(\\w)+\\.java$");
 
-    private final File temp = new File("/tmp/" + UUID.randomUUID());
-    private final ExecutorService executor = Executors.newFixedThreadPool(20);
+    private final File sdkJar;
+    private final File temp;
 
-    public void testsToDex(File directoryToScan, final File out) throws Exception {
-        writeTestRunnerJar(out);
-
-        System.out.print("Scanning " + directoryToScan + "...");
-        List<TestDescription> tests = getTests(directoryToScan);
-        System.out.println("done. Found " + tests.size() + " tests.");
-
-        List<Future<File>> futures = new ArrayList<Future<File>>();
-        for (final TestDescription testDescription : tests) {
-            futures.add(executor.submit(new Callable<File>() {
-                public File call() throws Exception {
-                    return testToDex(testDescription, out);
-                }
-            }));
-        }
-
-        for (Future<File> future : futures) {
-            try {
-                future.get();
-            } catch (ExecutionException e) {
-                System.out.println("Failed: " + e.getMessage());
-            } catch (InterruptedException e) {
-                throw new RuntimeException(e);
-            }
-        }
-
-        executor.shutdown();
+    TestToDex(File sdkJar, File temp) {
+        this.sdkJar = sdkJar;
+        this.temp = temp;
     }
 
     /**
      * Creates a testrunner jar that can execute the packaged tests.
      */
-    private void writeTestRunnerJar(File out) {
-        // TODO: perform this step as a part of make
-
+    File writeTestRunnerJar() {
         File base = new File(temp, "testrunner");
         base.mkdirs();
 
@@ -102,76 +68,54 @@
                 .destination(base)
                 .compile(TEST_RUNNER_JAVA);
 
-        File output = new File(out, "testrunner.jar");
+        File output = new File(temp, "testrunner.jar");
         new Dx().dex(output.toString(), base);
-
-        System.out.println("Created: testrunner");
+        return output;
     }
 
     /**
      * Writes a Dalvik-friendly {@code .jar} for the described test.
      *
-     * @param out the directory to receive the constructed {@code .jar}.
-     * @return the path of the constructed {@code .jar}.
+     * @return the path of the constructed {@code .jar}, or {@code null} if the
+     *      test cannot be converted to Dex (presumably because it is not of
+     *      the right type).
+     * @throws CommandFailedException if javac fails
      */
-    private File testToDex(TestDescription testDescription, File out)
-            throws IOException {
+    File dexify(TestDescription testDescription) throws IOException {
         String qualifiedName = TestDescriptions.qualifiedName(testDescription);
 
         if (!JAVA_TEST_PATTERN.matcher(testDescription.getFile().toString()).find()) {
-            System.out.println("Skipping: " + qualifiedName);
             return null;
         }
 
-        File base = new File(temp, qualifiedName);
-        base.mkdirs();
+        File jarContents = new File(temp, qualifiedName);
+        jarContents.mkdirs();
 
         // write a test descriptor
         Properties properties = TestDescriptions.toProperties(testDescription);
         FileOutputStream propertiesOut = new FileOutputStream(
-                new File(base, TestRunner.TEST_PROPERTIES_FILE));
+                new File(jarContents, TestRunner.TEST_PROPERTIES_FILE));
         properties.store(propertiesOut, "generated by " + getClass().getName());
         propertiesOut.close();
 
-        try {
-            // TODO(jessewilson): compile against the Android API .jar
-            new Javac()
-                    .classPath(testDescription.getDir(), JTREG_JAR)
-                    .sourcePath(testDescription.getDir())
-                    .destination(base)
-                    .compile(testDescription.getFile());
-        } catch (CommandFailedException e) {
-            List<String> log = new ArrayList<String>();
-            log.add("command: " + e.getArgs());
-            log.addAll(e.getOutputLines());
-            String lastLogMessage = log.get(log.size() - 1);
-            File output = new File(out, qualifiedName + ".javac.txt");
-            writeFile(output, log);
-            System.out.println("Compile failed: " + qualifiedName + ": " + lastLogMessage);
-            return null;
-        }
+        new Javac()
+                .bootClasspath(sdkJar)
+                .classpath(testDescription.getDir(), JTREG_JAR)
+                .sourcepath(testDescription.getDir())
+                .destination(jarContents)
+                .compile(testDescription.getFile());
 
-        File output = new File(out, qualifiedName + ".jar");
-        new Dx().dex(output.toString(), base, testDescription.getDir());
-
-        System.out.println("Created: " + qualifiedName);
+        File output = new File(temp, qualifiedName + ".jar");
+        new Dx().dex(output.toString(), jarContents);
         return output;
     }
 
-    private void writeFile(File target, List<String> lines) throws IOException {
-        FileWriter writer = new FileWriter(target);
-        for (String line : lines) {
-            writer.append(line);
-            writer.append("\n");
-        }
-        writer.close();
-    }
-
     /**
      * Scans {@code directoryToScan} for test cases, using JTHarness + jtreg
      * behind the scenes.
      */
-    private List<TestDescription> getTests(File directoryToScan) throws Exception {
+    List<TestDescription> findTests(File directoryToScan) throws Exception {
+        System.out.print("Scanning " + directoryToScan + "...");
         File workDirectory = new File(temp, "JTwork");
         workDirectory.mkdirs();
 
@@ -190,27 +134,7 @@
             TestResult testResult = (TestResult) i.next();
             result.add(testResult.getDescription());
         }
+        System.out.println("done. Found " + result.size() + " tests.");
         return result;
     }
-
-    public static void main(String[] args) throws Exception {
-        if (args.length != 2) {
-            System.out.println("Usage: TestToDex <directoryToScan> <out>");
-            System.out.println();
-            System.out.println("  directoryToScan: a directory containing test cases; typically");
-            System.out.println("      this is 'platform_v6/jdk/test' if 'platform_v6' contains");
-            System.out.println("      the sources of a platform implementation.");
-            System.out.println();
-            System.out.println("  out: the directory to receive constructed .jars for successful");
-            System.out.println("      compilations and .javac.txt files for failed compilations.");
-            System.out.println();
-            return;
-        }
-
-        File directoryToScan = new File(args[0]);
-
-        File out = new File(args[1]);
-        out.mkdirs();
-        new TestToDex().testsToDex(directoryToScan, out);
-    }
 }