shell/ batch scripting to direct commands to adb shell

I am trying to write a batch(for win) and a shell script for linux to automate key and touch events on a android UI. At the moment in a windows batch file I am starting a adb shell for each event for eg

    :again

adb shell am start -a android.intent.action.MAIN -n com.q.me.fui.activity/.InitActivity

sleep 15

adb shell sendevent /dev/input/event0 3 0 281
adb shell sendevent /dev/input/event0 3 1 70
adb shell sendevent /dev/input/event0 1 330 1
adb shell sendevent /dev/input/event0 0 0 0
adb shell sendevent /dev/input/event0 1 330 0
adb shell sendevent /dev/input/event0 0 0 0   
adb shell sendevent /dev/input/event0 1 330 1
adb shell sendevent /dev/input/event0 0 0 0
adb shell sendevent /dev/input/event0 1 330 0
adb shell sendevent /dev/input/event0 0 0 0
adb shell sendevent /dev/input/event0 0 0 0
adb shell sendevent /dev/input/event0 0 0 0   

sleep 5

adb shell input keyevent 82
adb shell input keyevent 20
adb shell input keyevent 20
adb shell input keyevent 22
adb shell input keyevent 22
adb shell input keyevent 22
adb shell input keyevent 66

sleep 5

goto again

The above code is infact starting a new adb shell each time. I want to avoid this. I want my batch script to start the adb shell only once and I would like to route the sendevent and other commands to the subshell, ie the adb shell.

Any idea how I can do this in win batch and Lin shell script?


Solution 1:

Put all the commands you want to run at once in an external file, one per line, then run:

adb shell < commands.txt

Solution 2:

I don't know much about batch scripting or shell scripting, but I was able to quickly write a java program to do this:

import java.io.InputStream;
import java.io.OutputStream;
import java.io.IOException;

public class AndroidShell  {
   private ProcessBuilder builder;
   private Process adb;
   private static final byte[] LS = "\n".getBytes();

   private OutputStream processInput;
   private InputStream processOutput;

   private Thread t;

   /**
    * Starts the shell 
    */
   public void start() throws IOException  {
      builder = new ProcessBuilder("adb", "shell");
      adb = builder.start();

      // reads from the process output
      processInput = adb.getOutputStream();

      // sends to process's input
      processOutput = adb.getInputStream();

      // thread that reads process's output and prints it to system.out
      Thread t = new Thread() {
         public void run() {
            try   {
               int c = 0;
               byte[] buffer = new byte[2048];
               while((c = processOutput.read(buffer)) != -1) {
                     System.out.write(buffer, 0, c);
               }
            }catch(Exception e)  {}
         }
      };
      t.start();
   }

   /**
    * Stop the shell;
    */
   public void stop()   {
      try   {
         if(processOutput != null && t != null) {
            this.execCommand("exit");
            processOutput.close();
         }
      }catch(Exception ignore)  {}
   }

   /**
    * Executes a command on the shell
    * @param adbCommand the command line.
    * e.g. "am start -a android.intent.action.MAIN -n com.q.me.fui.activity/.InitActivity" 
    */
   public void execCommand(String adbCommand) throws IOException {
      processInput.write(adbCommand.getBytes());
      processInput.write(LS);
      processInput.flush();
   }

   public static void main(String[] args) throws Exception  {
      AndroidShell shell = new AndroidShell();
      shell.start();

      for(String arg : args)  {
         if(arg.startsWith("sleep"))   {
            String sleep = arg.split(" ")[1].trim();
            long sleepTime = Integer.parseInt(sleep) * 1000;
            Thread.sleep(sleepTime);
         }else {
            shell.execCommand(arg);
         }
      }

      shell.stop();
   }
}

You can then use this class in a shell script as you like passing the commands to execute as command line arguments in your main method.

e.g. Below is the shell script:

#!/bin/bash

java AndroidShell "am start -a android.intent.action.MAIN -n com.q.me.fui.activity/.InitActivity" \
"sleep 15" \
"sendevent /dev/input/event0 3 0 281" \
"sendevent /dev/input/event0 3 1 70" \
"sendevent /dev/input/event0 1 330 1" \
"sendevent /dev/input/event0 0 0 0" \
"sleep 10" \
"sendevent /dev/input/event0 1 330 0" \
"exit"

Solution 3:

Topher's answer is almost correct.

Just remove the newlines and it will work.

adb shell "sendevent /dev/input/event9 3 53 215;sendevent /dev/input/event9 3 54 68;sendevent /dev/input/event9 3 48 40;sendevent /dev/input/event9 3 50 6;sendevent /dev/input/event9 3 57 0;sendevent /dev/input/event9 0 2 0;sendevent /dev/input/event9 0 0 0;sendevent /dev/input/event9 3 53 215;sendevent /dev/input/event9 3 54 68;sendevent /dev/input/event9 3 48 0;sendevent /dev/input/event9 3 50 6;sendevent /dev/input/event9 3 57 0;sendevent /dev/input/event9 0 2 0;sendevent /dev/input/event9 0 0 0;"

The only thing you need to take care of is, that you do not feed in more than 25 (that's the amount I used, 30 doesn work anymore) sendevents, because else adb will throw the error, that there are too many arguments or so.

Solution 4:

I am doing something similar

(
   echo cd sdcard
   echo ls
) | adb shell

So it may work as below:

(
    echo am start -a android.intent.action.MAIN -n com.q.me.fui.activity/.InitActivity
    echo sleep 15
    echo sendevent /dev/input/event0 3 0 281
    echo sendevent /dev/input/event0 3 1 70
    echo sendevent /dev/input/event0 1 330 1
    echo sendevent /dev/input/event0 0 0 0
    echo sendevent /dev/input/event0 1 330 0
    echo sendevent /dev/input/event0 0 0 0   
    echo sendevent /dev/input/event0 1 330 1
    echo sendevent /dev/input/event0 0 0 0
    echo sendevent /dev/input/event0 1 330 0
    echo sendevent /dev/input/event0 0 0 0
    echo sendevent /dev/input/event0 0 0 0
    echo sendevent /dev/input/event0 0 0 0   
    echo sleep 5
    echo input keyevent 82
    echo input keyevent 20
    echo input keyevent 20
    echo input keyevent 22
    echo input keyevent 22
    echo input keyevent 22
    echo input keyevent 66
    echo sleep 5
) | adb shell