ADB shell get Toast messages - java

I have been working around a Java test framework and ended up with testing an android application which does a lot of toast messages.
The problem is the framework doesn't use anything other than ADB and I can't use any extra libs.
so Is there any way to get the toasted message from an application via adb?
I wouldn't mind writing hundreds of lines for this alone..

You can check toast messages through events with adb shell uiautomator events from the command line. Within your java test framework, however, you can create a method for code reuse that runs this command and parses it for whatever string you want to compare it to with a try block as such:
try {
Process process = Runtime.getRuntime().exec("uiautomator events");
BufferedReader bufferedReader = new BufferedReader(
new InputStreamReader(process.getInputStream()));
StringBuilder log=new StringBuilder();
String toastMessage;
while ((toastMessage = bufferedReader.readLine()) != null) {
log.append(toastMessage).append("\n");
if (toastMessage.contains(myToastStringVar)) {
Log.i("ToastMessageMatcher", "" // <-- your info message);
} else {
Log.e("ToastMessageMatcher", "" // <-- your error message);
}
}
bufferedReader.close();
process.waitFor();
System.out.println(log.toString());
} catch (IOException | InterruptedException e) {
e.printStackTrace();
}
This can likewise be directly in your derivatives too.

Using AndroidViewClient/culebra you can wait for and retrieve the text in a Toast using something like this
#! /usr/bin/env python3
# -*- coding: utf-8 -*-
from com.dtmilano.android.viewclient import ViewClient
vc = ViewClient(*ViewClient.connectToDeviceOrExit(), useuiautomatorhelper=True)
print(vc.uiAutomatorHelper.device.wait_for_new_toast(timeout=10000))
however in this case is not using adb as the backend (which is the default for AndroidViewClient/culebra) but CulebraTester2-public, an alternate backend with more capabilities (precisely this is one of those). You get this backend using useuiautomatorhelper=True while creating the ViewClient object.
You can take a look at the complete API here, so if you want to use java you would be able.

Related

Calling python script from java web application with Processbuilder

I am working on a simple meteo station - I want to use raspberry pi 3b+ as a host, dht22 sensor and write a web application in Java (with spring boot, then deploy it to tomcat 8) and Python for retrieving sensor's data.
What I've done so far:
Python application for retrieving and displaying data. Works as expected, it just prints something like "22.5;37.4":
import Adafruit_DHT
DHT_SENSOR = Adafruit_DHT.DHT22
DHT_PIN = 4
humidity, temperature = Adafruit_DHT.read_retry(DHT_SENSOR, DHT_PIN)
if humidity is not None and temperature is not None:
print("{0:0.1f};{1:0.1f}".format(temperature, humidity))
else:
print("FAIL")
Then I've wrote a java application, put it into .jar and checked if I am able to get sensor's data. Not a rocket science, also works as expected when I use java -jar InputTest.jar on my raspberry pi:
public static void main(String[] args) {
try {
ProcessBuilder pb = new ProcessBuilder("python", "/home/pi/Desktop/input/dht_once.py");
Process process = pb.start();
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
String line;
while ((line = reader.readLine()) != null) {
System.out.println("measured: " + line);
}
process.waitFor();
} catch (IOException ) {
System.out.println(" exception " + e.getLocalizedMessage());
}
}
Then I've created a spring boot application, put my java code inside (logic same as above), packed as a war, deployed to tomcat 8 and run it. It turned out nothing is being printed (of course I've changed code to log output to logfile, it works fine, I can see other logs inside). No issues in logs, it looks like reader never returns a line.
I believe application does not wait for a process to produce output, but I have no idea why. Important thing: it takes up to few seconds to produce sensor's output. I've also changed python script just for test purposes to return value immediately:
print("22.4;33.0")
and it results in successful read by java web application. But when it has to wait few seconds for the output it kills process (process.isAlive() is false right after while loop).
I've also tried to play with sleep() on current thread to force it to wait for python process but no success.
Do you guys have any idea what can be the reason for this behavior? Is there anything more I should check?
TLDR;
Java application which creates python process works fine until I run it as a web application - then it looks like it does not wait for a process' output
I haven't found a solution yet, however I've implemented workaround/cleaner solution.
I've decided to separate totally java and python code and created microservice for data retrieving. I use flask for rest webservice (followed this tutorial https://docs.dataplicity.com/docs/control-gpios-using-rest-api) and call it directly from java.
Since this does not resolve my initial question I do not mark it as an answer, however it might help someone.

Set focus of any application with Java (OSX)?

How can I set the focus (e.g. cmd+tab) of an arbitrary application (Java or not) from a Java program, on OSX?
Looking for an answer to this question, I came across this question, but it doesn't really help for OSX.
EDIT: one possibiltiy seems to be to use something like Quicksilver, and a Robot to send it keypresses with modifiers. I'd prefer something more portable, though, that requires less setup to make changes after it's compiled....
You should be able to reactivate an already running app using the open command that comes with OS X:
Runtime.exec("open /path/to/Whichever.app");
(Or some equivalent overload of that function.) This will also open an app if it's not running yet.
Chuck's answer tipped me off to osascript, so I decided to give it a shot straight from the command line. Managed to get it working with Runtime.exec(), osascript, and AppleScript.
Java launches an AppleScript and passes it the application name, using osascript from the command line, via Runtime.exec():
try {
List<String> shellCommandList = new ArrayList<String>();
shellCommandList.add("osascript");
shellCommandList.add("activateApplication.scpt");
shellCommandList.add(appName);
String[] shellCommand = (String[])shellCommandList.toArray(new String[0]);
Process p = Runtime.getRuntime().exec(shellCommand);
// if desired, pipe out the script's output
BufferedReader in = new BufferedReader(new InputStreamReader(p.getInputStream()));
String cmdOutStr = "";
while ((cmdOutStr = in.readLine()) != null) {
System.out.println(cmdOutStr);
}
// if desired, check the script's exit value
int exitValue = p.waitFor();
if (exitValue != 0) {
// TODO: error dialog
System.err.println("Invalid application name: "+ appName);
}
} catch (Exception e) {
e.printStackTrace();
}
And the AppleScript uses a run handler to capture the incoming argument:
on run (arguments)
set appName to (item 1 of arguments)
tell application appName to activate
return 0
end run
You can use the javax.script API to run AppleScripts. So you can write a script along the lines of "tell application "WhateverApp" to activate", filling in your arbitrary application for WhateverApp, and it should do what you want.

android getRuntime().exec() with cat command

I am using the process class to run this command
/sdcard/file1.mpg /sdcar/file2.mpg > /sdcard/out.mpg
Here is how I am trying to do it:
Process processx = Runtime.getRuntime().exec(new String[] {"cat","/sdcard/file1.mpg /sdcard/file2.mpg > /sdcard/out.mpg" });
BufferedReader in = new BufferedReader(new InputStreamReader(processx.getInputStream()));
String line = null;
while ((line = in.readLine()) != null) {
System.out.println(line);
}
// Waits for the command to finish.
processx.waitFor();
The command works from terminal but not when I try the above, can anyone see why?
Redirection (>) is not the OS feature. This is a feature of shell. To make it working from java you have to run something like the following:
/bin/sh yourcommand > yourfile
i.e. in your case:
/bin/sh cat /sdcard/file1.mpg /sdcard/file2.mpg > /sdcard/out.mpg
BUT could you please explain me why are you doeing this? Do you understand that this command is exact equivalent of cp /sdcard/file1.mpg /sdcard/file2.mpg /sdcard/out.mpg that can be coded in pure java without running any command line? Unless you have special reasons go on it! Write pure java code when it is possible. It is easier to debug, support and maintain.
There's absolutely no reason to use 'cat' to do this. It's not a supported or encouraged mechanism on Android, and there's no reason to launch a new executable to do what you can easily do in java code, by reading in one file and writing it out to the other.
For the record, you are trying to do a shell redirection, and that will not work since you are not executing a shell.
im using this small code to execute "cat" command and most of shell commands:
String[] cmdline = { "sh", "-c", "cat /sdcard/file1 >> /sdcard/file2" };
try {
Runtime.getRuntime().exec(cmdline);
} catch (Exception s) {
finishAffinity();
}

Redirecting Input/Output/Error Streams of a CMD.exe Process Completely with Java

My aim with this project was to have a remote command prompt feel with Java. Using TCP/IP sockets, I was aiming to run a command prompt process on one computer, and virtually transmit all control to the other side. I immediately stumbled over Runtime.getRuntime().exec() and Process objects, etc. I've solved my problem about halfway. With my remote command prompt, I can run a single command, gather the output, and send it back to the other side. The problem is, I can only seem to run one command per command prompt instance. This won't do (with situations where I need to change directory and THEN run a command, etc). I've stripped all socket/networking programming from this situation to show you (and to create an easier testing environment for me).
import java.io.*;
public class testingProgram {
public static void main(String[] args) {
Runtime rt = Runtime.getRuntime();
StringBuilder inputMessage = new StringBuilder();
String resultData;
try {
Process pr = rt.exec("cmd.exe /c net user");
BufferedReader processInput = new BufferedReader(new InputStreamReader(pr.getInputStream()));
BufferedReader errorProcessInput = new BufferedReader(new InputStreamReader(pr.getErrorStream()));
PrintWriter processOut = new PrintWriter(pr.getOutputStream());
while( (resultData = processInput.readLine()) != null ) {
inputMessage.append(resultData + "\n");
}
resultData = inputMessage.toString();
System.out.print(resultData);
} catch(IOException e) {
} //catch(InterruptedException e) {
//}
}
}
I have a lot more, but this is where my problem is. I can customize the command "net user" with a simple variable and message from the socketstream, so that's not my problem. My problem is that I need to create an ongoing command prompt instance, retaining all redirections of the input/output. Basically, I would like to be able to send another command AFTER "net user".
I have gathered and redirected the output stream. I want to be able to do something like:
processOut.write("net user");
I want to be able to use this, have the command prompt run the command, and retain the output (whether it be from the errorStream OR the inputStream).
I just need some more direction on how to go about doing this.
You should look into multi threading. What you basically want is a thread which keeps running and maintaining the rt.
Like this:
String commandLine;
while ((commandLine = System.in.readline()) != 'q') {
Process pc = rt.exec(commandLine);
}
For further reference on multithreading:
http://download.oracle.com/javase/tutorial/essential/concurrency/procthread.html
You problem is that your program terminates after one call.
cheers
You're telling the command interpreter to terminate. Remove the /C after cmd.exe.
cmd /?
Starts a new instance of the Windows command interpreter
CMD [/A | /U] [/Q] [/D] [/E:ON | /E:OFF] [/F:ON | /F:OFF] [/V:ON | /V:OFF]
[[/S] [/C | /K] string]
/C Carries out the command specified by string and then terminates
/K Carries out the command specified by string but remains
...

Strange behavior when running a bash script from java program

I have a script (KSH script to be precise) that downloads 3 files from a FTP server, using the curl command.
When I run manually my script, i.e. by executing the command ./ftp_download.sh XXX (XXX are the parameters for the script), the download finishes correctly.
As I want to run the script from a Java program, I have made a short Java class that contains exactly that:
public class Run {
private static final String CMD = "/.../sh/ftp_download.sh XXX";
public static void main(String[] args) {
System.out.println("========================================================");
BufferedReader out = null;
try {
long startTime = System.currentTimeMillis();
String strOutputline;
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date now = new Date();
Process processus = Runtime.getRuntime().exec(CMD);
out = new BufferedReader(new InputStreamReader(processus.getInputStream()));
while ((strOutputline = out.readLine()) != null) {
now.setTime(System.currentTimeMillis());
System.out.println(sdf.format(now) + " " + strOutputline);
}
System.out.println("RESULT : " + processus.waitFor());
out.close();
processus.destroy();
long duration = System.currentTimeMillis() - startTime;
System.out.println("Duration : " + duration);
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (out != null) {
out.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
System.out.println("========================================================");
System.out.println("END");
}
}
However, when I run this simple program, it simply freezes after exactly 3m20 (this duration is always the same, even if I run the Java program several times).
By freezing, I mean that the Java program is still running (the curl process too) but the downloaded file is not growing anymore (i.e. curl does not continue to download any data)...
Thus, I never get the RESULT: xxx line printed in the console...
What can explain this strange behavior?
ps: In the near future, I will change my project in order to download these files using the Apache commons-net library, but I really want to understand this strange behavior!
Thanks to derobert, I finally manage to solve this issue. Some explanations: in normal mode, curl is displaying a progress information (a table with the amount of data downloaded, the remaining time, etc.). After some time, the buffer seems to be completly filled, and that's why the process freezes...
I'm not a Java person, but rather a Unix one, and one thing seems obvious: The buffer on either stdout or stderr is filling up, and then curl is blocking.
Does it work if you run curl in silent mode, as in curl --silent?
Checking the Java documentation, it looks like you want to also use getErrorStream in addition to getInputStream.
From Process:
The parent process uses these streams to feed input to and get output from the subprocess. Because some native platforms only provide limited buffer size for standard input and output streams, failure to promptly write the input stream or read the output stream of the subprocess may cause the subprocess to block, and even deadlock.
So you need to get the standard output and the error output of the process and read them until they’re empty (i.e. returning -1 on read()).

Categories

Resources