Execute file from Android device programatically - java

I have finished my Chess UI application and now want to load a chess engine to test if my UI truly is UCI-compatible. The chess engine is inside the Download folder of the Android device ('/storage/emulated/0/Download'). This is the code that is run:
try {
File f = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS);
String path = f.getAbsolutePath();
String stockfishPath = path + "/Stockfish-9-armv64v8";
engineProcess = Runtime.getRuntime().exec(stockfishPath);
processReader = new BufferedReader(new InputStreamReader(
engineProcess.getInputStream()));
String sCurrentLine;
ArrayList<String> output = new ArrayList<>();
while ((sCurrentLine = processReader.readLine()) != null) {
output.add(sCurrentLine);
}
processWriter = new OutputStreamWriter(
engineProcess.getOutputStream());
} catch (Exception e) {
e.printStackTrace();
}
When I run this it fails on the exec() method because it claims it cannot find the file, even though the file exists on the Android device. I tried running the "ls" command on the exec() method, but the folder inside "emulated" is empty. The obvious reason for this is probably because I do not have permission to view/access these files, but I need to know how I can do that (despite adding the READ_EXTERNAL_STORAGE and WRITE_EXTERNAL_STORAGE in the manifest file).
Is it maybe possible to embed the engine somewhere in the project (in resources?) and somehow adb-shell into that?

you cannot do that, simply because the SD card is being mounted with -noexec flag.
using the internal storage with chmod +x would be the only option available.

Related

Android cannot create directory

I cannot create directory, I have all the permissions and this in my Manifest:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
In MainActivity onCreate, checks permission, if it has it should create a directory but it always returns a false:
if (!checkPermission()) requestPermission();
else {
File folder = new File(Environment.getExternalStorageDirectory() +
File.separator + "receipts");
if (!folder.exists()) {
boolean bool = folder.mkdirs();
System.out.println(bool);
}
}
Any clue or hint to why? Thanks
Unfortunately, with the security updates brought by Android 11 and up, as #CommonsWare said, you simply can't write directories on external storage (sdcard).
Straight from the docs:
Access to directories
You can no longer use the ACTION_OPEN_DOCUMENT_TREE intent action to
request access to the following directories:
The root directory of the internal storage volume.
The root directory of each SD card volume that the device manufacturer considers to be reliable, regardless of whether the card
is emulated or removable. A reliable volume is one that an app can
successfully access most of the time.
The Download directory.
Additionally from the same place:
App-specific directory on external storage Starting in Android 11, apps
cannot create their own app-specific directory on external storage. To
access the directory that the system provides for your app, call
getExternalFilesDirs().
Your app has a system generated directory to store any information. This makes sense, of course, because at any given time the user could remove/format the sd card inside the device, and your app's data would be entirely lost.
From more docs:
You would use this to write:
//Write to a file
String filename = "myfile";
String fileContents = "Hello world!";
try (FileOutputStream fos = context.openFileOutput(filename, Context.MODE_PRIVATE)) {
fos.write(fileContents.toByteArray());
}
And to read a file:
//To read from the file
FileInputStream fis = context.openFileInput(filename
);
InputStreamReader inputStreamReader =
new InputStreamReader(fis, StandardCharsets.UTF_8);
StringBuilder stringBuilder = new StringBuilder();
try (BufferedReader reader = new BufferedReader(inputStreamReader)) {
String line = reader.readLine();
while (line != null) {
stringBuilder.append(line).append('\n');
line = reader.readLine();
}
} catch (IOException e) {
// Error occurred when opening raw file for reading.
} finally {
String contents = stringBuilder.toString();
}
These are both within your app's "sandbox" folder. Because of this, you do not need to declare permissions.
File folder = new File(Environment.getExternalStorageDirectory() +
File.separator + "receipts");
Change to:
File folder = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS), "receipts");

Android Studio :: Want to list files saved in default location

