adding a recorder function to collect output into an xml file; adding getvars and listvars command to MonkeyRunner
diff --git a/tools/monkeyrunner/src/Android.mk b/tools/monkeyrunner/src/Android.mk
index 576025a..fb6b9c1 100644
--- a/tools/monkeyrunner/src/Android.mk
+++ b/tools/monkeyrunner/src/Android.mk
@@ -21,9 +21,31 @@
 LOCAL_JAR_MANIFEST := ../etc/manifest.txt
 LOCAL_JAVA_LIBRARIES := \
 	ddmlib \
-	jython
+	jython \
+	xmlwriter
 
 
 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/MonkeyRecorder.java b/tools/monkeyrunner/src/com/android/monkeyrunner/MonkeyRecorder.java
new file mode 100644
index 0000000..1132733
--- /dev/null
+++ b/tools/monkeyrunner/src/com/android/monkeyrunner/MonkeyRecorder.java
@@ -0,0 +1,311 @@
+/*
+ * 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.monkeyrunner;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipOutputStream;
+
+import org.jheer.XMLWriter;
+
+/**
+ *  MonkeyRecorder is a host side class that records the output of scripts that are run. 
+ *  It creates a unique directory, puts in an xml file that records each cmd and result.
+ *  It stores every screenshot in this directory.
+ *  When finished, it zips this all up.
+ *
+ *  Calling Sequence:
+ *    mr = new MonkeyRecorder(scriptName);
+ *    mr.startCommand();
+ *    [mr.addAttribute(name, value);]
+ *    ...
+ *    [mr.addInput(cmd);]
+ *    [mr.addResults(result, filename);]   // filename = "" if no screenshot
+ *    mr.endCommand();
+ *    mr.addComment(comment);
+ *    mr.startCommand();
+ *    ...
+ *    mr.endCommand();
+ *    ...
+ *    mr.close();
+ *
+ *  With MonkeyRunner this should output an xml file, <script_name>-yyyyMMdd-HH:mm:ss.xml, into the
+ *  directory out/<script_name>-yyyyMMdd-HH:mm:ss with the contents:
+ *
+ *  <?xml version="1.0" encoding='UTF-8'?>
+ *  <script_run>
+ *    script_name="filename"
+ *    monkeyRunnerVersion="0.2"
+ *    <!-- Device specific variables -->
+ *    <device_var var_name="name" var_value="value" />
+ *    <device_var name="build.display" value="opal-userdebug 1.6 DRC79 14207 test-keys"/>
+ *    ...
+ *    <!-- Script commands -->
+ *    <command>
+ *      dateTime="20090921-17:08:43"
+ *      <input cmd="Pressing: menu"/>
+ *      <response result="OK" dateTime="20090921-17:08:43"/>
+ *    </command>
+ *    ...
+ *    <command>
+ *      dateTime="20090921-17:09:44"
+ *      <input cmd="grabscreen"/>
+ *      <response result="OK" dateTime="20090921-17:09:45" screenshot="home_screen-20090921-17:09:45.png"/>
+ *    </command>
+ *    ...
+ *  </script_run>
+ *  
+ *  And then zip it up with all the screenshots in the file: <script_name>-yyyyMMdd-HH:mm:ss.zip.
+ */
+ 
+public class MonkeyRecorder {
+
+  // xml file to store output results in
+  private static String mXmlFilename;
+  private static FileWriter mXmlFile;
+  private static XMLWriter mXmlWriter;
+  
+  // unique subdirectory to put results in (screenshots and xml file)
+  private static String mDirname;
+  private static ArrayList <String> mScreenShots = new ArrayList<String>();
+  
+  // where we store all the results for all the script runs
+  private static final String ROOT_DIR = "out";
+  
+  // for getting the date and time in now()
+  private static final SimpleDateFormat SIMPLE_DATE_TIME_FORMAT = new SimpleDateFormat("yyyyMMdd-HH:mm:ss");
+  
+  /**
+   * Create a new MonkeyRecorder that records commands and zips up screenshots for submittal
+   * 
+   * @param scriptName filepath of the monkey script we are running
+   */
+  public MonkeyRecorder(String scriptName) throws IOException {
+    // Create directory structure to store xml file, images and zips
+    File scriptFile = new File(scriptName);
+    scriptName = scriptFile.getName();  // Get rid of path
+    mDirname = ROOT_DIR + "/" + stripType(scriptName) + "-" + now();
+    new File(mDirname).mkdirs();
+    
+    // Initialize xml file
+    mXmlFilename = stampFilename(stripType(scriptName) + ".xml");
+    initXmlFile(scriptName);
+  }
+
+  // Get the current date and time in a simple string format (used for timestamping filenames)
+  private static String now() {
+    return SIMPLE_DATE_TIME_FORMAT.format(Calendar.getInstance().getTime());     
+  }
+  
+  /**
+   * Initialize the xml file writer
+   * 
+   * @param scriptName filename (not path) of the monkey script, stored as attribute in the xml file
+   */
+  private static void initXmlFile(String scriptName) throws IOException {
+    mXmlFile = new FileWriter(mDirname + "/" + mXmlFilename);
+    mXmlWriter = new XMLWriter(mXmlFile);
+    mXmlWriter.begin();
+    mXmlWriter.comment("Monkey Script Results");
+    mXmlWriter.start("script_run");
+    mXmlWriter.addAttribute("script_name", scriptName);
+  }
+  
+  /**
+   * Add a comment to the xml file.
+   * 
+   * @param comment comment to add to the xml file
+   */
+  public static void addComment(String comment) throws IOException {
+    mXmlWriter.comment(comment);
+  }
+    
+  /**
+   * Begin writing a command xml element
+   */
+  public static void startCommand() throws IOException {
+    mXmlWriter.start("command");
+    mXmlWriter.addAttribute("dateTime", now());
+  }
+  
+  /**
+   * Write a command name attribute in a command xml element.  
+   * It's add as a sinlge script command could be multiple monkey commands.
+   * 
+   * @param cmd command sent to the monkey
+   */
+  public static void addInput(String cmd)  throws IOException {
+    String name = "cmd";
+    String value = cmd;
+    mXmlWriter.tag("input", name, value);
+  }
+  
+  /**
+   * Write a response xml element in a command.  
+   * Attributes include the monkey result, datetime, and possibly screenshot filename
+   * 
+   * @param result response of the monkey to the command
+   * @param filename filename of the screen shot (or other file to be included)
+   */
+  public static void addResult(String result, String filename) throws IOException {
+    int num_args = 2;
+    String[] names = new String[3];
+    String[] values = new String[3];
+    names[0] = "result";
+    values[0] = result;
+    names[1] = "dateTime";
+    values[1] = now();
+    if (filename.length() != 0) {
+      names[2] = "screenshot";
+      values[2] = stampFilename(filename); 
+      addScreenShot(filename);
+      num_args = 3;
+    }
+    mXmlWriter.tag("response", names, values, num_args); 
+  }
+  
+  /**
+   * Add an attribut to an xml element. name="escaped_value"
+   * 
+   * @param name name of the attribute
+   * @param value value of the attribute
+   */
+  public static void addAttribute(String name, String value) throws IOException {
+    mXmlWriter.addAttribute(name, value);
+  }
+
+   /**
+   * Add an xml device variable element. name="escaped_value"
+   * 
+   * @param name name of the variable
+   * @param value value of the variable
+   */
+  public static void addDeviceVar(String name, String value) throws IOException {
+    String[] names = {"name", "value"};
+    String[] values = {name, value};
+    mXmlWriter.tag("device_var", names, values, names.length);
+  }
+ 
+  /**
+   * Move the screenshot to storage and remember you did it so it can be zipped up later.
+   * 
+   * @param filename file name of the screenshot to be stored (Not path name)
+   */
+  private static void addScreenShot(String filename) {
+    File file = new File(filename);
+    String screenShotName = stampFilename(filename);
+    file.renameTo(new File(mDirname, screenShotName));
+    mScreenShots.add(screenShotName);
+  }
+
+  /**
+   * Finish writing a command xml element
+   */
+  public static void endCommand() throws IOException {
+    mXmlWriter.end();
+  }
+  
+  /**
+   * Add datetime in front of filetype (the stuff after and including the last infamous '.')
+   *
+   * @param filename path of file to be stamped
+   */
+  private static String stampFilename(String filename) {
+    // 
+    int typeIndex = filename.lastIndexOf('.');
+    if (typeIndex == -1) {
+      return filename + "-" + now();
+    }  
+    return filename.substring(0, typeIndex) + "-" + now() + filename.substring(typeIndex);
+  }
+  
+  /**
+   * Strip out the file type (the stuff after and including the last infamous '.')
+   *
+   * @param filename path of file to be stripped of type information
+   */
+   private static String stripType(String filename) {
+    // 
+    int typeIndex = filename.lastIndexOf('.');
+    if (typeIndex == -1)
+      return filename;
+    return filename.substring(0, typeIndex);
+  }
+  
+   /**
+   * Add a signature element
+   *
+   * @param filename path of file to be signatured
+   */
+   private static void addMD5Signature(String filename) throws IOException {
+      String signature = "";
+      // find signature... MD5 sig = new MD5(filename); signature = sig.toString();
+      String[] names = new String[] { "type", "filename", "signature" };
+      String[] values = new String[] { "md5", filename, signature };
+      mXmlWriter.tag("Signature", names, values, values.length);
+   }
+ 
+
+  /**
+   * Close the monkeyRecorder by closing the xml file and zipping it up with the screenshots.
+   *
+   * @param filename path of file to be stripped of type information
+   */ 
+  public static void close() throws IOException {
+    // zip up xml file and screenshots into ROOT_DIR.
+    byte[] buf = new byte[1024];
+    String zipFileName = mXmlFilename + ".zip";
+    endCommand();
+    mXmlFile.close();
+    FileOutputStream zipFile = new FileOutputStream(ROOT_DIR + "/" + zipFileName);
+    ZipOutputStream out = new ZipOutputStream(zipFile);
+
+    // add the xml file
+    addFileToZip(out, mDirname + "/" + mXmlFilename, buf);
+    
+    // Add the screenshots
+    for (String filename : mScreenShots) {
+      addFileToZip(out, mDirname + "/" + filename, buf);
+    }
+    out.close();
+  }
+  
+  /**
+   * Helper function to zip up a file into an open zip archive.
+   *
+   * @param zip the stream of the zip archive
+   * @param filepath the filepath of the file to be added to the zip archive
+   * @param buf storage place to stage reads of file before zipping
+   */ 
+  private static void addFileToZip(ZipOutputStream zip, String filepath, byte[] buf) throws IOException {
+    FileInputStream in = new FileInputStream(filepath);
+    zip.putNextEntry(new ZipEntry(filepath));
+    int len;
+    while ((len = in.read(buf)) > 0) {
+      zip.write(buf, 0, len);
+    }
+    zip.closeEntry();
+    in.close();
+  }
+}
diff --git a/tools/monkeyrunner/src/com/android/monkeyrunner/MonkeyRunner.java b/tools/monkeyrunner/src/com/android/monkeyrunner/MonkeyRunner.java
index cbc881c..13386c0 100644
--- a/tools/monkeyrunner/src/com/android/monkeyrunner/MonkeyRunner.java
+++ b/tools/monkeyrunner/src/com/android/monkeyrunner/MonkeyRunner.java
@@ -30,18 +30,21 @@
 import java.io.BufferedWriter;
 import java.io.File;
 import java.io.IOException;
