I have a Java SE Application that use
input = new Scanner(System.in);
to get Input parameters
and use System.out.println("..");
to print results
Since all Java APIs used in the original Java Project are also available in Android, I have tried to import all classes without any error, but now I don't know how replicate the behaviour of the classic Java console in Android.
I have seen that there are developers that have achieved this in some IDE-like apps, but I don't know how.
Could you help me?
Example:
assume that you want to port this dummy Java SE Application in Android mantaining the console-like approach of the original code
public static void main(String[] args) {
System.out.println("Please enter your choice");
System.out.println("A, B");
Scanner myScanner = new Scanner(System.in);
String choice = myScanner .nextLine();
if (choice.charAt(0) == 'A') {
...do something
}
else{
...do something
}
}
You can execute system commands with exec(). Here is how to do it:
Runtime r = Runtime.getRuntime();
Process p = r.exec("uname -a"); // here goes your input
p.waitFor();
BufferedReader b = new BufferedReader(new InputStreamReader(p.getInputStream()));
String line = "";
while ((line = b.readLine()) != null) {
System.out.println(line);
}
Update:
Ok, from what I understand, you would like to compile and run code written by user. I can see 3 options:
Most difficult I think. Get the source code of some Java compiler and include it in your project. So, user inputs a text. You compile it, run and give the output.
Using already built compiler. This requires root. Install javac on your device. Then, in your application you can call it with the above exec() code.
Easiest one. Using internet and for example, Ideone.com. In your app you send code to compile on Ideone. You get back the output and present it to the user.
Related
I'm thinking of creating a nice gui for ffmpeg command line using Sketchware. Is it possible to add a ffmpeg build into a Sketchware project?
I'd say kinda, you will need an arm-compiled ffmpeg (with it's library statically-linked i believe) for that, and if i'm not wrong, you can execute ffmpeg directly using Runtime.getRuntime().exec("path/to/ffmpeg -arguments");
So it goes on like this:
First, you'll need to include the arm-compiled ffmpeg into your app and extract it at launch at getFilesDir() directory,
Second, the ffmpeg needs to be chmod u+x ffmpeg-ed to allow the user to execute the binary.
Third, just use the above code, Runtime.getRuntime().exec("path/to/ffmpeg -arguments")
Though, I've heard some news that Android 11 is going to restrict binary execution like this.
Another note, I haven't really tried this myself, but if i have time, I'll probably update this answer.
I just found out a precompiled ffmpeg binary that is used on termux here. All you need to do is to manually change the library locaiton to the extracted library location.
I did not understand your question well
, But if you want cmd this class does it
public class CommandLine{
private BufferedReader r;
private Process p;
private ProcessBuilder builder;
private String LinesString = null;
public String run(String command)throws Exception{
builder = new ProcessBuilder(command.split(" "));
builder.redirectErrorStream(true);
p = builder.start();
r = new BufferedReader(new InputStreamReader(p.getInputStream()));
String line = null;
Object[] lines = r.lines().toArray();
for (int i = 0; i < lines.length; i++) {
if(LinesString == null){
LinesString = lines[i].toString();
}else{
LinesString = LinesString + " "+lines[i].toString();
}
}
return LinesString;
}
}
Until you run this class :
try{
String out = new CommandLine().run("echo hi");
} catch (Exception e) {
}
Well,
because it's not even for android, it's quite impossible.
If FFmpeg was for Android, in theory it would be possible.
It is impossible to make a command line for FFmpeg in Android on Sketchware (that is, if you do not need to program any emulators;))
Probably the only option would be a Linux terminal emulator, but in Basic Sketchware I doubt it would work. Otherwise, in sketchware you can do practically anything (especially Sketchware PRO) using the ASD block (Add source directly) which allows you to upload your own code.
Summary; it is not possible. (Or very difficult)
I am doing the dagger tutorial for android in java, and they told me to create this class:
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
CommandRouterFactory commandRouterFactory =
DaggerCommandRouterFactory.create();
CommandRouter commandRouter = commandRouterFactory.router();
while (scanner.hasNextLine()) {
commandRouter.route(scanner.nextLine());
}
}
}
I wrote my own code to try to see what the scanner is pulling from, but nothing shows up. I am just wondering, if System.in is some sort of command line input, and if so, how would I see that show up? I tried typing in the terminal built into android, but that doesn't produce any output either.
Finally, where do you even get a class like this to run in android? I'm only used to having code run at least from the starting point of a main activity.
Here's the link to the tutorial - it doesn't help much with setting up
https://dagger.dev/tutorial/02-initial-dagger
I'm working on an app that uses Android's MediaMuxer for recording the screen. Using Crashlytics, a significant number of users have the "Failed to stop the muxer" crash, but I can't reproduce it locally on any of my devices. According to another question, the MPEG4Writer logs generated while MediaMuxer is running should indicate what the source of the problem is, but since I'm unable to reproduce it locally, I need to collect those logs remotely and pass them over to Crashlytics.
So here's my problem: MediaMuxer and MPEG4Writer are system classes, so obviously I can't edit them to add Crashlytics.log() lines. I've thought of having the app read the Logcat output and storing all entries containing MPEG4Writer, which are then sent to Crashlytics if the muxer crashes, using this implementation as a base. Here's my code:
public class LogRetriever extends Thread {
private static final String TAG = LogRetriever.class.getCanonicalName();
public static ArrayList<String> logStorage = new ArrayList<>();
private AtomicBoolean mLoggingActive = new AtomicBoolean(true);
#Override
public void run() {
try {
String[] command = new String[] { "logcat" };
Process process = Runtime.getRuntime().exec(command);
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(process.getInputStream()));
String line;
while (mLoggingActive.get() && ((line = bufferedReader.readLine()) != null)){
if(line.contains("MPEG4Writer")) {
logStorage.add(line);
}
}
}
catch (IOException ex) {
Log.e(TAG, "start failed", ex);
}
}
public void stopLogging() {
mLoggingActive.set(false);
}
}
Using the above method, I only seem to get the first four log lines generated by MPEG4Writer. The rest are visible through Android Studio's logcat, but aren't collected by my code. I've also tried this library which seems to do the same thing, but again, same problem, only the first 4 lines are collected. I suspect that MediaMuxer is creating its own process after those 4 lines, at which point I can no longer read its logcat output because my LogRetriever class is now in a different process. So how am I supposed to collect those logs? Am I taking the wrong approach here?
So how am I supposed to collect those logs?
Generally, unless you are working for a device manufacturer, you don't collect those logs.
First, accessing LogCat at runtime has never been officially supported; hence, the clunky "fork logcat" approach that you have to take.
Beyond that, you need the READ_LOGS permission to get more than what you are. That permission has signature|privileged|development for the protectionLevel, meaning that ordinary apps cannot hold that permission.
This is for privacy reasons. READ_LOGS gives you access to all of LogCat, and lots of apps (and some system processes) log information that may be sensitive.
Good day. The main amazing thing about the BeanShell is the idea that i can control what i want to be done dynamically from the server and i thought it would be amazing.
Although i never succeded in achieving that and seems no one else tried to start activity from the beanshell either.
Here how it goes. I simply want to pass the code from the server side to the Android,Android is going to evaluate that code within interpreter and run that.
The issue is that i am getting the exception from BeanShell no matter what i try.
The code from server side is the next.
$response['method'] = "import my.some.name.*;"
. "startActivity(new Intent(this,MyProfile.class))";
The code for Android is the next.
try {
String responseBody = response.body().string();
JSONObject jsonObject = new JSONObject(responseBody);
String method = jsonObject.optString("method");
Interpreter interpreter = new Interpreter();
try {
Object res = interpreter.eval(method);
} catch (EvalError evalError) {
evalError.printStackTrace();
}
} catch (IOException e) {
e.printStackTrace();
} catch (JSONException e) {
e.printStackTrace();
}
}
But i am getting the next exception from the BeanShell
Sourced file: inline evaluation of: ``import my.some.name.*;startActivity(new Intent(this,MyProfile.class));'' : Class: MyProfile not found in namespace : at Line: 1 : in file: inline evaluation of: ``import my.some.name.*;startActivity(new Intent(this,MyProfile.class));'' : MyProfile
Any ideas what is going on?
Just in case if anyone needs the same solution i am posting for everyone to know.
Here how it goes.
Firstly you need to know that whatever you are trying to do on the server side remember that the BeanShell actually does not know anything about the String code you are passing itself,as it is going to interpret it just like a code out of box so with the help of CommonWare hint about full name path i managed to get it working.
So first step to do is to initialize the Interpreter.
Basic initialization goes like this :
String responseBody = response.body().string();
JSONObject jsonObject = new JSONObject(responseBody);
String method = jsonObject.optString("method");
Interpreter interpreter = new Interpreter();
try {
interpreter.set("context",getApplicationContext());
Object res = interpreter.eval(method);
} catch (EvalError evalError) {
evalError.printStackTrace();
}
Take a very attentive notice about the context as it was my main issue going back and forth as at the moment when i succeded to actually force BeanShell recognize my classes,the BeanShell started to throw Method not found exception about the startActivity() so by thinking logically we can assume that we would set the context as activity as the parent one for our remote methods and start evaluating everything from the context. So here how the remote code is looking.
$response['method'] = "import ink.va.activities;"
. "import android.content.Intent;"
. "import android.content.*;"
. "context.startActivity(new android.content.Intent(context, my.package.name.MyProfile.class));";
The most important things to notice here.
• We are importing everything possible for BeanSherll to recognize our classes,even if they are Android-Build,no matter,still we need to import them.
• If you are going to use any class,then as CommonWare noticed out,you MUST specify the full path to that Class E.G my.package.name.MyProfile.class.
• As i was getting Command Not Found i started to think about the context.startActivity() as i have defined the context beforehand in BeanShell as my parent from which i am going to use methods and Woala,everything worked like a charm!
Possible Problems
I don't know a lot about BeanShell, but there's a couple of issues here
You can import a class (in a compiled language) at runtime
You're trying to do the equivalent of Reflection (but aren't doing any)
Security. No user would consent to you having control to open a screen on their app remotely
Presumably BeanShell is supposed to do the reflection under the covers, but in an case you won't be able to do the import.
Possible solutions
The class/activity using the library should import everything (I'm not sure if a compiler will even retain this)
You can use reflection directly, with things like "method from name". The downside is it's very limited what code you can send from the server unless you handle a myriad of cases.
You could only send names/commands; to specific endpoints in your java app (this is what I recommend) and plan the actions you want ahead of time
$response['method'] = "my.some.name.MyProfile";
JSONObject jsonObject = new JSONObject(response.body().string());
String nameParam = jsonObject.optString("method");
Class<? extends Activity> clazz = Class.forName(nameParam); //wrap with try
startActivity( new Intent(this, clazz) )
To the best of my (current) understanding, Android has no console to send the messages to so the System.out.println messages get lost. Instead, Log.x (outputing to LogCat) should be used.
Yet, in the acclaimed Pro Android 2 book, listing 8-1 does just that:
in = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));
StringBuffer sb = new StringBuffer("");
String line = "";
String NL = System.getProperty("line.separator");
while ((line = in.readLine()) != null) {
sb.append(line + NL);
}
in.close();
String page = sb.toString();
System.out.println(page);
Does System.out.println really work in Android or is it only a typo?
If the former (i.e. not a typo), what does it really do and where should I expect to find the output?
System.out.println prints to whatever is currently defined as the "standard" output PrintStream. It is possible to hook this up to point to the log stream, but really there is no good reason to use it. Use Log.x.
This is probably just a typo in the book. Nothing in that code snippet is Android specific.
That System.out.println code does work (despite what the android documentation says). I've tried it on my on my Android development set up (without changing the settings as they describe in the documentation). I've had tried on the set ups of my Android programming students, both on their Windows and Macs. And it always comes out the same way:
The following line does output to logcat by default.
System.out.println("blah blah");
Now of course, it's probably best to stick to Log.x() anyway. It's probably never a good idea to rely on undocumented features, especially in a book. This feature could be here today, and be just as well gone the next time the tools get updated.
From the android docs:
By default, the Android system sends stdout and stderr (System.out and System.err) output to /dev/null.
It also explains how to use System.out and System.err properly.
If you're using Eclipse, System.out will be displayed on the LogCat tab not in the Console.
You can also try the Log.i("MyLog", "The message here...."); also displayed on the LogCat.
Enjoy!