I'm new to Android Studio 3.0, emulating on a Nexus 4, Marshmallow. I'm trying to build simple "Save File" and "Load File" parts of my app. Here's the "Save File" part:
String filename = "myFile01"; // Then "myFile02", "myFile03", etc...
String userData = "Some useful data here...";
try {
// Adapted from: https://www.youtube.com/watch?v=_15mKw--RG0
FileOutputStream fileOutputStream = openFileOutput(filename, MODE_PRIVATE); // creates a file with given filename
fileOutputStream.write(userData.getBytes()); // puts userData into the file
fileOutputStream.close();
Toast.makeText(getApplicationContext(), "File saved!", Toast.LENGTH_LONG).show();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
The above code will be called again and again as the user creates and saves additional files. Later, the user may want to view all the saved files and load one. I'll have a ListView displaying all the files... but I need help reading the current directory to get that list.
I thought I read somewhere that in Android, there's one flat directory for your app to save and retrieve files. So I was hoping if I saved a bunch of files and then called a read() method, all my saved files would simply be in the default directory, no need to search. That seems to be a bad assumption; here's why:
Here's my code looking in the default directory and listing all the files found within there. First, I need the path of said default directory:
// Get current directory adapted from: https://stackoverflow.com/questions/5527764/get-application-directory
String packName, currDir;
PackageManager m = getPackageManager();
packName = getPackageName();
PackageInfo p = null;
try {
p = m.getPackageInfo(packName, 0);
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
}
currDir = p.applicationInfo.dataDir;
And then I open "currDir," and store the names of all the local files in an array:
// get list of files adapted from: https://stackoverflow.com/questions/9317483/showing-a-list-of-files-in-a-listview#9317583
File dir = new File(currDir);
File[] filelist = dir.listFiles();
String[] fileArr = new String[filelist.length];
for (int i = 0; i < fileArr.length; i++) {
fileArr[i] = filelist[i].getName();
}
The plan from here is to load the "fileArr" into a ListView and go from there. But when I step through the debugger, I see this as the contents of "fileArr":
"cache"
"code_cache"
"files"
This is true no matter how many files I've saved previously.
BTW, in the debugger, the assignments for packName and currDir look 100% correct:
packName = com.mydomain.myapp
currDir = /data/user/0/com.mydomain.myapp
So... I'm kinda assuming that my saved files are actually here:
/data/user/0/com.mydomain.myapp/files
And therefore, I should append this to my "get current directory" code:
// Get current directory adapted from: https://stackoverflow.com/questions/5527764/get-application-directory
String packName, currDir;
...everything from before...
currDir = p.applicationInfo.dataDir+"/files"; // <---- appending "+"/files"
Or am I way off? Any advice will be appreciated, thanks!
First of all, if you want to save your files in the app's directory, then you should call create a directory,
File directoryDefault = new File(Environment.DIRECTORY_DOCUMENTS, "YOUR_FOLDER_NAME");
if (!directoryDefault.exists()) {
directoryDefault.mkdir();
}
Then you have to save whatever files you have to save in the above mentioned default directory. Afterwards, when you want to list all the files available in that directory, you should call,
private ArrayList<String> fileNames() {
ArrayList<String> namesArray = new ArrayList<>();
File[] arrayFiles = directoryDefault.listFiles();
for (File file : arrayFiles) {
namesArray.add(file.getName());
}
return namesArray;
}

java.io.FileNotFoundException: (Permission denied) when writing an object using ObjectOutputStream

I have been trying to work around this for several hours and I am extremely frustrated so I am coming to you guys for some guidance.
I am trying to save and retrieve a User object I have created. I want to make it so that I can save and retrieve this User object from any intent throughout my application, so I decided to go with a FileInput and Output stream. I have included my code for both below.
Here is my output data method:
public static void serializeDataOut(User ish) {
try {
String path = Environment.getExternalStorageDirectory().getAbsolutePath();
File newFile = new File(path + "myFile.ser");
FileOutputStream fos = new FileOutputStream(newFile);
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(ish);
oos.flush();
oos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
And here is my input data method:
public static User serializeDataIn(){
try{
String path = Environment.getExternalStorageDirectory().getAbsolutePath();
FileInputStream fin = new FileInputStream(path + "myFile.ser");
ObjectInputStream ois = new ObjectInputStream(fin);
User iUser = (User) ois.readObject();
ois.close();
return iUser;
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
return null;
}
}
Note: both of these methods reside inside my User class, which also implements Serializable.
The whole error with the file path looks like this: java.io.FileNotFoundException: /storage/emulated/0myFile.ser (Permission denied) and it appeared at this line: FileOutputStream fos = new FileOutputStream(newFile); when I called it from a different intent like so: User.serializeDataOut(addingUser); in which addingUser was a valid User object.
The first thing I did after seeing (Permission denied) in the exception log, was go into my manifest and check if I was allowing my application to read and write to storage, which I did in fact do. I have included my permissions below:
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
Then I read that some people were having this error if they had the wrong path, more specifically not including the absolute path, which I then edited my code to include the Environment.getExternalStorageDirectory().getAbsolutePath(); part, which I am pretty sure I am using correctly.
I also made sure that, since I am testing this on an emulator, that I had enabled an SD card and the emulator had an SD folder. I checked and it indeed did have an SD card folder, and I also tested this application on an S8 and I got the same error.
What exactly am I doing wrong here? All I want to do is save one User object and retrieve it somewhere else, and I am perfectly ok with a previous file being overwritten and only having one User saved at a time.
Also something that is probably related I just noticed: about every 3-5 seconds in my Android Monitor, an error keeps on popping up non stop even after I kill my application. The error looks like this: onFatalError, processing error from engine(4)
com.google.android.apps.gsa.shared.speech.a.g: Error reading from input stream Although I can only assume this isn't the source of the problem, I just wanted to add it in, in case it could help. Thanks
You've added the permission in manifest, So I'm sure you are not asking runtime permissions. If you are using SDK 23 or higher, Ask runtime permission. For reference I'm adding some snippet here:
if(Build.VERSION.SDK_INT>22){
requestPermissions(new String[] {YOUR_PERMISSIONS AS STRING}, 1);
}
and to check whether permission is granted or not, you need to use onRequestPermissionResults() method.
#Override
public void onRequestPermissionsResult(int requestCode,
String permissions[], int[] grantResults) {
switch (requestCode) {
case 1: {
if (!(grantResults.length > 0
&& grantResults[0] == PackageManager.PERMISSION_GRANTED && grantResults[1] == PackageManager.PERMISSION_GRANTED)) {
Toast.makeText(addAlarm.this, "Permission denied to access your location.", Toast.LENGTH_SHORT).show();
}
}
}
}
This java.io.FileNotFoundException: /storage/emulated/0myFile.ser looks like you are missing a '/' in the path.
Use
String path = Environment.getExternalStorageDirectory().getAbsolutePath() + '/';
Beginning in Android 6.0 (API level 23), users grant permissions to
apps while the app is running
Everything you need to know is in :
https://developer.android.com/training/permissions/requesting.html
The other error has nothing to do with it

how to open a file using exec method in java?

C:\Users\Admin\Downloads\VID_20160226_203631957.mp4
when I execute above line in command prompt the corresponding video gets played with default media player.
But when I try to do same using java Runtime class it doesnt work.
I am using following method.
Runtime r= Runtime.getRuntime();
r.exec("C:\Users\Admin\Downloads\VID_20160226_203631957.mp4")
Use Desktop.open(File) which launches the associated application to open the file. Something like,
File f = new File("C:/Users/Admin/Downloads/VID_20160226_203631957.mp4");
try {
Desktop.getDesktop().open(f);
} catch (IOException e) {
e.printStackTrace();
}
You might prefer to build the path relative to the user's home directory; something like
File downloads = new File(System.getProperty("user.home"), "Downloads");
File f = new File(downloads, "VID_20160226_203631957.mp4");
Try this.
Runtime r= Runtime.getRuntime();
r.exec("cmd /c C:\\Users\\Admin\\Downloads\\VID_20160226_203631957.mp4");

Using "pathdir" on Java Applications

First, i'm using Ubuntu! :)
I need some help here,
I built a Java App, i want to set a default path tree, like this:
> cd /anyDirectory/meuRestaurante
> ls
bin/ data/
> cd bin
> ls
meuRestaurante.jar
> cd ..
> cd data
> ls
Cartoes.txt Clientes.txt
I want that my Java App save these txt's files on /data directory, while is on /bin directory.
Exctaly, how should be if i use these functions to read/save the txt's files.:
public static String readFile(String fileName) {
try {
File file = new File("."+fileName);
FileReader reader = new FileReader(file);
BufferedReader in = new BufferedReader(reader);
String string;
String returnString = "";
while ((string = in.readLine()) != null) {
returnString = "" + returnString + string;
}
in.close();
return returnString;
} catch (IOException e) {
System.err.println("readFile " + e.getMessage());
return null;
}
}
public static boolean writeFile(String fileName, String newContent){
try {
BufferedWriter out = new BufferedWriter(new FileWriter(fileName, true));
out.write(newContent);
out.close();
return true;
}catch(IOException e){
System.err.println("writeFile " + e.getMessage());
return false;
}
}
How should be the fileName?
Anyone has a tip ?
Try this:
data/Cartoes.txt
If these files are intended to be read only, put them in a Jar, add the Jar to the applications run-time class-path and access them using getResource().
If the files are intended to be written to (read/write), avoid attempting to save files in a location relative to the application executable(1). This will lead to no end of frustration later.
Instead, put the data files in a sub-directory of ${user.home}. The sub-directory is to help ensure that applications do not overwrite each others files. The sub-directory might be based on the package name of the main class of the app., which should be unique to your organization.
(1)
Neither applets nor apps. launched using Java Web Start are able to discover the location the app. is stored on the local disk.
Microsoft has been telling developers for years not to save program settings in the 'Program Files' folder.
While an app. is almost guaranteed of being able to write to/read from user home, the tightening of security in recent times means that other locations are much less reliable.

Categories