Change help test generation to use clearsilver templates just like the rest of the system.  This should more easily allow customization of the generated output.

Change-Id: I5c51f3781aab3ce85653ecb69c1f10fd76d8c172
diff --git a/tools/monkeyrunner/src/Android.mk b/tools/monkeyrunner/src/Android.mk
index 614acca..59337c6 100644
--- a/tools/monkeyrunner/src/Android.mk
+++ b/tools/monkeyrunner/src/Android.mk
@@ -22,30 +22,11 @@
 LOCAL_JAVA_LIBRARIES := \
 	ddmlib \
 	jython \
-	xmlwriter \
-	guavalib
-
+	guavalib \
+	clearsilver
+LOCAL_SHARED_LIBRARIES := libclearsilver-jni
+LOCAL_JAVA_RESOURCE_DIRS := resources
 
 LOCAL_MODULE := monkeyrunner
 
 include $(BUILD_HOST_JAVA_LIBRARY)
-
-# Build ext.jar
-# ============================================================
-
-ext_dirs := 	../../../../external/xmlwriter/src
-
-ext_src_files := $(call all-java-files-under,$(ext_dirs))
-
-# ====  the library  =========================================
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(ext_src_files)
-
-LOCAL_NO_STANDARD_LIBRARIES := true
-#LOCAL_JAVA_LIBRARIES := core
-#LOCAL_STATIC_JAVA_LIBRARIES := libgoogleclient
-
-LOCAL_MODULE := xmlwriter
-
-include $(BUILD_HOST_JAVA_LIBRARY)
diff --git a/tools/monkeyrunner/src/com/android/monkeyrunner/MonkeyImage.java b/tools/monkeyrunner/src/com/android/monkeyrunner/MonkeyImage.java
index 7475407..7cff67f 100644
--- a/tools/monkeyrunner/src/com/android/monkeyrunner/MonkeyImage.java
+++ b/tools/monkeyrunner/src/com/android/monkeyrunner/MonkeyImage.java
@@ -198,8 +198,10 @@
     }
 
     @MonkeyRunnerExported(doc = "Compare this image to the other image.",
-            args = {"other"},
-            argDocs = {"The other image."},
+            args = {"other", "percent"},
+            argDocs = {"The other image.",
+                       "A float from 0.0 to 1.0 indicating the percentage " +
+                           "of pixels that need to be the same.  Defaults to 1.0"},
             returns = "True if they are the same image.")
     public boolean sameAs(PyObject[] args, String[] kws) {
         ArgParser ap = JythonUtils.createArgParser(args, kws);
@@ -208,6 +210,8 @@
         PyObject otherObject = ap.getPyObject(0);
         MonkeyImage other = (MonkeyImage) otherObject.__tojava__(MonkeyImage.class);
 
+        double percent = JythonUtils.getFloat(ap, 1, 1.0);
+
         BufferedImage otherImage = other.getBufferedImage();
         BufferedImage myImage = getBufferedImage();
 
@@ -222,15 +226,21 @@
         int[] otherPixel = new int[1];
         int[] myPixel = new int[1];
 
+        int width = myImage.getWidth();
+        int height = myImage.getHeight();
+
+        int numDiffPixels = 0;
         // Now, go through pixel-by-pixel and check that the images are the same;
-        for (int y = 0; y < myImage.getHeight(); y++) {
-            for (int x = 0; x < myImage.getWidth(); x++) {
+        for (int y = 0; y < height; y++) {
+            for (int x = 0; x < width; x++) {
                 if (myImage.getRGB(x, y) != otherImage.getRGB(x, y)) {
-                    return false;
+                    numDiffPixels++;
                 }
             }
         }
-        return true;
+        double numberPixels = (height * width);
+        double diffPercent = numDiffPixels / numberPixels;
+        return percent <= 1.0 - diffPercent;
     }
 
     private static class BufferedImageMonkeyImage extends MonkeyImage {
diff --git a/tools/monkeyrunner/src/com/android/monkeyrunner/MonkeyRunner.java b/tools/monkeyrunner/src/com/android/monkeyrunner/MonkeyRunner.java
index 66ceedd..cdab926 100644
--- a/tools/monkeyrunner/src/com/android/monkeyrunner/MonkeyRunner.java
+++ b/tools/monkeyrunner/src/com/android/monkeyrunner/MonkeyRunner.java
@@ -90,12 +90,16 @@
 
     @MonkeyRunnerExported(doc = "Simple help command to dump the MonkeyRunner supported " +
             "commands",
+            args = { "format" },
+            argDocs = {"The format to return the help text in. (default is text)"},
             returns = "The help text")
     public static String help(PyObject[] args, String[] kws) {
         ArgParser ap = JythonUtils.createArgParser(args, kws);
         Preconditions.checkNotNull(ap);
 
-        return MonkeyRunnerHelp.helpString();
+        String format = ap.getString(0, "text");
+
+        return MonkeyRunnerHelp.helpString(format);
     }
 
     @MonkeyRunnerExported(doc = "Put up an alert dialog to inform the user of something that " +
diff --git a/tools/monkeyrunner/src/com/android/monkeyrunner/MonkeyRunnerHelp.java b/tools/monkeyrunner/src/com/android/monkeyrunner/MonkeyRunnerHelp.java
index bda4551..8dbe85b 100644
--- a/tools/monkeyrunner/src/com/android/monkeyrunner/MonkeyRunnerHelp.java
+++ b/tools/monkeyrunner/src/com/android/monkeyrunner/MonkeyRunnerHelp.java
@@ -19,15 +19,20 @@
 import com.google.common.collect.Collections2;
 import com.google.common.collect.Lists;
 import com.google.common.collect.Sets;
+import com.google.common.io.Resources;
 
 import com.android.monkeyrunner.doc.MonkeyRunnerExported;
 
-import java.io.ByteArrayOutputStream;
-import java.io.PrintStream;
+import org.clearsilver.CS;
+import org.clearsilver.CSFileLoader;
+import org.clearsilver.HDF;
+
+import java.io.IOException;
 import java.lang.reflect.Constructor;
 import java.lang.reflect.Field;
 import java.lang.reflect.Member;
 import java.lang.reflect.Method;
+import java.nio.charset.Charset;
 import java.util.Arrays;
 import java.util.Comparator;
 import java.util.List;
@@ -39,6 +44,18 @@
 public final class MonkeyRunnerHelp {
     private MonkeyRunnerHelp() { }
 
+    private static final String HELP = "help";
+    private static final String NAME = "name";
+    private static final String DOC = "doc";
+    private static final String ARGUMENT = "argument";
+    private static final String RETURNS = "returns";
+    private static final String TYPE = "type";
+
+    // Enum used to describe documented types.
+    private enum Type {
+        ENUM, FIELD, METHOD
+    }
+
     private static void getAllExportedClasses(Set<Field> fields,
             Set<Method> methods,
             Set<Constructor<?>> constructors,
@@ -120,13 +137,35 @@
         }
     };
 
-    public static String helpString() {
-        ByteArrayOutputStream os = new ByteArrayOutputStream();
-        help(new PrintStream(os, true));
-        return os.toString();
+    public static String helpString(String format) {
+        // Quick check for support formats
+        if ("html".equals(format) || "text".equals(format)) {
+            HDF hdf = buildHelpHdf();
+            CS clearsilver = new CS(hdf);
+            // Set a custom file loader to load requested files from resources relative to this class.
+            clearsilver.setFileLoader(new CSFileLoader() {
+                public String load(HDF hdf, String filename) throws IOException {
+                    return Resources.toString(Resources.getResource(MonkeyRunnerHelp.class, filename),
+                            Charset.defaultCharset());
+                }
+            });
+
+            // Load up the CS template file
+            clearsilver.parseFile(format.toLowerCase() + ".cs");
+            // And render the output
+            return clearsilver.render();
+        } else if ("hdf".equals(format)) {
+            HDF hdf = buildHelpHdf();
+            return hdf.writeString();
+        }
+        return "";
     }
 
-    private static void help(PrintStream out) {
+    private static HDF buildHelpHdf() {
+        HDF hdf = new HDF();
+
+        int outputItemCount = 0;
+
         Set<Field> fields = Sets.newTreeSet(MEMBER_SORTER);
         Set<Method> methods = Sets.newTreeSet(MEMBER_SORTER);
         Set<Constructor<?>> constructors = Sets.newTreeSet(MEMBER_SORTER);
@@ -134,51 +173,54 @@
         getAllExportedClasses(fields, methods, constructors, classes);
 
         for (Class<?> clz : classes) {
-            out.println(clz.getCanonicalName() + ":");
+            String prefix = HELP + "." + outputItemCount + ".";
+
+            hdf.setValue(prefix + NAME, clz.getCanonicalName());
             MonkeyRunnerExported annotation = clz.getAnnotation(MonkeyRunnerExported.class);
-            out.println("  " + annotation.doc());
+            hdf.setValue(prefix + DOC, annotation.doc());
+            hdf.setValue(prefix + TYPE, Type.ENUM.name());
+
+            // Now go through the enumeration constants
             Object[] constants = clz.getEnumConstants();
             String[] argDocs = annotation.argDocs();
             if (constants.length > 0) {
-                out.println("  Values:");
                 for (int x = 0; x < constants.length; x++) {
-                    Object constant = constants[x];
-                    StringBuilder sb = new StringBuilder();
-                    sb.append("    ").append(constant);
+                    String argPrefix = prefix + ARGUMENT + "." + x + ".";
+                    hdf.setValue(argPrefix + NAME, constants[x].toString());
                     if (argDocs.length > x) {
-                        sb.append(" - ").append(argDocs[x]);
+                        hdf.setValue(argPrefix + DOC, argDocs[x]);
                     }
-
-                    out.println(sb.toString());
                 }
             }
-            out.println();
+            outputItemCount++;
         }
 
         for (Method m : methods) {
+            String prefix = HELP + "." + outputItemCount + ".";
+
             MonkeyRunnerExported annotation = m.getAnnotation(MonkeyRunnerExported.class);
             String className = m.getDeclaringClass().getCanonicalName();
             String methodName = className + "." + m.getName();
-            out.println(methodName + ":");
-            out.println("  " + annotation.doc());
+            hdf.setValue(prefix + NAME, methodName);
+            hdf.setValue(prefix + DOC, annotation.doc());
             if (annotation.args().length > 0) {
-                out.println("  Args:");
                 String[] argDocs = annotation.argDocs();
                 String[] aargs = annotation.args();
                 for (int x = 0; x < aargs.length; x++) {
-                    StringBuilder sb = new StringBuilder();
-                    sb.append("      ").append(aargs[x]);
+                    String argPrefix = prefix + ARGUMENT + "." + x + ".";
+
+                    hdf.setValue(argPrefix + NAME, aargs[x]);
                     if (argDocs.length > x) {
-                        sb.append(" - ").append(argDocs[x]);
+                        hdf.setValue(argPrefix + DOC, argDocs[x]);
                     }
-                    out.println(sb.toString());
                 }
             }
             if (!"".equals(annotation.returns())) {
-                out.println("  Returns:");
-                out.println("      " + annotation.returns());
+                hdf.setValue(prefix + RETURNS, annotation.returns());
             }
-            out.println();
+            outputItemCount++;
         }
+
+        return hdf;
     }
 }
diff --git a/tools/monkeyrunner/src/com/android/monkeyrunner/ScriptRunner.java b/tools/monkeyrunner/src/com/android/monkeyrunner/ScriptRunner.java
index 7b2edb0..c247a5f 100644
--- a/tools/monkeyrunner/src/com/android/monkeyrunner/ScriptRunner.java
+++ b/tools/monkeyrunner/src/com/android/monkeyrunner/ScriptRunner.java
@@ -24,6 +24,7 @@
 import org.python.core.PyException;
 import org.python.core.PyObject;
 import org.python.util.InteractiveConsole;
+import org.python.util.JLineConsole;
 import org.python.util.PythonInterpreter;
 
 import java.io.File;
@@ -170,7 +171,7 @@
      */
     public static void console() {
         initPython();
-        InteractiveConsole python = new InteractiveConsole();
+        InteractiveConsole python = new JLineConsole();
         python.interact();
     }
 }
diff --git a/tools/monkeyrunner/src/resources/com/android/monkeyrunner/html.cs b/tools/monkeyrunner/src/resources/com/android/monkeyrunner/html.cs
new file mode 100644
index 0000000..98bf211
--- /dev/null
+++ b/tools/monkeyrunner/src/resources/com/android/monkeyrunner/html.cs
@@ -0,0 +1,23 @@
+<html>
+<body>
+<h1>MonkeyRunner Help<h1>
+<h2>Table of Contents</h2>
+<ul>
+<?cs each:item = help ?>
+<li><a href="#<?cs name:item ?>"><?cs var:item.name ?></a></li>
+<?cs /each ?>
+</ul>
+<?cs each:item = help ?>
+<h2><a name="<?cs name:item ?>"><?cs var:item.name ?></a></h2>
+  <p><?cs var:item.doc ?></p>
+    <?cs if:subcount(item.argument) ?>
+<h3>Args</h3>
+<ul>
+      <?cs each:arg = item.argument ?>
+        <li><?cs var:arg.name ?> - <?cs var:arg.doc ?></li>
+      <?cs /each ?>
+</ul>
+<?cs /if ?>
+<?cs /each ?>
+</body>
+</html>
diff --git a/tools/monkeyrunner/src/resources/com/android/monkeyrunner/text.cs b/tools/monkeyrunner/src/resources/com/android/monkeyrunner/text.cs
new file mode 100644
index 0000000..b20095c
--- /dev/null
+++ b/tools/monkeyrunner/src/resources/com/android/monkeyrunner/text.cs
@@ -0,0 +1,8 @@
+MonkeyRunner help
+<?cs each:item = help ?>
+<?cs var:item.name ?>
+  <?cs var:item.doc ?>
+
+<?cs if:subcount(item.argument) ?>  Args:<?cs each:arg = item.argument ?>
+    <?cs var:arg.name ?> - <?cs var:arg.doc ?><?cs /each ?>
+<?cs /if ?><?cs /each ?>