Intent.ACTION_OPEN_DOCUMENT and app-private files - android

I am working on getting my application over to scoped storage. One feature of the app is that it contains document templates stored as application assets. At run time, they are copied to local storage, here: (code is Java)
String path = Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_DOWNLOADS)
.getAbsolutePath() +
File.separator + "Templates";
Since these files are private to the app, I am happy to put them in
String path = context.getFilesDir()
.getAbsolutePath() +
File.separator + "Templates";
But I'm also planning to do this (or something like it) for the user to browse for files:
Intent newIntent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
newIntent.addCategory(Intent.CATEGORY_OPENABLE);
newIntent.setType("*/*");
startActivityForResult(newIntent, 0);
My question is, how can I get ACTION_OPEN_DOCUMENT to include as browsable the place where I've put my templates?

The only way to expose private files from your app in the system file picker is to create a custom DocumentsProvider. This would add your app as a source of files that the user can pick from.
Note that with this approach, there is no requirement to copy files to local storage at all - your code for opening a document can use AssetManager's openFd() method along with getParcelFileDescriptor() to directly pass that through to the calling app without going through the File APIs at all.

Related

How can I rename a folder I created in the shared storage?

My app creates folders in the shared storage (DCIM/ and Pictures/ directories), which I want to be able to rename afterwards.
I save the images using MediaStore, the folders are created automatically.
Android Q (and above) already takes care of creating the folders if
they don’t exist. The example is hard-coded to output into the
DCIM folder. If you need a sub-folder then append the sub-folder name as next:
final String relativeLocation = Environment.DIRECTORY_DCIM + File.separator + “YourSubforderName”;
https://stackoverflow.com/a/56990305/10226383
I just can't seem to figure out how to do it, is that even possible with scoped storage, do I need to use MediaStore or SAF?
I know before the change to scoped storage you could do it this way:
File oldfolder = new File("path of the old folder","old name");
File newfolder = new File("path of the new folder","new name");
oldfolder.renameTo(newfolder);
If someone could point me in the right direction I would be really grateful!

Android app - providing *.kml with app or downloading it? (how to provide data with app)

