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