+import java.io.InputStream;
 import java.io.InputStreamReader;
 import java.io.OutputStreamWriter;
 import java.net.InetAddress;
 import java.net.Socket;
 import java.net.UnknownHostException;
+import java.util.logging.Level;
+import java.util.logging.Logger;
 
 import javax.imageio.ImageIO;
 
 /**
  *  MonkeyRunner is a host side application to control a monkey instance on a
- * device. MonkeyRunner provides some useful helper functions to control the
- * device as well as various other methods to help script tests. 
+ *  device. MonkeyRunner provides some useful helper functions to control the
+ *  device as well as various other methods to help script tests. 
  */
 public class MonkeyRunner {
 
@@ -50,27 +53,45 @@
   static Socket monkeySocket = null;
 
   static IDevice monkeyDevice;
-  
+
   static BufferedReader monkeyReader;
   static BufferedWriter monkeyWriter;
+  static String monkeyResponse;
+
+  static MonkeyRecorder monkeyRecorder;
 
   static String scriptName = null;
+  
+  // Obtain a suitable logger.
+//  private static Logger logger = Logger.getLogger("com.android.monkeyrunner");
+  private static Logger logger = Logger.global;
 
   // delay between key events
   final static int KEY_INPUT_DELAY = 1000;
+  
+  // version of monkey runner
+  final static String monkeyRunnerVersion = "0.2";
 
-  public static void main(String[] args) {
+  public static void main(String[] args) throws IOException {
 
+    // haven't figure out how to get below INFO...bad parent.  Pass -v INFO to turn on logging 
+    logger.setLevel(Level.parse("WARNING"));  
     processOptions(args);
     
+    logger.info("initAdb");
     initAdbConnection();
+    logger.info("openMonkeyConnection");
     openMonkeyConnection();
 
+    logger.info("start_script");
     start_script();
     
+    logger.info("ScriptRunner.run");
     ScriptRunner.run(scriptName);
    
+    logger.info("end_script");
     end_script();
+    logger.info("closeMonkeyConnection");
     closeMonkeyConnection();  
   }
 
@@ -166,13 +187,15 @@
     try {
       InetAddress addr = InetAddress.getByName(monkeyServer);
       monkeySocket = new Socket(addr, monkeyPort);
+      monkeyWriter = new BufferedWriter(new OutputStreamWriter(monkeySocket.getOutputStream()));
+      monkeyReader = new BufferedReader(new InputStreamReader(monkeySocket.getInputStream()));
     } catch (UnknownHostException e) {
       e.printStackTrace();
     } catch(IOException e) {
       e.printStackTrace();
     }
   }
-
+  
   /** 
    * Close tcp session with the monkey on the device
    * 
@@ -189,47 +212,59 @@
   }
 
   /** 
-   * This is a house cleaning type routine to run before starting a script. Puts
-   * the device in a known state.
+   * This is a house cleaning routine to run before starting a script. Puts
+   * the device in a known state and starts recording interesting info.
    */
-  public static void start_script() {
-    press("menu");
-    press("menu");
-    press("home");
+  public static void start_script() throws IOException {
+    press("menu", false);
+    press("menu", false);
+    press("home", false);
+    
+    // Start recording the script output, might want md5 signature of file for completeness
+    monkeyRecorder = new MonkeyRecorder(scriptName);
+
+    // Record what device and version of software we are running on
+    monkeyRecorder.addAttribute("monkeyRunnerVersion", monkeyRunnerVersion);
+    addDeviceVars();
+    monkeyRecorder.addComment("Script commands");
   }
 
-  public static void end_script() {
-    String command = "END";
-    sendMonkeyEvent(command);
+  /** 
+   * This is a house cleaning routine to run after finishing a script.
+   * Puts the monkey server in a known state and closes the recording.
+   */
+  public static void end_script() throws IOException {
+    String command = "done";
+    sendMonkeyEvent(command, false, false);
+    
+    // Stop the recording and zip up the results
+    monkeyRecorder.close();
   }
 
   /** This is a method for scripts to launch an activity on the device
    * 
    * @param name The name of the activity to launch 
    */
-  public static void launch_activity(String name) {
-    try {
-      System.out.println("Launching: " + name);
-      monkeyDevice.executeShellCommand("am start -a android.intent.action.MAIN -n " 
-          + name, new NullOutputReceiver());
-    } catch (Exception e) {
-      e.printStackTrace();
-    }
-  }
+  public static void launch_activity(String name) throws IOException {
+    System.out.println("Launching: " + name);
+    recordCommand("Launching: " + name);
+    monkeyDevice.executeShellCommand("am start -a android.intent.action.MAIN -n " 
+        + name, new NullOutputReceiver());
+    // void return, so no response given, just close the command element in the xml file.
+    monkeyRecorder.endCommand();
+   }
 
   /**
    * Grabs the current state of the screen stores it as a png
    * 
    * @param tag filename or tag descriptor of the screenshot
    */
-  public static void grabscreen(String tag) {
+  public static void grabscreen(String tag) throws IOException {
     tag += ".png";
 
     try {
       Thread.sleep(1000);
       getDeviceImage(monkeyDevice, tag, false);
-    } catch (IOException e) {
-      e.printStackTrace();
     } catch (InterruptedException e) {
     }
   }
@@ -239,9 +274,11 @@
    * 
    * @param msec msecs to sleep for
    */
-  public static void sleep(int msec) {
+  public static void sleep(int msec) throws IOException {
     try {
+      recordCommand("sleep: " + msec);
       Thread.sleep(msec);
+      recordResponse("OK");
     } catch (InterruptedException e) {
       e.printStackTrace();
     }
@@ -253,12 +290,14 @@
    * @param x x-coordinate
    * @param y y-coordinate
    */
-  public static boolean tap(int x, int y) {
-    String command = "touch down " + x + "  " + y + "\r\n" +
-    "touch up " + x + " " + y + "\r\n";
+  public static boolean tap(int x, int y) throws IOException {
+    String command = "touch down " + x + "  " + y + "\r\n" + "touch up " + x + " " + y + "\r\n";
 
+    recordCommand("Tapping: " + x + ", " + y);
     System.out.println("Tapping: " + x + ", " + y);
-    return sendMonkeyEvent(command);
+    boolean result = sendMonkeyEvent(command, true, false);
+    recordResponse(monkeyResponse);
+    return result;
   }
 
   /** 
@@ -266,25 +305,38 @@
    * 
    * @param key key to press
    */
-  public static boolean press(String key) {
-    String command = "key down " + key + "\r\n" +
-    "key up " + key + "\r\n";
+  public static boolean press(String key) throws IOException {
+    return press(key, true);
+  }
 
-    System.out.println("Pressing: " + key);
-    return sendMonkeyEvent(command);
+  /** 
+   * Press function for scripts to call on a particular button or key
+   * 
+   * @param key key to press
+   * @param print whether to send output to user
+   */
+  private static boolean press(String key, boolean print) throws IOException {
+    String command = "key down " + key + "\r\n" + "key up " + key + "\r\n";
+
+    recordCommand("Pressing: " + key);
+    if (print)
+      System.out.println("Pressing: " + key);
+    boolean result = sendMonkeyEvent(command, print, false);
+    recordResponse(monkeyResponse);
+    return result;
   }
 
   /**
    * dpad down function
    */
-  public static boolean down() {
+  public static boolean down() throws IOException {
     return press("dpad_down");
   }
 
   /**
    * dpad up function
    */
-  public static boolean up() {
+  public static boolean up() throws IOException {
     return press("dpad_up");
   }
 
@@ -293,8 +345,10 @@
    * 
    * @param text text to type
    */
-  public static boolean type(String text) {
+  public static boolean type(String text) throws IOException {
     System.out.println("Typing: " + text);
+    recordCommand("Typing: " + text);
+    
     for (int i=0; i<text.length(); i++) {
       String command = "key down ";
       char c = text.charAt(i);
@@ -304,8 +358,9 @@
         command = "key down " + c + "\n" + "key up " + c + "\n";
       }
 
-      if(!sendMonkeyEvent(command)) {
+      if(!sendMonkeyEvent(command, false, false)) {
         System.out.println("\nERROR: Key not set \n");
+        recordResponse("ERROR: Key not set");
       }
 
       // lets delay a bit after each input to ensure accuracy
@@ -314,48 +369,168 @@
       } catch (InterruptedException e) {
       }
     }
+    System.out.println("MonkeyServer: OK");
+    recordResponse("OK");
 
     return true;
   }
+  
+  /**
+   * Function to get a static variable from the device
+   * 
+   * @param name name of static variable to get
+   */
+  public static boolean getvar(String name) throws IOException {
+    System.out.println("Getting var: " + name);
+    return sendMonkeyEvent("getvar " + name + "\n");
+  }
+
+  /**
+   * Function to get the list of static variables from the device
+   */
+  public static boolean listvar() throws IOException {
+    System.out.println("List of vars:");
+    return sendMonkeyEvent("listvar \n");
+  }
 
   /**
    * This function is the communication bridge between the host and the device.
    * It sends monkey events and waits for responses over the adb tcp socket.
+   * This version if for all scripted events so that they get recorded and reported to user.
    * 
    * @param command the monkey command to send to the device
    */
-  private static boolean sendMonkeyEvent(String command) {
-    try {
-      monkeyWriter = new BufferedWriter(
-          new OutputStreamWriter(monkeySocket.getOutputStream()));
-      monkeyWriter.write(command);
-      monkeyWriter.flush();
-
-      monkeyReader = new BufferedReader(
-          new InputStreamReader(monkeySocket.getInputStream()));
-      String response = monkeyReader.readLine();
-
-      sleep(1000);
-      System.out.println("MonkeyServer: " + response);
-      if(response.equals("OK"))
-        return true;
-      if(response.equals("ERROR"))
-        return false;
-
-    } catch (IOException e) {
-      e.printStackTrace();
-    }
-
-    return false;
+  private static boolean sendMonkeyEvent(String command) throws IOException {
+    return sendMonkeyEvent(command, true, true);
   }
 
+  /**
+   * This function allows the communication bridge between the host and the device
+   * to be invisible to the script for internal needs.
+   * It splits a command into monkey events and waits for responses for each over an adb tcp socket.
+   * Returns on an error, else continues and sets up last response.
+   * 
+   * @param command the monkey command to send to the device
+   * @param print whether to print out the responses to the user
+   * @param record whether to put the command in the xml file that stores test outputs
+   */
+  private static boolean sendMonkeyEvent(String command, Boolean print, Boolean record) throws IOException {
+    // split a command string into line driven protocol monkey understands
+    String[] commands = command.trim().split("[\r\n|\r|\n]+");
+    for (String subcommand: commands) {
+      if (record)
+        recordCommand(subcommand);
+      logger.info("Monkey Command: " + subcommand + ".");
+      
+      // send a single command and get the response
+      monkeyWriter.write(subcommand + "\n");
+      monkeyWriter.flush();      
+      monkeyResponse = monkeyReader.readLine();
 
+      logger.info("Monkey Response: " + monkeyResponse + ".");      
+      if (record)
+        recordResponse(monkeyResponse);
+      
+      // if a command returns an error, abandon further commands and return
+      if((monkeyResponse != null) && monkeyResponse.equals("ERROR")) {
+        if (print)
+          System.out.println("MonkeyServer: " + monkeyResponse);
+        return false;
+      }
+    }
+    if (monkeyResponse != null) {
+      // all responses were not ERROR
+      if(monkeyResponse.startsWith("OK"))
+        if (print)
+          System.out.println("MonkeyServer: " + monkeyResponse);
+        return true;
+    } else {
+      // didn't get a final response...
+      if (print)
+        System.out.println("MonkeyServer: ??no response");
+      return false;
+    }
+  }
+
+  /**
+   * Record the command in the xml file
+   *
+   * @param command the command sent to the monkey server
+   */
+  private static void recordCommand(String command) throws IOException {
+    if (monkeyRecorder != null) {                       // don't record setup junk
+      monkeyRecorder.startCommand();
+      String[] commands = command.split("[\\r\\n]+");   // for formatting, text might have line ends
+      for (String subcommand: commands) {
+        monkeyRecorder.addInput(subcommand);
+      }
+    }
+  }
+  
+  /**
+   * Record the response in the xml file
+   *
+   * @param response the response sent by the monkey server
+   */
+  private static void recordResponse(String response) throws IOException {
+    recordResponse(response, "");
+  } 
+  
+  /**
+   * Record the response and the filename in the xml file, store the file (to be zipped up later)
+   *
+   * @param response the response sent by the monkey server
+   * @param filename the filename of a file to be time stamped, recorded in the xml file and stored
+   */
+  private static void recordResponse(String response, String filename) throws IOException {
+    if (monkeyRecorder != null) {                    // don't record setup junk
+      monkeyRecorder.addResult(response, filename);  // ignores file if filename empty
+      monkeyRecorder.endCommand();
+    }
+  }
+    
+  /**
+   * Add the device variables to the xml file in monkeyRecorder.
+   * The results get added as attributes to the script_run tag
+   */
+  private static void addDeviceVars() throws IOException {
+    monkeyRecorder.addComment("Device specific variables");
+    sendMonkeyEvent("listvar \n", false, false);
+    if (monkeyResponse.startsWith("OK:")) {
+      // peel off "OK:" string and get the individual var names  
+      String[] varNames = monkeyResponse.substring(3).split("\\s+");
+      // grab all the individual var values
+      for (String name: varNames) {
+        sendMonkeyEvent("getvar " + name, false, false);
+        if(monkeyResponse != null) {
+          if (monkeyResponse.startsWith("OK") ) {
+            if (monkeyResponse.length() > 2) {
+              monkeyRecorder.addDeviceVar(name, monkeyResponse.substring(3));
+            } else { 
+              // only got OK - good variable but no value
+              monkeyRecorder.addDeviceVar(name, "null");
+            }
+          } else { 
+            // error returned - couldn't get var value for name... include error return
+            monkeyRecorder.addDeviceVar(name, monkeyResponse);
+          }
+        } else { 
+          // no monkeyResponse - bad variable with no value
+          monkeyRecorder.addDeviceVar(name, "null");
+        }
+      }
+    } else {
+      // it's an error, can't find variable names...
+      monkeyRecorder.addAttribute("listvar", monkeyResponse);
+    }
+  }
+  
   /**
    * Process the command-line options
    *
    * @return Returns true if options were parsed with no apparent errors.
    */
-  public static void processOptions(String[] args) {
+  private static void processOptions(String[] args) {
     // parse command line parameters.
     int index = 0;
 
@@ -364,7 +539,7 @@
 
       if ("-s".equals(argument)) {
         if(index == args.length) {
-          printAndExit("Missing Server after -s", false);
+          printUsageAndQuit("Missing Server after -s");
         }
 
         monkeyServer = args[index++];
@@ -372,18 +547,32 @@
       } else if ("-p".equals(argument)) {
         // quick check on the next argument.
         if (index == args.length) {
-          printAndExit("Missing Server IP after -p", false /* terminate */);
+          printUsageAndQuit("Missing Server port after -p");
         }
 
         monkeyPort = Integer.parseInt(args[index++]);
-      } else {
-        // get the filepath of the script to run.
-        scriptName = argument;
 
-        // should not be any other device.
-        //if (index < args.length) {
-        //    printAndExit("Too many arguments!", false /* terminate */);
-        //}
+      } else if ("-v".equals(argument)) {
+        // quick check on the next argument.
+        if (index == args.length) {
+          printUsageAndQuit("Missing Log Level after -v");
+        }
+
+        Level level = Level.parse(args[index++]);
+        logger.setLevel(level);
+        level = logger.getLevel();
+        System.out.println("Log level set to: " + level + "(" + level.intValue() + ").");
+        System.out.println("Warning: Log levels below INFO(800) not working currently... parent issues");
+        
+      } else if (argument.startsWith("-")) {
+        // we have an unrecognized argument.
+        printUsageAndQuit("Unrecognized argument: " + argument + ".");
+
+        monkeyPort = Integer.parseInt(args[index++]);
+
+      } else {
+        // get the filepath of the script to run.  This will be the last undashed argument.
+        scriptName = argument;
       }
     } while (index < args.length);
   }
@@ -394,22 +583,29 @@
   private static void getDeviceImage(IDevice device, String filepath, boolean landscape)
   throws IOException {
     RawImage rawImage;
+    recordCommand("grabscreen");
+    System.out.println("Grabbing Screeshot: " + filepath + ".");
 
     try {
       rawImage = device.getScreenshot();
     }
     catch (IOException ioe) {
+      recordResponse("No frame buffer", "");
       printAndExit("Unable to get frame buffer: " + ioe.getMessage(), true /* terminate */);
       return;
     }
 
     // device/adb not available?
-    if (rawImage == null)
+    if (rawImage == null) {
+      recordResponse("No image", "");
       return;
-
+    }
+    
     assert rawImage.bpp == 16;
 
     BufferedImage image;
+    
+    logger.info("Raw Image - height: " + rawImage.height + ", width: " + rawImage.width);
 
     if (landscape) {
       // convert raw data to an Image
@@ -458,16 +654,20 @@
     }
 
     if (!ImageIO.write(image, "png", new File(filepath))) {
+      recordResponse("No png writer", "");
       throw new IOException("Failed to find png writer");
     }
+    recordResponse("OK", filepath);
   }
 
-  private static void printUsageAndQuit() {
+  private static void printUsageAndQuit(String message) {
     // 80 cols marker:  01234567890123456789012345678901234567890123456789012345678901234567890123456789
+    System.out.println(message);
     System.out.println("Usage: monkeyrunner [options] SCRIPT_FILE");
     System.out.println("");
     System.out.println("    -s      MonkeyServer IP Address.");
     System.out.println("    -p      MonkeyServer TCP Port.");
+    System.out.println("    -v      MonkeyServer Logging level (ALL, FINEST, FINER, FINE, CONFIG, INFO, WARNING, SEVERE, OFF)");
     System.out.println("");
     System.out.println("");