喜欢是淡淡的爱,爱是深深的喜欢!!

发布新日志

  • MonkeyRunner.java

    2012-03-19 15:05:42

    路径:android-2.2-froyo/com/android/monkeyrunner/MonkeyRunner.java

    /**
     * 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 com.android.ddmlib.AndroidDebugBridge;
    import com.android.ddmlib.IDevice;
    import com.android.ddmlib.Log;
    import com.android.ddmlib.NullOutputReceiver;
    import com.android.ddmlib.RawImage;
    import com.android.ddmlib.Log.ILogOutput;
    import com.android.ddmlib.Log.LogLevel;
    
    import java.awt.image.BufferedImage;
    
    import java.io.BufferedReader;
    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. 
     */
    public class MonkeyRunner {
    
      static String monkeyServer = "127.0.0.1";
      static int monkeyPort = 1080;
      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");
    
      // delay between key events
      final static int KEY_INPUT_DELAY = 1000;
      
      // version of monkey runner
      final static String monkeyRunnerVersion = "0.4";
    
      // TODO: interface cmd; class xml tags; fix logger; test class/script.
      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();  
      }
    
      /***
       *  Initialize an adb session with a device connected to the host
       * 
       */
      public static void initAdbConnection() {
        String adbLocation = "adb";
        boolean device = false;
        boolean emulator = false;
        String serial = null;
    
        AndroidDebugBridge.init(false /** debugger support */);
    
        try {
          AndroidDebugBridge bridge = AndroidDebugBridge.createBridge(
              adbLocation, true /** forceNewBridge */);
    
          // we can't just ask for the device list right away, as the internal thread getting
          // them from ADB may not be done getting the first list.
          // Since we don't really want getDevices() to be blocking, we wait here manually.
          int count = 0;
          while (bridge.hasInitialDeviceList() == false) {
            try {
              Thread.sleep(100);
              count++;
            } catch (InterruptedException e) {
              // pass
            }
    
            // let's not wait > 10 sec.
            if (count > 100) {
              System.err.println("Timeout getting device list!");
              return;
            }
          }
    
          // now get the devices
          IDevice[] devices = bridge.getDevices();
    
          if (devices.length == 0) {
            printAndExit("No devices found!", true /** terminate */);
          }
    
          monkeyDevice = null;
    
          if (emulator || device) {
            for (IDevice d : devices) {
              // this test works because emulator and device can't both be true at the same
              // time.
              if (d.isEmulator() == emulator) {
                // if we already found a valid target, we print an error and return.
                if (monkeyDevice != null) {
                  if (emulator) {
                    printAndExit("Error: more than one emulator launched!",
                        true /** terminate */);
                  } else {
                    printAndExit("Error: more than one device connected!",true /** terminate */);
                  }
                }
                monkeyDevice = d;
              }
            }
          } else if (serial != null) {
            for (IDevice d : devices) {
              if (serial.equals(d.getSerialNumber())) {
                monkeyDevice = d;
                break;
              }
            }
          } else {
            if (devices.length > 1) {
              printAndExit("Error: more than one emulator or device available!",
                  true /** terminate */);
            }
            monkeyDevice = devices[0];
          }
    
          monkeyDevice.createForward(monkeyPort, monkeyPort);
          String command = "monkey --port " + monkeyPort;
          monkeyDevice.executeShellCommand(command, new NullOutputReceiver());
    
        } catch(IOException e) {
          e.printStackTrace();
        }
      }
    
      /***
       * Open a tcp session over adb with the device to communicate monkey commands
       */
      public static void openMonkeyConnection() {
        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
       * 
       */
      public static void closeMonkeyConnection() {
        try {
          monkeyReader.close();
          monkeyWriter.close();
          monkeySocket.close();
          AndroidDebugBridge.terminate();
        } catch(IOException e) {
          e.printStackTrace();
        }
      }
    
      /*** 
       * 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() 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, monkeyRunnerVersion);
    
        // Record what device we are running on
        addDeviceVars();
        monkeyRecorder.addComment("Script. commands");
      }
    
      /*** 
       * 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) 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) throws IOException {
        tag += ".png";
    
        try {
          Thread.sleep(1000);
          getDeviceImage(monkeyDevice, tag, false);
        } catch (InterruptedException e) {
        }
      }
    
      /***
       * Sleeper method for script. to call
       * 
       * @param msec msecs to sleep for
       */
      public static void sleep(int msec) throws IOException {
        try {
          recordCommand("sleep: " + msec);
          Thread.sleep(msec);
          recordResponse("OK");
        } catch (InterruptedException e) {
          e.printStackTrace();
        }
      }
    
      /***
       * Tap function for scripts to call at a particular x and y location
       * 
       * @param x x-coordinate
       * @param y y-coordinate
       */
      public static boolean tap(int x, int y) throws IOException {
        String command = "tap " + x + " " + y;
        boolean result = sendMonkeyEvent(command);
        return result;
      }
    
      /*** 
       * Press function for scripts to call on a particular button or key
       * 
       * @param key key to press
       */
      public static boolean press(String key) throws IOException {
        return press(key, true);
      }
    
      /*** 
       * 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 = "press " + key;
        boolean result = sendMonkeyEvent(command, print, true);
        return result;
      }
    
      /***
       * dpad down function
       */
      public static boolean down() throws IOException {
        return press("dpad_down");
      }
    
      /***
       * dpad up function
       */
      public static boolean up() throws IOException {
        return press("dpad_up");
      }
    
      /***
       * Function to type text on the device
       * 
       * @param text text to type
       */
      public static boolean type(String text) throws IOException {
        boolean result = false;
        // text might have line ends, which signal new monkey command, so we have to eat and reissue
        String[] lines = text.split("[\\r\\n]+");
        for (String line: lines) {
          result = sendMonkeyEvent("type " + line + "\n");
        }
        // return last result.  Should never fail..?
        return result;
      }
      
      /***
       * 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 {
        return sendMonkeyEvent("getvar " + name + "\n");
      }
    
      /***
       * Function to get the list of static variables from the device
       */
      public static boolean listvar() throws IOException {
        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) 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 {
        command = command.trim();
        if (print)
          System.out.println("MonkeyCommand: " + command);
        if (record)
          recordCommand(command);
        logger.info("Monkey Command: " + command + ".");
          
        // send a single command and get the response
        monkeyWriter.write(command + "\n");
        monkeyWriter.flush();
        monkeyResponse = monkeyReader.readLine();
    
        if(monkeyResponse != null) {
          // if a command returns with a response
          if (print)
            System.out.println("MonkeyServer: " + monkeyResponse);
          if (record)
            recordResponse(monkeyResponse);
          logger.info("Monkey Response: " + monkeyResponse + ".");
    
          // return on error
          if (monkeyResponse.startsWith("ERROR"))
            return false;
    
          // return on ok
          if(monkeyResponse.startsWith("OK"))
            return true;
    
          // return on something else?
          return false;
        }
        // didn't get a response...
        if (print)
          System.out.println("MonkeyServer: ??no response");
        if (record)
          recordResponse("??no response");
        logger.info("Monkey Response: ??no response.");
    
        //return on 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();
          monkeyRecorder.addInput(command);
        }
      }
      
      /***
       * 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 device_var tags in 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.
       */
      private static void processOptions(String[] args) {
        // parse command line parameters.
        int index = 0;
    
        do {
          String argument = args[index++];
    
          if ("-s".equals(argument)) {
            if(index == args.length) {
              printUsageAndQuit("Missing Server after -s");
            }
    
            monkeyServer = args[index++];
    
          } else if ("-p".equals(argument)) {
            // quick check on the next argument.
            if (index == args.length) {
              printUsageAndQuit("Missing Server port after -p");
            }
    
            monkeyPort = Integer.parseInt(args[index++]);
    
          } 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);
      }
    
      /**
       * Grab an image from an ADB-connected device.
       */
      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) {
          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
          image = new BufferedImage(rawImage.height, rawImage.width,
              BufferedImage.TYPE_INT_ARGB);
    
          byte[] buffer = rawImage.data;
          int index = 0;
          for (int y = 0 ; y < rawImage.height ; y++) {
            for (int x = 0 ; x < rawImage.width ; x++) {
    
              int value = buffer[index++] & 0x00FF;
              value |= (buffer[index++] << 8) & 0x0FF00;
    
              int r = ((value >> 11) & 0x01F) << 3;
              int g = ((value >> 5) & 0x03F) << 2;
              int b = ((value >> 0) & 0x01F) << 3;
    
              value = 0xFF << 24 | r << 16 | g << 8 | b;
    
              image.setRGB(y, rawImage.width - x - 1, value);
            }
          }
        } else {
          // convert raw data to an Image
          image = new BufferedImage(rawImage.width, rawImage.height,
              BufferedImage.TYPE_INT_ARGB);
    
          byte[] buffer = rawImage.data;
          int index = 0;
          for (int y = 0 ; y < rawImage.height ; y++) {
            for (int x = 0 ; x < rawImage.width ; x++) {
    
              int value = buffer[index++] & 0x00FF;
              value |= (buffer[index++] << 8) & 0x0FF00;
    
              int r = ((value >> 11) & 0x01F) << 3;
              int g = ((value >> 5) & 0x03F) << 2;
              int b = ((value >> 0) & 0x01F) << 3;
    
              value = 0xFF << 24 | r << 16 | g << 8 | b;
    
              image.setRGB(x, y, value);
            }
          }
        }
    
        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(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("");
    
        System.exit(1);
      }
    
      private static void printAndExit(String message, boolean terminate) {
        System.out.println(message);
        if (terminate) {
          AndroidDebugBridge.terminate();
        }
        System.exit(1);
      }
    }

  • ScriptRunner.java

    2012-03-19 15:05:42

    路径:android-2.2-froyo/com/android/monkeyrunner/ScriptRunner.java

    package com.android.monkeyrunner;
    
    import org.python.core.Py;
    import org.python.core.PyObject;
    import org.python.util.PythonInterpreter;
    import org.python.util.InteractiveConsole;
    
    import java.io.File;
    import java.io.IOException;
    import java.io.FileInputStream;
    import java.lang.RuntimeException;
    import java.util.Properties;
    
    
    /***
     * Runs Jython based scripts.
     */
    public class ScriptRunner {
    
      /*** The "this" scope object for scripts. */
      private final Object scope;
      private final String variable;
      
      /*** Private constructor. */
      private ScriptRunner(Object scope, String variable) {
        this.scope = scope;
        this.variable = variable;
      }
      
      /*** Creates a new instance for the given scope object. */
      public static ScriptRunner newInstance(Object scope, String variable) {
        return new ScriptRunner(scope, variable);
      }
    
      /***
       * Runs the specified Jython script. First runs the initialization script. to
       * preload the appropriate client library version.
       */
      public static void run(String scriptfilename) {
        try {
          initPython();
          PythonInterpreter python = new PythonInterpreter();
          
          python.execfile(scriptfilename);
        } catch(Exception e) {
          e.printStackTrace();
        }
      }
      
    
      /*** Initialize the python interpreter. */
      private static void initPython() {
        Properties props = new Properties();
        // Default is 'message' which displays sys-package-mgr bloat
        // Choose one of error,warning,message,comment,debug
        props.setProperty("python.verbose", "error");
        props.setProperty("python.path", System.getProperty("java.class.path"));
        PythonInterpreter.initialize(System.getProperties(), props, new String[] {""});
      }
    
      /***
       * Create and run a console using a new python interpreter for the test
       * associated with this instance.
       */
      public void console() throws IOException {
        initPython();
        InteractiveConsole python = new InteractiveConsole();
        initInterpreter(python, scope, variable);
        python.interact();
      }
    
      /***
       * Start an interactive python interpreter using the specified set of local
       * variables. Use this to interrupt a running test script. with a prompt:
       * 
       * @param locals
       */
      public static void console(PyObject locals) {
        initPython();
        InteractiveConsole python = new InteractiveConsole(locals);
        python.interact();
      }
    
      /***
       * Initialize a python interpreter.
       * 
       * @param python
       * @param scope
       * @throws IOException
       */
      public static void initInterpreter(PythonInterpreter python, Object scope, String variable) 
          throws IOException {
        // Store the current test case as the this variable
        python.set(variable, scope);
      }
    }
  • MonkeyRecorder.java源码

    2012-03-19 15:01:48

    路径:android-2.2-froyo/com/android/monkeyrunner/MonkeyRecorder.java

    /**
     * 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.List;
    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 like:
     *
     *  <?xml version="1.0" encoding='UTF-8'?>
     *  <!-- Monkey Script. Results -->
     *  <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 List<String> mScreenShotNames = 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, String version) 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, version);
      }
    
      // 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
       * @param version of the monkey runner test system
       */
      private static void initXmlFile(String scriptName, String version) throws IOException {
        String[] names = new String[] { "script_name", "monkeyRunnerVersion" };
        String[] values = new String[] { scriptName, version };
        mXmlFile = new FileWriter(mDirname + "/" + mXmlFilename);
        mXmlWriter = new XMLWriter(mXmlFile);
        mXmlWriter.begin();
        mXmlWriter.comment("Monkey Script. Results");
        mXmlWriter.start("script_run", names, values, names.length);
      }
      
      /***
       * 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", "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 open 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));
        mScreenShotNames.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);
      }
    
      /***
       * 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 ut = new ZipOutputStream(zipFile);
    
        // add the xml file
        addFileToZip(out, mDirname + "/" + mXmlFilename, buf);
        
        // Add the screenshots
        for (String filename : mScreenShotNames) {
          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();
      }
    }
  • monkeyrunner脚本生成器

    2012-01-11 10:02:54

    monkeyrunner脚本生成器

  • monkeyrunner测试apk包安装卸载

    2011-04-21 18:54:51

    from com.android.monkeyrunner import MonkeyRunner, MonkeyDevice, MonkeyImage
    device = MonkeyRunner.waitForConnection()
    #device.removePackage ('ApiDemos.apk')
    device.removePackage ('com.example.android.notepad')
    print ('卸载成功')
    MonkeyRunner.sleep(15)
    device.installPackage('ApiDemos.apk')
    print ('安装成功')
  • 了解monkey命令行的一些参数

    2011-04-21 18:47:34

     

    1.-p:所在测试的包,可以是一个也可以是多个(如:monkey -p com.androd.a -p com.androd.b)

    2.-c:如果用此参数指定了一个或几个类别,Monkey将只允许系统启动被这些类别中的某个类别列出的Activity。如果不指定任何类别,Monkey将选择下列类别中列出的Activity: Intent.CATEGORY_LAUNCHER或Intent.CATEGORY_MONKEY。要指定多个类别,需要使用多个-c选项,每个-c选项只能用于一个类别.

    3.-ignore-crash:当应用程序崩溃或发生任何失控异常时,Monkey将停止运行。如果设置此选项,Monkey将继续向系统发送事件,直到计数完成.

    4.-ignore-timeouts:通常,当应用程序发生任何超时错误(如“Application Not Responding”对话框)时,Monkey将停止运行。如果设置此选项,Monkey将继续向系统发送事件,直到计数完成.

    5.-ignore-security-exceptions:通常,当应用程序发生许可错误(如启动一个需要某些许可的Activity)时,Monkey将停止运行。如果设置了此选项,Monkey将继续向系统发送事件,直到计数完成

    6.-monitor-native-crashes:监视并报告Android系统中本地代码的崩溃事件。如果设置了–kill-process-after-error,系统将停止运行

    7.-kill-process-after-error:如果程序出现错误,monkey将结束此程序进程

    8.-hprof:设置此项,将在monkey事件序列之前和之后立即生成profilling报告。这将会在data/misc中生成大文件(约5mb)所以要小心使用它

    9.-pct-touch:调整触摸事件的百分比(触摸事件是一个down-up事件,它发生在屏幕的某单一位置)

    10.-pct-motion:动作事件的百分比(动作事件由屏幕上某处的一个down事件、一系列的随机事件和一个up事件组成)

    11.-pct-trackball:调整轨迹事件的百分比(轨迹事件由一个或几个随机移动组成,有时还伴随着点击)

    12.-pct-syskeys:调整系统按键事件的百分比(这些按键通常被保留,由系统使用,如home,back,start call,end call及音量控制)

    13.-pct-nav 调整基本导航事件的百分比(导航事件来自方向输入设备的up/down/left/right组成)

    14.-pct-majornav:调整“主要”导航事件的百分比(这些导航事件通常引发图形界面中的动作,如:5-way键盘的中间按键、回退按键、菜单按键)

    15.-pct-appswitch:调整启动Activity的百分比。在随机间隔里,Monkey将执行一个startActivity()调用,作为最大程度覆盖包中全部Activity的一种方法

    16.-pct-anyevent:调整启动Activity的百分比。它包罗了所有其它的事件类型,如:按键,其它不常用的设备按钮

    17.–wait-dbg:停止执行中的Monkey,直到有调试器和它相连接

    18.–dbg-no-events:设置此选项,Monkey将执行初始启动,进入到一个测试Activity,然后不会再进一步生成事件。为了得到最佳结果,把它与-v、一个或几个包约束、以及一个保持Monkey运行30秒或更长时间的非零值联合起来,从而提供一个环境,可以监视应用程序所调用的包之间的转换

    19.-port:为monkey开启专用端口。此时只monkey不会帮你乱点击,而此时你自己就是一只monkey了,在你乱点的时候,monkey会输出你点击后回馈的信息。如果你打完命令之后模拟器上没有启动你所要启动的包,你需要自己启动,但是你只能启动你-p中指定的那几个包。ctrl+c中断

    20.--throttle :当事件起效时等待的毫秒数

    21.-s:随机数生成器的seed值。如果用相同的seed值再次运行monkey,它将生成相同的事件序列

    22.COUNT:要发送的事件数

     

  • android的monkey测试小结

    2011-04-21 17:39:29

    Monkey测试是Android自动化测试的一种手段,Monkey测试本身非常简单,就是模拟用户的按键输入,触摸屏输入,手势输入等,看设备多长时间会出异常。

    Monkey程序在模拟器或设备运行的时候,如果用户出发了比如点击,触摸,手势或一些系统级别的事件的时候,它就会产生随机脉冲,所以可以用Monkey用随机重复的方法去做相关的性能测试。

    命令:$ adb shell monkey -v -p your.package.name 500

    例如:monkey -v -p com.android.camera --throttle 5000 --pct-anyevent 100 500

    -v显示默认程度的信息

    -p com.android.camera是指定测试的程序(这是开始测试的camera的内容

    --throttle 5000 设定延时

    --pct-anyevent 100(设定启动activity的百分比为100%

    500设定的事件数

    (具体可以看monkey的命令帮助)

    以下是个例子: monkey -p com.example.android.notepad -v -v -v 10

    运行结果相关解释如下:

    各种事件所占的比例

    // Event percentages:
    //   0: 15.0%
    //   1: 10.0%
    //   2: 15.0%
    //   3: 25.0%
    //   4: 15.0%
    //   5: 2.0%
    //   6: 2.0%
    //   7: 1.0%
    //   8: 15.0%

    表示跳转到com.example.android.notepad里面的NotesList这一个Activity

    :Switch: #Intent;action=android.intent.action.MAIN;category=android.intent.categ
    ory.LAUNCHER;launchFlags=0x10000000;component=com.example.android.notepad/.Notes
    List;end

    允许此Intent跳转

    Allowing start of Intent { act=android.intent.action.MAIN cat=[android.in
    tent.category.LAUNCHER] cmp=com.example.android.notepad/.NotesList } in package
    com.example.android.notepad

    发送的一些动作:

    Sleeping for 0 milliseconds
    :SendKey (ACTION_DOWN): 21    // KEYCODE_DPAD_LEFT
    :SendKey (ACTION_UP): 21    // KEYCODE_DPAD_LEFT
    Sleeping for 0 milliseconds
    :Sending Pointer ACTION_MOVE x=-4.0 y=2.0
    :Sending Pointer ACTION_MOVE x=-5.0 y=-4.0
    :Sending Pointer ACTION_MOVE x=0.0 y=-1.0
    :Sending Pointer ACTION_MOVE x=-3.0 y=2.0
    :Sending Pointer ACTION_MOVE x=-4.0 y=2.0
    :Sending Pointer ACTION_MOVE x=-2.0 y=4.0
    :Sending Pointer ACTION_MOVE x=4.0 y=1.0
    Events injected: 10

    丢弃的,键=0,指针=0,轨迹球=0,翻转=0

    :Dropped: keys=0 pointers=0 trackballs=0 flips=0

    网络统计经过时间为7249ms,其中7249ms是用于在手机上的,0ms用于无线网络上,没有连接的时间为0ms

    ## Network stats: elapsed time=7249ms (7249ms mobile, 0ms wifi, 0ms not connecte
    d)

    结束// Monkey finished

Open Toolbar