Android: reading file selected in Google Drive file picker - android

In my app I need to read a settings file, and that settings file can either be on local storage or on the user's Google Drive storage (with Google Drive app installed).
The following opens up a file chooser, first asking the user which file picker to use, including the option of using the Google Drive file picker:
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.setType("file/*");
intent.addCategory(Intent.CATEGORY_OPENABLE);
Intent chooserIntent = Intent.createChooser(intent, "Open file");
startActivityForResult(chooserIntent, REQUEST_CODE_FILE_PICKER);
In my onActivityResult() function, if the user opted to use a file picker to choose a local file, then I already know how to successfully get the file path and read the file. But if the user instead used the Google Drive file picker to choose a remote file, how do I access the file that the user selected?
These are the bare bones of my onActivityResult() function:
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == REQUEST_CODE_FILE_PICKER && resultCode == RESULT_OK) {
if (LOCAL FILE) {
Uri uri = data.getData();
File myFile = new File(uri.getPath());
String filePath = myFile.getAbsolutePath();
// now read file store at 'filePath' from local storage (this part is fine)
} else if (GOOGLE DRIVE FILE) {
// what do I do here to retrieve the selected file?
}
}
super.onActivityResult(requestCode, resultCode, data);
}
When selecting a Google Drive file using the Google Drive file picker, the selected file seems to be downloaded (but to where??) but then nothing happens... how do I access the downloaded file to use in my app?
And in onActivityResult() above, how do I tell if the selected file is actually a Google Drive file, so that I can treat it accordingly? i.e. what is the test for if (GOOGLE DRIVE FILE)?

I believe you're using OpenFileActivityBuilder when Drive is selected as the file picker. It will return a EXTRA_RESPONSE_DRIVE_ID which is the Drive ID of the selected file. After this, you just need to call DriveFile.open to open the said file. This can be your flag to check if you selected a Drive File picker or not.
I cannot answer where the file is downloaded, but my best guess for it is its inside your data/ of the application (which you most likely don't have access to)

Related

Android: Converting a URI to File

I'm working on an app that allows users to create backup files and then re-import them with a file chooser. I export the file using the following code:
Intent intent = new Intent(Intent.ACTION_CREATE_DOCUMENT);
intent.setType("application/*");
startActivityForResult(intent, Constants.FILE_CHOOSER);
The code returns a URI in onActivityResult():
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if(requestCode == Constants.FILE_CHOOSER) {
Uri uri = data.getData();
}
I have a File that references a file within my app's local storage that contains data. I would simply like to take the file from the app's internal storage and save it to whatever directory the user selected. I can't get it to work. How do I convert the returned Uri into a File so I can write data more easily?
I would simply like to take the file from the app's internal storage and save it to whatever directory the user selected
The user didn't select a directory. The user is creating a document, where the Uri points to that document.
How do I convert the returned Uri into a File so I can write data more easily?
You don't, any more than you convert an HTTPS URL into a File so you can write data more easily.
Use ContentResolver and openOutputStream() to open an OutputStream on the (empty) document created by ACTION_CREATE_DOCUMENT and identified by the returned Uri. Then, use standard Java I/O to copy the bytes from your file (e.g., via a FileInputStream) to the OutputStream.

Saving files to SD card on Android Lollipop

Android 5 introduce new API for working with SD-card. If you want to write files into some directory on the SC-card, y need get access to it.
As far as I know, it could be done in this way:
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE);
startActivityForResult(intent, 42);
and then:
public void onActivityResult(int requestCode, int resultCode, Intent resultData) {
if (resultCode == RESULT_OK) {
Uri treeUri = resultData.getData();
getActivity().getContentResolver().takePersistableUriPermission(treeUri,
Intent.FLAG_GRANT_READ_URI_PERMISSION |
Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
}
}
This code launch folder picker, and when folder is picked it requires permissions on the folder by it's Uri.
But is it possible to get permissions on exact directory by it's path? Without using folder picker. I meant that I know directory, which I want get access, and I don't want to launch Folder Picker, because it will confuse user.
How to open DocumentFile without user interaction?
It's impossible. User should choose directory using android's file picker. The only way to get access to folder is using:
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE);
startActivityForResult(intent, 42);
Because file is provided by Storage Access Framework DocumentsProvider. Actually it could return some Uri from 3-rd party app, which is not real file, but some entity, which 3-rd party app present as file.

Intent.ACTION_GET_CONTENT with Google Drive

