Reputation: 25
Here's what I would like to do in my app:
So I'd like to get real path to file and store it. The user will only be allowed to get files from internal/external storage so, as I assume, the real path will always exist. I've been looking for solutions and pretty much everyone asks only about images/audio/video and uses MediaStore in their solutions (and I, as of now, have no idea what this is, and I can get Uri without using it). I'd like a solution that would work with any type of file, if that's possible.
Here's how I'm getting Uri:
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.addFlags(FLAG_GRANT_READ_URI_PERMISSION);
intent.setType("*/*");
startActivityForResult(Intent.createChooser(intent, "Choose File"), 1);
and I'm storing the received information in onActivityResult
method.
So i get Uri and store it as a string which looks like, for example, content://com.android.providers.downloads.documents/document/4588
. How do I convert it to a real filepath?
Upvotes: 0
Views: 1471
Reputation: 2334
Sharing my Fileutils file from one of my projects
public class FileUtils {
public static String getFilePath(Context context, Uri uri) throws URISyntaxException {
String selection = null;
String[] selectionArgs = null;
// Uri is different in versions after KITKAT (Android 4.4), we need to
if (Build.VERSION.SDK_INT >= 19 && DocumentsContract.isDocumentUri(context
.getApplicationContext(), uri)) {
if (isExternalStorageDocument(uri)) {
final String docId = DocumentsContract.getDocumentId(uri);
final String[] split = docId.split(":");
return Environment.getExternalStorageDirectory() + "/" + split[1];
} else if (isDownloadsDocument(uri)) {
final String id = DocumentsContract.getDocumentId(uri);
uri = ContentUris.withAppendedId(
Uri.parse("content://downloads/public_downloads"), Long.valueOf(id));
} else if (isMediaDocument(uri)) {
final String docId = DocumentsContract.getDocumentId(uri);
final String[] split = docId.split(":");
final String type = split[0];
if ("image".equals(type)) {
uri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
} else if ("video".equals(type)) {
uri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
} else if ("audio".equals(type)) {
uri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
}
selection = "_id=?";
selectionArgs = new String[]{
split[1]
};
} else if (isGoogleDriveFile(uri)) {
String mimeType = context.getContentResolver().getType(uri);
Cursor returnCursor =
context.getContentResolver().query(uri, null, null, null, null);
int nameIndex = returnCursor.getColumnIndex(OpenableColumns.DISPLAY_NAME);
int sizeIndex = returnCursor.getColumnIndex(OpenableColumns.SIZE);
returnCursor.moveToFirst();
String fileName = returnCursor.getString(nameIndex);
Log.d("name", returnCursor.getString(nameIndex));
Log.d("size", Long.toString(returnCursor.getLong(sizeIndex)));
try {
InputStream inputStream = context.getContentResolver().openInputStream(uri);
File root = new File(Environment.getExternalStorageDirectory(), "WittyParrot");
root.mkdirs();
File file = new File(root, fileName);
copyStreamToFile(file, inputStream);
return Uri.fromFile(file).getPath();
} catch (FileNotFoundException e) {
e.printStackTrace();
} finally {
returnCursor.close();
}
}
}
if ("content".equalsIgnoreCase(uri.getScheme())) {
String[] projection = {
MediaStore.Images.Media.DATA
};
Cursor cursor = null;
try {
cursor = context.getContentResolver()
.query(uri, projection, selection, selectionArgs, null);
int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
if (cursor.moveToFirst()) {
return cursor.getString(column_index);
}
} catch (Exception e) {
}
} else if ("file".equalsIgnoreCase(uri.getScheme())) {
return uri.getPath();
}
return null;
}
public static boolean isExternalStorageDocument(Uri uri) {
return "com.android.externalstorage.documents".equals(uri.getAuthority());
}
public static boolean isDownloadsDocument(Uri uri) {
return "com.android.providers.downloads.documents".equals(uri.getAuthority());
}
public static boolean isMediaDocument(Uri uri) {
return "com.android.providers.media.documents".equals(uri.getAuthority());
}
public static boolean isGoogleDriveFile(Uri uri) {
return "com.google.android.apps.docs.storage".equals(uri.getAuthority());
}
public static void copyStreamToFile(File file, InputStream input) {
try {
OutputStream output = new FileOutputStream(file);
try {
byte[] buffer = new byte[4 * 1024]; // or other buffer size
int read;
while ((read = input.read(buffer)) != -1) {
output.write(buffer, 0, read);
}
output.flush();
} catch (IOException e) {
e.printStackTrace();
} finally {
output.close();
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
input.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
Upvotes: 2
Reputation: 1007534
The user will only be allowed to get files from internal/external storage
Not according to your code. The user can use anything that supports ACTION_GET_CONTENT
. There is no requirement for ACTION_GET_CONTENT
implementations to be limited to external storage, and you cannot access internal storage from other apps using the filesystem.
If you are only willing to work with external storage, use a file chooser library, not ACTION_GET_CONTENT
or ACTION_OPEN_DOCUMENT
.
I'd like a solution that would work with any type of file, if that's possible.
How do I convert it to a real filepath?
Upvotes: 0