How to bind the standard output of a process to a TextView - android

I'm developping my first Android App. I need to execute a command in a shell as the root user so I've introduced this code in my App:
process = Runtime.getRuntime().exec("su");
Then I obtain an output stream to the process and I use it to execute the command:
os = new DataOutputStream(process.getOutputStream());
os.writeBytes("tcpdump\n");
Then I obtain an input stream which I want to use for displaying the results of the process:
is = new DataInputStream(process.getInputStream());
I would like to bind the obtained DataInputStream to a TextView in the layout so the text that it displays gets updated in real time as the process goes on showing results.
I've been searching trought the java.io API for android and I can't find an easy way to do this. I've been thinking in running a thread with a loop which continously checks if there is new data in the input stream and then copy it to the TextView but this seems a crappy solution.
I would thank you if anyone knows a way to do this.

Channel channel = session.openChannel("shell");
OutputStream os = new OutputStream() {
#Override
public void write(int oneByte) throws IOException {
TextView textView1 = (TextView) findViewById(R.id.textView1);
char ch = new Character((char) oneByte);
textView1.setText(textView1.getText() + String.valueOf(ch));
System.out.write(oneByte);
}
};
// channel.setOutputStream(System.out);
channel.setOutputStream(os, true);

Combine TextView.append method with Handler
Here is good example:
http://android-developers.blogspot.com/2007/11/stitch-in-time.html

I've been able to set a Handler and start a runnable which will read from the input stream every 200ms.
Despite this, it seems that the input stream isn't receiving any characters form the process standard output and everytime I call a read() method it gets blocked waiting for characters that never come. I've been trying following this two websites instructions without sucess:
http://gimite.net/en/index.php?Run%20native%20executable%20in%20Android%20App
http://code.google.com/p/market-enabler/wiki/ShellCommands
Thanks.

After one day of research and tests, I found that the only solution for this problem is using AsyncTask.
You can adapt this code, which is working fine: https://stackoverflow.com/a/9063257
It also works replacing ProcessBuilder() with Runtime.getRuntime() if you like it.

Related

Read logs from Logcat without killing the tablet