I have the following intent:
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.setType("text/*");
startActivityForResult(intent, DBOpenHelper.REQUEST_CODE_RESTORE);
The intent allows the user to select a text file from a number of options. It works fine with local storage and Dropbox for example, and in both cases I can get the file from as follows:
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if ((requestCode == DBOpenHelper.REQUEST_CODE_RESTORE)
&& (resultCode == Activity.RESULT_OK)) {
restoreFile = new File(data.getData().getPath());
restoreFileName = restoreFile.getName();
}
}
Local storage works fine and Dropbox will copy a local copy of the file to the SD card and return the correct path. The problem is that if the user to selects files from Google Drive. When they use Google Drive, data.getData().getPath() returns something like: "/document/acc=1;doc=195" instead of returning the path to the locally stored file. How do I have Google Drive download the file and return the path? I want to allow the user to select from any file storage option they have available.
Google Drive may or may not have downloaded the file locally when the user picks the file. However, in all cases, you can access the contents of the file via getContentResolver().openInputStream(data.getData()) - note that openInputStream() also supports local files and can and should be used in other cases as well.

Storage Access Framework as a "Private" (local-only) Folder/File Picker?

My ultimate goal is to allow the user to select a folder to save a file to - the file is a video file that will be created at some point after the user has chosen the destination.
I am simply using the storage access framework picker to allow them to select a location for it to be saved in.
First of all, is there a way to allow a user to select only a folder (and not a file/filename)?
The best I can do right now is use the ACTION_CREATE_DOCUMENT Intent in order to get a save location, however I do not really want to specify the filename in the SAF picker (this will be done back in the app)...
Secondly, after reading the Storage Access Framework documentation, and cobbling together some bits from a few code samples, I've got a working DocumentsProvider which almost does what I want - which is to allow the user to browse their external storage (SD Card) directories for a suitable place to save a video file - by adding my own root which points to Environment.getExternalStorageDirectory() to the queryRoots() method.
However, what I really want is for that to be my only root (at the minute I've also got Drive, Downloads etc.).
Is it possible to remove/hide other roots so it essentially becomes an application-specific file picker?
Or even show local storage only (perhaps the Root.FLAG_LOCAL_ONLY flag can help)?
Thanks!
API 21 supports Intent.ACTION_OPEN_DOCUMENT_TREE. This allows you to select the location once and then you can use the provided URI to manipulate its content.
private static final int LOCATION_CHOOSER_REQ_CODE = 4;
public void chooseLocation() {
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE);
startActivityForResult(intent, LOCATION_CHOOSER_REQ_CODE);
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == LOCATION_CHOOSER_REQ_CODE && resultCode == Activity.RESULT_OK) {
if (data != null) {
Uri uri = data.getData(); // Use this URI to access files
}
}

Open file picker form my Android activity

I'm making an Android app which stores some downloaded pdf files inside the device's SD card.
Everything works fine, but now I want to add a function to just pop up the default android file/folder browser showing the directory where my app stores all the PDF (with subdirectories in it) so that the user sees where his documents are stored and can easily browse them.
I've been throught many other SO questions and forum posts, but it seems this can only be done for music/images/contacts/etc. basically those file types which have a 'dedicated browsing system' but not with general file browsing.
I'm actually using this code:
File file = new File("/sdcard/MySorgenia/Documenti/");
Intent intent = new Intent();
intent.setAction(android.content.Intent.ACTION_VIEW);
Uri data = Uri.fromFile(file);
String type = "*/*";
intent.setDataAndType(data, type);
startActivity(intent);
But this will show me a "Choose the application to complete your action" dialog with many applications such as "Music" "Gallery" etc, but no general purpose one.
Thanks!
Because In android there is no any native application which you can use as a File Explorer and responds to Intent type "*/*"
Implement your own File-Explorer Code for this purpose..
Look at these two Links..
openintents
Android-File-Explore
public void loadfile()
{
private static final int gallery=12;
private static final String type="*/*";
Intent i=new Intent(Intent.ACTION_GET_CONTENT);
i.setType(type);
startActivityForResult(Intent.createChooser(i,"select file"), gallery);
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == gallery && resultCode == RESULT_OK && data != null) {
Uri uploadfileuri = data.getData();
File file = new File(uploadfileuri.getPath());
}
}
Since Android 4.4 KitKat (API level 19), there is an Android built-in file picker: your app invokes the ACTION_OPEN_DOCUMENT and/or ACTION_CREATE_DOCUMENT intent and receives the files returned by document providers. More info about that can be found here:
Open files using storage access framework | Android Developers
Depending on where you want to store files, you may need to request permission:
Request App Permissions | Android Developers
Here is a how to:
An Android Storage Access Framework Example - Techtopia.
And a great working example is Ian Lake's Local Storage. Its source can be found on GitHub:
https://github.com/ianhanniballake/LocalStorage
And the app can be downloaded from Google Play:
https://play.google.com/store/apps/details?id=com.ianhanniballake.localstorage
Most android distributions do not come with a default file browser, and the behavior you noticed is the default android behavior. If there's any good third party file browser installed, it will automatically show up in that list. However it is not guaranteed that every end user will have a file browser installed. A general purpose fragment-widget can be created for this (and probably shared with others).
Look at this file picker, it's the best one I found:

Categories

Resources