Trying to convert a URI
that I got from Intent.ACTION_GET_CONTENT
, input stream opens fine for local files, but for URI
from drive (/document/acc=1;doc=4089
) I get a FileNotFoundException
, saying the file is "virtual". How can I open an input stream for such files?
Getting the URI:
Intent i = new Intent(Intent.ACTION_GET_CONTENT);
i.setType("*/*"); //No I18N
try{
startActivityForResult(Intent.createChooser(i, "Pick a file"), REQUEST_CODE_UPLOAD_FILE_FOR_IMPORT);
}catch (android.content.ActivityNotFoundException ex){
Log.e("Error","FileManager not found!");
}
and
importedFileUri = data.getData();
System.out.println("URI path: "+importedFileUri.getPath()+" "+importedFileUri.getEncodedPath());
System.out.println("URI Scheme "+importedFileUri.getScheme());
System.out.println("URI Authority :"+importedFileUri.getAuthority());
System.out.println("URI Fragment :"+importedFileUri.getFragment());
System.out.println("URI path segments : ");
for(String str : importedFileUri.getPathSegments()){
System.out.println("\t" +str );
}
String ext;
if (importedFileUri.getScheme().equals(ContentResolver.SCHEME_CONTENT)) {
final MimeTypeMap mime = MimeTypeMap.getSingleton();
ext = mime.getExtensionFromMimeType(mActivity.getContentResolver().getType(importedFileUri));
System.out.println("resolved type (content) : "+ mActivity.getContentResolver().getType(importedFileUri));
} else {
ext = MimeTypeMap.getFileExtensionFromUrl(Uri.fromFile(new File(importedFileUri.getPath())).toString());
System.out.println("resolved type (other) : "+ Uri.fromFile(new File(importedFileUri.getPath())).toString());
}
Getting the inputstream:
InputStream is = null;
try {
is = contentResolver.openInputStream(importedFileUri);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
Result:
URI path: /document/acc=1;doc=4089 /document/acc%3D1%3Bdoc%3D4089
GetString - content://com.google.android.apps.docs.storage/document/acc%3D1%3Bdoc%3D4089
URI Scheme content
URI Authority :com.google.android.apps.docs.storage
URI Fragment :null
URI path segments :
document
acc=1;doc=4089
resolved type (content) : application/vnd.google-apps.spreadsheet
ext : null
The Exception:
java.io.FileNotFoundException: File is virtual: acc=1;doc=4089
Check if File at URI is Virtual or not:
private static boolean isVirtualFile(Uri uri) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
if (!DocumentsContract.isDocumentUri(activity, uri)) {
return false;
}
Cursor cursor = activity.getContentResolver().query(
uri,
new String[]{DocumentsContract.Document.COLUMN_FLAGS},
null, null, null);
int flags = 0;
if (cursor.moveToFirst()) {
flags = cursor.getInt(0);
}
cursor.close();
return (flags & DocumentsContract.Document.FLAG_VIRTUAL_DOCUMENT) != 0;
} else {
return false;
}
}
Get Input stream from Virtual file with this:
private static InputStream getInputStreamForVirtualFile(Uri uri, String mimeTypeFilter)
throws IOException {
ContentResolver resolver = activity.getContentResolver();
String[] openableMimeTypes = resolver.getStreamTypes(uri, mimeTypeFilter);
if (openableMimeTypes == null ||
openableMimeTypes.length < 1) {
throw new FileNotFoundException();
}
return resolver
.openTypedAssetFileDescriptor(uri, openableMimeTypes[0], null)
.createInputStream();
}
Overall
if (isVirtualFile(sourceuri)) {
input = getInputStreamForVirtualFile(sourceuri, getMimeType(name));
} else {
input = activity.getContentResolver().openInputStream(sourceuri);
}
More information here.
Since an app cannot directly open a virtual file by using the openInputStream() method, your app does not receive any virtual files if you include the CATEGORY_OPENABLE category in the ACTION_OPEN_DOCUMENT intent.
To open virtual files, your client app needs to include special logic to handle them. If you want to get a byte representation of the file—to preview the file, for example—you need to request for an alternate MIME type from the documents provider.
To get a URI for a virtual document in your app, first you create an Intent to open the file picker UI, like the code shown previously in Seach for documents.
private boolean isVirtualFile(Uri uri) {
if (!DocumentsContract.isDocumentUri(this, uri)) {
return false;
}
Cursor cursor = getContentResolver().query(
uri,
new String[] { DocumentsContract.Document.COLUMN_FLAGS },
null, null, null);
int flags = 0;
if (cursor.moveToFirst()) {
flags = cursor.getInt(0);
}
cursor.close();
return (flags & DocumentsContract.Document.FLAG_VIRTUAL_DOCUMENT) != 0;
}
After you verify that the file is virtual, you can then coerce the file into an alternative MIME type such as an image file. The following code snippet shows how to check whether a virtual file can be represented as an image, and if so, gets an input stream from the virtual file.
private InputStream getInputStreamForVirtualFile(Uri uri, String mimeTypeFilter)
throws IOException {
ContentResolver resolver = getContentResolver();
String[] openableMimeTypes = resolver.getStreamTypes(uri, mimeTypeFilter);
if (openableMimeTypes == null ||
openableMimeTypes.length < 1) {
throw new FileNotFoundException();
}
return resolver
.openTypedAssetFileDescriptor(uri, openableMimeTypes[0], null)
.createInputStream();
}
The description and code snippet are taken from the android docs. Check out the link and reference to learn more about Storage Access Framework.
Youtube
Reference
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With