I have made an app that works ok, but only for ideal case of downloading .kml to /sdcard/download/.kml.
I would like to make it proper. So the current code is:
public void dwnldKmlKorculaOrlandusa(View v)
{
Intent dwnldKmlKorculaOrlandusa = new Intent();
dwnldKmlKorculaOrlandusa.setAction(Intent.ACTION_VIEW);
dwnldKmlKorculaOrlandusa.setData(Uri.parse("http://www.visitkorcula.eu/downloads/bike-trails/korcula-orlandusa.kml"));
startActivity(dwnldKmlKorculaOrlandusa);
}
public void openKmlKorculaOrlandusa(View v)
{
Intent openKmlKorculaOrlandusa = new Intent();
openKmlKorculaOrlandusa.setAction(Intent.ACTION_VIEW);
File kmlKorculaOrlandusa = new File(Environment.getExternalStorageDirectory().getPath() + File.separator + "download" + File.separator + "korcula-orlandusa.kml"); //"/sdcard/download/korcula-orlandusa.kml"
openKmlKorculaOrlandusa.setDataAndType(Uri.fromFile(kmlKorculaOrlandusa), "application/vnd.google-earth.kml+xml");
startActivity(openKmlKorculaOrlandusa);
}
The app downloads *.kml from link (ideally, if it's the older Maps on phone it opens kml in it than) to download folder. On other click it opens it with app that you select (preferably Orux maps).
How to make this proper -> download to specific location and than running it from there?
Or even better, how to provide *.kml's with app and that app then can run kml without need of internet, just calling it from specific location?
If you kml is not going to change often you can package it with your apk by putting it in the assets folder of your project.
Then you can copy the kml file to the desired directory. take a look at How to copy files from 'assets' folder to sdcard?
You can place any file in your assets folder. You can then get an InputStream of the file like so:
Context.getAssets().open("myKml.kml")

load somefile.html file from internal storage to a webview of an app

I have a file in the internal storage of my tablet. /myfolder/subfolder/index.html. How can i load this into a webview of an app.
i have tried
webview.loadURL("file:///myfolder/subfolder/index.html");
but it is not giving the expected result. it says web page not available.
I know how to load from the asset folder or from the web/internet. but i need to load local file into webview. is it possible.?
File file = new File("/data/data/packagename/foldername/");
webView.loadUrl("file:///" + file);
I was able to solve my problem by using the following as path:
webview.loadURL("file:///mnt/sdcard/myfolder/subfolder/index.html");
An app cannot access data from the Internal storage stored by another app. Permissions are applied to internal storage that make data written by an application not accessible outside of that application (your app cannot read anything written by another app).
So, if you are accessing a file that is not created by your app, AFAIK, you cannot have access to it.
BTW, you could access the file from the internal storage as below,
webview.loadURL("file:///data/data/com.yourproject.example/files/index.html");
Put your html files in asset folder access the page like given below.
webview.loadURL("file:///"+mContext.getFilesDir()+"/myfolder/subfolder/index.html");
you have to mention the android asset while accessing html pages in android assets.
File gameDir = new File("/data/data/" + getActivity().getPackageName() + "/games");
gameDir.mkdirs();
// Create and execute the background task.
mTask = new DownloadTask();
mTask.execute("https://github.com/gabrielecirulli/2048/archive/master.zip", "/data/data/" + getActivity().getPackageName() + "/games/2048.zip");
mWebView.getSettings().setJavaScriptEnabled(true);
Toast.makeText(MainActivity.this, path+"/index.html", Toast.LENGTH_SHORT).show();
mWebView.loadUrl("file:///data/data/com.example.zipfiledownload/games/2048-master/index.html");

android data save directories

My application is mostly c++ (using NDK) so I use fopen, fwrite, etc. standard functions to create and game save files and write into them.
When I use fopen("game.sav", "wb"), it appears that it's being created at path
/data/user/10/com.my.game/files/game.sav.
My app is multi-user. So I want to have a separated folders where users store their save-files. And instead of the path above I'd like to have paths like
/data/user/10/com.my.game/files/user0/game.sav,
/data/user/10/com.my.game/files/user1/game.sav, etc
My app's frontend is in Java, and when new user is being registered, I want to create a folder /data/user/10/com.my.game/files/user0/. But I don't know how to do it, because
final File newDir = context.getDir("user0", Context.MODE_PRIVATE);
results in path being created at /data/user/10/com.my.game/app_user0 that's a different path.
It is possible to create folders at /data/user/10/com.my.game/files/ and how ?
Simple way to do it, this code you can change it suit many conditions. If you know that your path is different from what getFilesDir() gets you then you can create a File first of all by using a path that you know and the last 2 lines of code will still be same.
File file = this.getFilesDir(); // this will get you internal directory path
Log.d("BLA BLA", file.getAbsolutePath());
File newfile = new File(file.getAbsolutePath() + "/foo"); // foo is the directory 2 create
newfile.mkdir();
And if you know the path to "files" directory:
File newfile2 = new File("/data/data/com.example.stackoverflow/files" + "/foo2");
newfile2.mkdir();
Both code works.
Proof of Working:

Accessing an app's project files on the Android platform

So in my Eclipse android project I have a pdf file that I'd like to open, I looked up the standard address on the android developer's page and I came up with this pointer:
File file = new File("Android/data/com.alex.testing.app/res/raw/jazz.pdf");
where jazz.pdf is situated in res->raw in my eclipse project,
and com.alex.testing is my package name.
Still, when I try if(file.exists()) , the function returns false (on the emulator it goes to an else I've set up to display an error message)...
Sorry for the newbie question, but I'm really stuck with this :(.
put the file in assets folder and pick the file from there
Now use Context.getAssets().open("jazz.pdf") and pass the resulting InputStream into PDf parser library
Ok, to access resources from current application you can use something like,
Uri path = Uri.parse("android.resource://<you package>/raw/<your_file.pdf>");
OR
Uri path = Uri.parse("android.resource://" + getPackageName() + "/" R.raw.<your_file.pdf>);
But I have a doubt if you are trying to use this pdf file in your application then its OK, but If you want to view this file using any third party application then I think you can't do it.
Because external application can't access application's package resources file.
So better way it to put this file in /asset directory then copy it to any public access area then view that file from that path.
//if your are stored in SDcard your location would be
"data/data/com.alex.testing/res/raw/jazz.pdf"
//you read resources from raw folder thru the below code
InputStream inputStream = getResources().openRawResource(R.raw.jazz);
byte[] reader = new byte[inputStream.available()];

Categories

Resources