I have to read the logs from Logcat and send them to a server through UDP.
For this task I have used this code: https://github.com/chemik/logcatudp
The main problem of that code is that the async Thread that is launched enters a while(true) loop that drains the tablet's battery on the long run.
Is there a way to get the logs in real time but without using a busy wait like that? Hopefully without adding some sleep(some_milliseconds) to reduce the problem?
It would be great to use some sort of event listener but I haven't found one. I have searched in every similar library but without any success.
The code is the following:
while (true) {
String sendingLine = "";
// assume that log writes whole lines
if (bufferedReader.ready()) {
logLine = bufferedReader.readLine();
sendingLine += logLine + System.getProperty("line.separator");
DatagramPacket packet = new DatagramPacket(sendingLine.getBytes(), sendingLine.length(),
InetAddress.getByName(mConfig.mDestServer), mConfig.mDestPort);
try {
mSocket.send(packet);
...
Any idea? Thanks.
Finally the answer was to put a Thread.sleep(10) in the while(true) loop.
It may seem really strange, but also with only 10ms of sleep it reduces the battery usage from almost 40% to 1%.

Android - how to stop continuous terminal action (ping) programmaticaly?

I am working on a simple app but don't know how to stop continuous action in terminal such as PING programmatically.
I just want to know the command, then I'll add it to runtime.getruntime.exec...
I know there's a CTRL+C shortcut in pc but how do I execute this on Android?
Sorry for not adding examples, I'm writing from my phone.
Another way:
Process proc = Runtime.getRuntime().exec("ping 127.0.0.1");
proc.destroy();
As you execute your command, you get the relating process. You can use it to stop your ping, too.
You can't directly send CTRL + C, but take a look at Process.sendSignal() (Android Developers)
First, get the process ID of the ping-process.
Then you can easily send a Process.sendSignal(yourPid, Process.SIGNAL_QUIT);
After debugging for a long time I found out how to solve the problem
"Kill results without the ping statistics being returned".
Get pid of ping process.
Ex:
Progress proc = runtime.exec("ping 192.168.1.1");
where proc will be something like Process[pid=2343], so you need to extract 2343.
Then when you are reading the ping output, you can use
"Runtime.getRuntime().exec("kill -INT " + 2243);" to kill the process.
InputStreamReader reader = new InputStreamReader(proc.getInputStream());
BufferedReader buffer = new BufferedReader(reader);
String line;
while ((line = buffer.readLine()) != null) {
echo.append(line).append("\n");
if (UserStopPing) {
Runtime.getRuntime().exec("kill -INT " + temp);
}
proc.waitFor();
This program will stop ping and you will get the statistic also [variable echo].
You can try this.
There is a CTRL option on your screen. Press that and then enter c.
This might help you.
Just in case people are still looking for a solution to this -- On an Android the equivalent of CTRL+C is "Volume down button" + C on your keyboard. This should stop the ping.

how to implement pooling using android bluetooth chat sample app?

I am working on an application that uses BluetoothChat sample application.
In my main activity I am using a webview in which I load an external page. I am handling Bluetooth functionality via a javascript that loads with the external page. Basically I add a bridge between Javascript and native code via the following line:
myWebView.addJavascriptInterface(new WebAppInterface(this,myWebView), "Android");//I pass a refference to the context and a refference to the webview.
WebAppInterface is the class that has all the public methods I can call from Javascript. In this class I have methods like: enableBluetooth, disableBluetooth, listBoundedDevices, connect etc.
I am using BluetoothSerialService class from BluetoothChat sample application. My device has to connect to an embedded device which receives commands and answers back differently depending on the input I give. An example would be like: when I press a button on the webview I call the following native code:
while(true){
out.write(requestKey);//send command - where "out" is the OutputStream
key = in.read();//get response - where "in" is the InputStream
if(key==KEY1){
out.write(activateRFID);//send command - activateRFID
rfidTag = in.read();//get response - RFID Tag
updateUI(rfidTag);//perform function - update the UI with the tag
}
else if(key==KEY2){
out.write(deactivateRFID);//send command - deactivate RFID
response = in.read();//get response
}
else if(key==KEY3){
out.write(anotherCommand);//send command -
response = in.read();//get response
}
}
What I am trying to achieve is sending commands to another device(request the pressed key) and perform functions. This has to happen always (pooling the device for the key pressed and perform a particular function).
How can I start 1 SINGLE THREAD that pools the device (write to the OutputStream and read the response from the InputStream)? The BluetoothChat sample application works a little different: whenever I call BluetoothChatSevice.write() I get a response via ConnectedThread run method that sends messages to UI via a mHandler.
All suggestions are welcome.
I did it today. I suggest that you do a boolean function readWrite() that whenever you write to outputStream you also read from the inputStream and send the readBuffer to UI with mHandler. If both read and write are ok, than return true, if one of them went wrong than return false and use resetConection before closing your ConnectedThread. See my answer here for the resetConnection. Application using bluetooth SPP profile not working after update from Android 4.2 to Android 4.3
But the answer about pooling is the following:
In the ConnectedThread run() method do a while(true), call a method similar to readWrite(byte[] data) inside the loop, where in the first place you write something to the device, and then you read the data from the input stream (from the device). In this readWrite() method, if writing to outpustream went fine, then continue to read from the inputstream. if you got any data to the input stream, send the data to UI for processing with the mHandler (or do some processing before sending to the UI).
It worked very nice for me.

Reusing the same process for shell commands execution in Android. What is wrong?

My app uses a process in separate thread to run some commands and get the input from them:
process = Runtime.getRuntime().exec("su");
out = new DataOutputStream(process.getOutputStream());
The app sends commands to the process like this:
public void setCommands(String[] commands)
{
try{
for(String command : commands){
out.writeBytes(command + "\n");
}
out.writeBytes("exit\n"); //if I comment this line the commands get lost
out.flush();
}catch(IOException e){
e.printStackTrace();
}
}
The thread then reads the input from process with BufferedReaders and sends it to the main thread and it works fine for the first time. The problem is that I want to reuse the same process with multiple calls to setCommands(), but after the first call the OutputStream of the process gets closed with out.writeBytes("exit\n"); statement. If I comment this line it seems like the out.flush() starts to have no effect. Could somebody please explain to me why is this happening and how can this be done right?

Is it possible to call getevent from an Android service?

Is is possible to run getevent from an Android service and get output similar to what you see when running adb to call getevent from a command prompt on a development machine? When I try something like:
ProcessBuilder builder = new ProcessBuilder()
.command("getevent")
.redirectErrorStream(true)
.start();
BufferedReader reader = new BufferedReader(new InputStreamReader(builder.getInputStream()));
...
the output I get for each device looks like:
could not open /dev/input/event[n], Permission denied
Is it just not possible to access low level information like this because of Android's security protections? Would it be possible on a "rooted" device?
Why I am trying to do this:
I would like to record a user's actions (touch and gesture events) on an Android device for the purpose of usability testing. An accessibility service seems to be the way to go, but the information is not detailed enough. For a swipe gesture, for example, I cannot get the screen coordinates of where the user swiped. I was thinking that getting the low-level input from the touch screen might let me get more detailed information. Maybe there is a better way to do this?
(I'm a newbie in the Android world. This kind of thing is easy on Windows.)
You can do like this.
th = new Thread(new Runnable(){
private Process exec;
#Override
public void run() {
try {
exec = Runtime.getRuntime().exec(new String[]{"su","-c","getevent -t " + device});
InputStreamReader is = new InputStreamReader(
exec.getInputStream());
String s;
BufferedReader br = new BufferedReader(is);
while(((s = br.readLine()) != null) && run){
...
}
is.close();
exec.destroy();
} catch (IOException e) {
e.printStackTrace();
}
}
You must use 'su' to get the root permission, but by this way you can't get the real time event, because there is a buffer size of 4k, you could get data only after contained 4k data.
Search for UIAutomator. This does what you want to do.
Your phone must be rooted to execute getevent/sendevent command.
One way is to install any terminal emulator from play store like Qute: Command Console & Terminal Emulator.
In terminal enter following:
1) su (it'll gain the root access required for getevent)
2) getevent (or getevent -c 8 to output only 8 lines else it would flood the terminal)

Categories

Resources