Persist Map <Integer, Integer> in android - java

I tried this weekend with different approaches to store data of a map <Integer, Integer> in android. Unfortunately, this has not worked as desired.
Corresponding code section:
if (getCounter() > 19){
try
{
File folder = new File(this.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS), "hashmap");
if (!folder.exists())
{
folder.mkdirs();
}
File ganiuSave = new File(folder, "mapDEGR");
OutputStream mapSave = new FileOutputStream(ganiuSave);
ObjectOutputStream oos = new ObjectOutputStream(mapSave);
oos.writeObject(mapDEGR);
oos.close();
mapSave.close();
}
catch(IOException ioe)
{
ioe.printStackTrace();
}}
I could not locate the corresponding file on the smartphone. The app was previously transferred to the smartphone using android debug bridge. The map contains values, so this should not be a reason why no saving takes place. All classes involved implement Serializable and no exception got thrown.
Anyone any ideas?
Tell me if you need more surrounding code to evaluate the issue. Code segment is located inside a switch statement.

To locate your file you can log your file's absolute location like this:
Log.v(LOG_TAG, "File Location: " + ganiuSave.getAbsolutePath());
Once you get the exact location, you can reach the file by using ADB or Android Studio's "Device File Explorer". When I tried with your code I'm getting:
On the emulator api 17;
/mnt/sdcard/Android/data/com.example.yourapp/files/Download/hashmap/mapDEGR
on a physical device api 24;
/storage/emulated/0/Android/data/com.example.yourapp/files/Download/hashmap/mapDEGR

Related

Can't create a folder in external storage, Android

I tried a lot to find a solution but everything has failed so far. It's probably something stupid.
I'm trying to save a photo as a jpeg in the storage of the phone. Everything fails even the simple task of making a folder. The code below is what I use to create the folder.
private void makeFolder(){
try{
File folder = new File(Environment.getExternalStorageDirectory().getAbsolutePath(),getString(R.string.app_name));
boolean success = true;
if (!folder.exists()) {
success = folder.mkdirs();
}
if (success) {
Toast.makeText(this,"Done",Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(this,"folder_failed",Toast.LENGTH_SHORT).show();
System.out.println(folder.getAbsolutePath());
}
}catch (Exception e){
Toast.makeText(this,"exception",Toast.LENGTH_SHORT).show();
e.printStackTrace();
}
}
I have tried many different ways like:
File folder = new File(Environment.getExternalStorageDirectory().getAbsolutePath() +
File.separator + getString(R.string.app_name)+File.separator);
File folder = new File(Environment.getExternalStorageDirectory().getAbsolutePath() +
File.separator + getString(R.string.app_name);
File folder = new File(Environment.getExternalStorageDirectory().getAbsolutePath()
,getString(R.string.app_name));
I have tried both mkdirs and mkdir and
-Environment.getExternalStorageDirectory().getAbsolutePath()
-getExternalStorageDirectory().getAbsolutePath()
-Environment.getExternalStorageDirectory()
-getExternalStorageDirectory()
The permission exists in the manifest and is accepted.
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
The path the the System.out prints is "/storage/emulated/0/appname"
I don't know what else to try. Similar code works for other applications. Min API is 23.
Any help is much appreciated.
I suggest you to try Context.getExternalFilesDir() instead of Environment.getExternalStorageDirectory()
If your test device runs Android 10/Q or API Level 29+: there are a few permission changes with storing data to media folder. You can store your data without problems to your app folder, but if you remove the app the images are gone too.
The easiest way is to add android:requestLegacyExternalStorage="true" in the manifest under application but it is more like a work around and it will probably not be supported for long.
Search for "store image android 10" here and you find the right way for you.

Unable to write to the Internal Storage

Please have a look at the following code
File folder = new File("/Main Note/Sub Notes/"+dateStr+"/");
File file = new File(folder+name.getText().toString()+".txt");
try
{
if(!folder.exists())
{
folder.mkdirs();
}
FileOutputStream outputStream = openFileOutput(file.getName(),Context.MODE_WORLD_WRITEABLE);
outputStream.write(spokenText.getBytes());
outputStream.flush();
outputStream.close();
Toast.makeText(VoiceNotes.this, "Data Successfully written to: "+file.getAbsolutePath(), Toast.LENGTH_LONG).show();
}
catch(IOException io)
{
Toast.makeText(VoiceNotes.this, "Error in Writing to SD", Toast.LENGTH_LONG).show();
}
Here I am trying to write data to the internal memory. This has no errors, displays the data has been written successfully.
But when I navigate to the Internal SD in phone, I don't see any folder or file it created! I guess I have done something wrong, this is the first time I am writing to the internal storage in Android.
File folder = new File(context.getFilesDir(),"/MyFolder/");
files will be created in "/data/data/app.package/files/...". But you can see them only if device was rooted
You want to access the path returned by getExternalStorageDirectory() as described here.

Getting the contents of a class file in Android

The problem I am facing is that I need to access the contents of a .class file inside my application to send it to another device. (This class is not known by the target device at compilation time so I cannot just send an instance as it will ClassNotFoundException me).
I have successfully solved this with two PC devices by sending the byte array of the class file, but I cannot seem to get the path to the class file in Android. I guess because they are actually inside the classes.dex file. Is there any way to access these .class files inside classes.dex?
This is the code I use to get the class file contents in a PC
try {
this.className = c.getName();
String pathToClass = c.getName().replaceAll("\\.", File.separator) + ".class";
InputStream is = c.getClassLoader().getResourceAsStream(pathToClass);
this.classContents = IOUtils.toByteArray(is);
} catch (IOException e) {
e.printStackTrace();
}
Thank you for your cooperation.

Error when reading a Pdf file from internal memory?

I am trying to read a pdf file from internal memory of the device my code is here:
File pdfFile;
pdfFile=new File("data/data/com.myapp.main/app_c"+md+"/c"+md+".pdf");
if(pdfFile.exists())
{
try{
FileOutputStream fileOutput = openFileOutput(pdfFile.toString(), Context.MODE_WORLD_READABLE);
}
catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
Uri path = Uri.fromFile(pdfFile);
Intent pdfIntent = new Intent(Intent.ACTION_VIEW);
pdfIntent.setDataAndType(path, "application/pdf");
pdfIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
try
{
startActivity(pdfIntent);
}
catch(ActivityNotFoundException e)
{
Toast.makeText(ChTable.this, "No Application available to view pdf", Toast.LENGTH_LONG).show();
}
But the Pdf reader shows an Error -File not supported-Or File Not found .But I have checked that file is there at this location.I have also changed the permission to the file ,but still the same result. Would Someone help me detect and solve my problem ?
you can use PDFBox library to read data from pdf -
http://pdfbox.apache.org/
data/data/com.myapp.main/app_c"+md+"/c"+md+".pdf"
Is this path correct?
I am guessing the path should be like below.
data/data/com/myapp/main/app_c"+md+"/c"+md+".pdf"
You should be using one of the apis to get the application's files directory rather than assuming what the path will be.
Your actual problem however is most likely that any file you create there is probably private to the owning application, so the PDF reader app lacks permission to access it.
Solutions to that would be to change the file mode to world readable, or more commonly to put the file on the external storage (ie, "sdcard") rather than the internal memory, as that does not (to date) have a concept of permissions. Though it's worth remembering that a device isn't guaranteed to have an external storage, or for it to be accessible at any given point in time even if it exists.

Hosting an executable within Android application

I am working on an Android application that depends on an ELF binary:
our Java code interacts with this binary to get things done. This
runtime needs to be started and terminated on Application startup and
application exit / on demand.
Questions:
I am assuming that we will be able to execute this binary using the
Runtime.exec() API. Is there any constraints as to where I
need to be putting my library in the folder structure? How would the system runtime locate this executable? Is there some sort of class path setting?
Since the application has dependencies on this Runtime, I was
thinking of wrapping it around a service so that it can be started or
stopped as required. What is the best way to handle such executables
in Android project?
What are other alternatives, assuming that I do not have source code for this executable?
Please advice.
Thanks.
1) No, there should be no constrains, besides those that access system files and thus require root. The best place would be straight to /data/data/[your_package_name] to avoid polluting elsewhere.
2) A very thorough discussion about compiling against native libraries can be found here: http://www.aton.com/android-native-libraries-for-java-applications/ . Another option is a cross-compiler for arm (here is the one used to compile the kernel, it's free: http://www.codesourcery.com/sgpp/lite/arm ). If you plan to maintain a service that executes your cammand, be warned that services can be stopped and restarted by android at any moment.
3) Now, if you don't have the source code, I hope that your file is at least compiled as an arm executable. If not, I don't see how you could even run it.
You will execute the file by running the following commands in your java class:
String myExec = "/data/data/APPNAME/FILENAME";
Process process = Runtime.getRuntime().exec(myExec);
DataOutputStream os = new DataOutputStream(process.getOutputStream());
DataInputStream osRes = new DataInputStream(process.getInputStream());
I know nothing about your executable, so you may or may not need to actually get the inputStream and outputStream.
I am assuming that running adb to push the binary file is out of the question, so
I was looking for a neat way to package it. I found a great post about including an executable in your app. Check it out here:
http://gimite.net/en/index.php?Run%20native%20executable%20in%20Android%20App
The important part is this one (emphasis mine):
From Android Java app, using assets folder
Include the binary in the assets folder.
Use getAssets().open(FILENAME) to get an InputStream.
Write it to /data/data/APPNAME (e.g. /data/data/net.gimite.nativeexe), where your application has access to write files and make it executable.
Run /system/bin/chmod 744 /data/data/APPNAME/FILENAME using the code above.
Run your executable using the code above.
The post uses the assets folder, insted of the raw folder that android suggests for static files:
Tip: If you want to save a static file in your application at compile time, save the file in your project res/raw/ directory. You can open it with openRawResource(), passing the R.raw. resource ID. This method returns an InputStream that you can use to read the file (but you cannot write to the original file).
To access the data folder, you can follow the instructions here:
http://developer.android.com/guide/topics/data/data-storage.html#filesInternal
Also, there's the File#setExecutable(boolean); method that should works instead of the shell command.
So, putting everything together, I would try:
InputStream ins = context.getResources().openRawResource (R.raw.FILENAME)
byte[] buffer = new byte[ins.available()];
ins.read(buffer);
ins.close();
FileOutputStream fos = context.openFileOutput(FILENAME, Context.MODE_PRIVATE);
fos.write(buffer);
fos.close();
File file = context.getFileStreamPath (FILENAME);
file.setExecutable(true);
Of course, all this should be done only once after installation. You can have a quick check inside onCreate() or whatever that checks for the presence of the file and executes all this commands if the file is not there.
Let me know if it works. Good luck!
Here is a complete guide for how to package and run the executable. I based it on what I found here and other links, as well as my own trial and error.
1.) In your SDK project, put the executable file in your /assets folder
2.) Programmatically get the String of that files directory (/data/data/your_app_name/files) like this
String appFileDirectory = getFilesDir().getPath();
String executableFilePath = appFileDirectory + "/executable_file";
3.) In your app's project Java code: copy the executable file from /assets folder into your app's "files" subfolder (usually /data/data/your_app_name/files) with a function like this:
private void copyAssets(String filename) {
AssetManager assetManager = getAssets();
InputStream in = null;
OutputStream out = null;
Log.d(TAG, "Attempting to copy this file: " + filename); // + " to: " + assetCopyDestination);
try {
in = assetManager.open(filename);
Log.d(TAG, "outDir: " + appFileDirectory);
File outFile = new File(appFileDirectory, filename);
out = new FileOutputStream(outFile);
copyFile(in, out);
in.close();
in = null;
out.flush();
out.close();
out = null;
} catch(IOException e) {
Log.e(TAG, "Failed to copy asset file: " + filename, e);
}
Log.d(TAG, "Copy success: " + filename);
}
4.) Change the file permissions on executable_file to actually make it executable. Do it with Java calls:
File execFile = new File(executableFilePath);
execFile.setExecutable(true);
5.) Execute the file like this:
Process process = Runtime.getRuntime().exec(executableFilePath);
Note that any files referred to here (such as input and output files) must have their full path Strings constructed. This is because this is a separate spawned process and it has no concept of what the "pwd" is.
If you want to read the command's stdout you can do this, but so far it's only working for me for system commands (like "ls"), not the executable file:
BufferedReader reader = new BufferedReader(
new InputStreamReader(process.getInputStream()));
int read;
char[] buffer = new char[4096];
StringBuffer output = new StringBuffer();
while ((read = reader.read(buffer)) > 0) {
output.append(buffer, 0, read);
}
reader.close();
process.waitFor();
Log.d(TAG, "output: " + output.toString());
For executing binary file starting from Android 10 it's only possible from read-only folder. It means that you should pack binary with your app. Android doc
Put android:extractNativeLibs="true" into AndroidManifest;
Put your binary to src/main/resources/lib/* directory, where * – stands for architecture of CPU, for instance armeabi-v7a;
Use code like this for executing:
private fun exec(command: String, params: String): String {
try {
val process = ProcessBuilder()
.directory(File(filesDir.parentFile!!, "lib"))
.command(command, params)
.redirectErrorStream(true)
.start()
val reader = BufferedReader(
InputStreamReader(process.inputStream)
)
val text = reader.readText()
reader.close()
process.waitFor()
return text
} catch (e: Exception) {
return e.message ?: "IOException"
}
}
Here is discussion with answer from android team on reddit.
I've done something like this using the NDK. My strategy was to recompile the program using the NDK and write some wrapper JNI code that called into the program's main function.
I'm not sure what the lifecycle of NDK code is like. Even services that are intended to be long-running can be started and stopped by the system when convenient. You would probably have to shutdown your NDK thread and restart it when necessary.

Categories