When I'm going select a file from all downloads folder and then getting file path from uri using content provider getting following permission denied issue below
Permission Denial: reading com.android.providers.downloads.DownloadProvider uri content://downloads/all_downloads/1092 from pid=31615, uid=10228 requires android.permission.ACCESS_ALL_DOWNLOADS, or grantUriPermission()
using following code
String[] contentUriPrefixesToTry = new String[]{
"content://downloads/public_downloads",
"content://downloads/my_downloads",
"content://downloads/all_downloads"
};
final String id = DocumentsContract.getDocumentId(uri);
String path = null;
for (String uriPath : contentUriPrefixesToTry) {
final Uri contentUri = ContentUris.withAppendedId(
Uri.parse(uriPath), Long.valueOf(id));
String lastPathSagment = uri.getLastPathSegment();
InputStream inputStream = context.getContentResolver().openInputStream(uri);
File file = new File(context.getCacheDir().getAbsolutePath() + "/" + lastPathSagment);
writeFile(inputStream, file);
path = file.getAbsolutePath();
if (path != null) {
return path;
}
}
I had the above issue, but found a solution. I was using ACTION_GET_CONTENT to pick a file from external storage, but it does not work in Android 7 and above. Someone guided me to use ACTION_OPEN_DOCUMENT to pick a file, and now it's working fine for me.
Intent PDF Picker:
if (Build.VERSION.SDK_INT <19) {
Intent pdfIntent = new Intent(Intent.ACTION_GET_CONTENT);
pdfIntent.setType("application/pdf");
startActivityForResult(pdfIntent, PICK_PDF);
} else {
Intent pdfIntent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
pdfIntent.setType("application/pdf");
pdfIntent.addCategory(Intent.CATEGORY_OPENABLE);
startActivityForResult(pdfIntent, PICK_PDF);
}
Code to get File Path:
if (isDownloadsDocument(uri)) {
String fileName = getFilePath(context, uri);
if (fileName != null) {
return String.format("%s/Download/%s", Environment.getExternalStorageDirectory().toString(), fileName);
}
String id = DocumentsContract.getDocumentId(uri);
if (id.startsWith("raw:")) {
id = id.replaceFirst("raw:", "");
File file = new File(id);
if (file.exists())
return id;
}
}
final Uri contentUri = ContentUris.withAppendedId(Uri.parse("content://downloads/public_downloads"), Long.valueOf(id));
return getDataColumn(context, contentUri, null, null);
}
Methods used in above code:
public static String getFilePath(Context context, Uri uri) {
Cursor cursor = null;
final String[] projection = { MediaStore.MediaColumns.DISPLAY_NAME };
try {
cursor = context.getContentResolver().query(uri, projection, null, null, null);
if (cursor != null && cursor.moveToFirst()) {
final int index = cursor.getColumnIndexOrThrow(MediaStore.MediaColumns.DISPLAY_NAME);
return cursor.getString(index);
}
} catch(Exception e) {
e.printStackTrace();
} finally {
if (cursor != null) {
cursor.close();
}
}
return null;
}
private static String getDataColumn(Context context, Uri uri, String selection, String[] selectionArgs) {
Cursor cursor = null;
final String column = "_data";
final String[] projection = { column };
try {
cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs, null);
if (cursor != null && cursor.moveToFirst()) {
final int column_index = cursor.getColumnIndexOrThrow(column);
return cursor.getString(column_index);
}
} finally {
if (cursor != null) {
cursor.close();
}
}
return null;
}
private static boolean isDownloadsDocument(Uri uri) {
return "com.android.providers.downloads.documents".equals(uri.getAuthority());
}
Your code is 'trying' to access that directory to see if it exists, and even open an inputstream to get the supposed File. If the directory doesn't exist Android will be displeased with you and tell you that you're not allowed to access that dir.
No need to request permission as the dir does not exist.
Related
To support Android 11 storage, I have implemented Scoped Storage - MediaStore API successfully. However, I ended up with one scenario which I am not sure how to resolve. Scenario is, When the Application is launched for the first time, we have created the Folder under Documents folder and able to read and write files into this folder without creating any duplicate folders. However, If I do Clear Data and re-login the Application, I am not able to fetch the folder which is already created and each time it is creating a new folder with duplicate name - Suffix as (2), (3) etc..,
Please find my code which I tired and also find the screenshots.
File folder = null;
String folderName = "Duration";
if(Build.VERSION.SDK_INT > Build.VERSION_CODES.Q) {
Uri contentUri = MediaStore.Files.getContentUri("external");
String filePath = FileUtils.readFileExternalStorage(contentUri,context,folderName).getPath();
if (!TextUtils.isEmpty(filePath) && FileUtils.isFileExisting(filePath)) {
folder = new File(filePath);
} else {
Uri uri = FileUtils.createFileExternalStorage(contentUri,context,folderName),Environment.DIRECTORY_DOCUMENTS);
Commons.print("URI "+uri.getPath());
folder = new File(FileUtils.getPath(context,uri));
}
if (!folder.exists()) {
folder.mkdirs();
}
} else {
folder = getStorageDir(folderName);
bmodel.deleteFiles(getStorageDir(folderName) + "/", filename);
}
File file = new File(folder, filename );
if(file.exists()) {
file.delete();
}
if (SynchronizationHelper.bcpJSONData != null) {
FileOutputStream outputStream;
try {
Commons.print("FilePath " + file.getPath());
outputStream = new FileOutputStream(file);//context.openFileOutput(filename, Context.MODE_PRIVATE);
outputStream.write(SynchronizationHelper.bcpJSONData.getBytes());
outputStream.close();
outputStream = null;
SynchronizationHelper.bcpJSONData = null;
} catch (Exception e) {
e.printStackTrace();
}
}
This is FileUtils class:
#RequiresApi(api = Build.VERSION_CODES.Q)
public static File readFileExternalStorage(Uri contentUri, Context context, String filename) {
final String selection = MediaStore.Files.FileColumns.DISPLAY_NAME + "=?";
final String[] selectionArgs = new String[] {filename};
return new File(getDataColumn(context,contentUri,selection,selectionArgs));
}
#RequiresApi(api = Build.VERSION_CODES.Q)
public static Uri createFileExternalStorage(Uri contentUri, Context context, String filename, String folder) {
ContentValues values = new ContentValues();
values.put(MediaStore.MediaColumns.DISPLAY_NAME, filename);
values.put(MediaStore.MediaColumns.RELATIVE_PATH, folder);
return context.getContentResolver().insert(contentUri, values);
}
public static String getDataColumn(Context context, Uri uri,
String selection, String[] selectionArgs) {
Cursor cursor = null;
final String column = "_data";
final String[] projection = { column };
try {
cursor = context.getContentResolver().query(uri, projection,
selection, selectionArgs, null);
if (cursor != null && cursor.moveToFirst()) {
final int index = cursor.getColumnIndexOrThrow(column);
return cursor.getString(index);
}
} finally {
if (cursor != null)
cursor.close();
}
return "";
}
#TargetApi(Build.VERSION_CODES.KITKAT)
#SuppressLint("NewApi")
public static String getPath(final Context context, final Uri uri) {
// check here to KITKAT or new version
final boolean isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;
// DocumentProvider
if (isKitKat && DocumentsContract.isDocumentUri(context, uri)) {
// ExternalStorageProvider
if (isExternalStorageDocument(uri)) {
final String docId = DocumentsContract.getDocumentId(uri);
final String[] split = docId.split(":");
final String type = split[0];
if ("primary".equalsIgnoreCase(type)) {
return Environment.getExternalStorageDirectory() + "/"
+ split[1];
}
}
// DownloadsProvider
else if (isDownloadsDocument(uri)) {
final String id = DocumentsContract.getDocumentId(uri);
final Uri contentUri = ContentUris.withAppendedId(
Uri.parse("content://downloads/public_downloads"),
Long.valueOf(id));
return getDataColumn(context, contentUri, null, null);
}
// MediaProvider
else if (isMediaDocument(uri)) {
final String docId = DocumentsContract.getDocumentId(uri);
final String[] split = docId.split(":");
final String type = split[0];
Uri contentUri = null;
if ("image".equals(type)) {
contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
} else if ("video".equals(type)) {
contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
} else if ("audio".equals(type)) {
contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
}
final String selection = "_id=?";
final String[] selectionArgs = new String[] { split[1] };
return getDataColumn(context, contentUri, selection,
selectionArgs);
}
}
// MediaStore (and general)
else if ("content".equalsIgnoreCase(uri.getScheme())) {
// Return the remote address
if (isGooglePhotosUri(uri))
return uri.getLastPathSegment();
return getDataColumn(context, uri, null, null);
}
// File
else if ("file".equalsIgnoreCase(uri.getScheme())) {
return uri.getPath();
}
return "";
}
On every instance after clearing data of the application, this method getDataColumn() is returning "" empty and on Debugging I found that the Cursor inside the try block, is not fetching anything out of it.
Well, You should consider 2 things first.
1. Don't create the folder if it already exists
2. Load media from the folder with different code
So, here is a little help.
1. Check the existence of the directory.
if (!file.exists()) {
createFolder();
}
Then
2. Load media differently
private ArrayList<Media> loadMedia(String directory_name) {
mediaList = new ArrayList<>();
String selection;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
selection = MediaStore.MediaColumns.RELATIVE_PATH + " LIKE ? ";
} else {
selection = MediaStore.Images.Media.DATA + " LIKE ? ";
}
String[] selectionArgs = new String[]{directory_name};
Cursor cursor = getContentResolver().query(
MediaStore.Files.getContentUri("external"),
null,
selection,
selectionArgs,
MediaStore.Video.Media.DATE_TAKEN + " DESC");
if (cursor != null) {
if (cursor.getCount() > 0) {
cursor.moveToFirst();
do {
int imageCol = cursor.getColumnIndex(MediaStore.Images.Media.DATA);
long id = cursor.getLong(cursor.getColumnIndexOrThrow(BaseColumns._ID));
String path = cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media.DATA));
long date = cursor.getLong(cursor.getColumnIndex(MediaStore.Images.Media.DATE_ADDED));
String pathId = cursor.getString(imageCol);
Uri uri = Uri.parse(pathId);
Uri contentUri;
if (uri.toString().endsWith(".mp4")) {
contentUri = ContentUris.withAppendedId(MediaStore.Video.Media.EXTERNAL_CONTENT_URI, id);
} else {
contentUri = ContentUris.withAppendedId(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, id);
}
Media media = new Media();
media.setPath(path);
media.setMediaStoreUri(contentUri);
media.setUri(uri);
media.setAlbumName(new File(path).getParent());
mediaList.add(media);
}
while (cursor.moveToNext());
cursor.close();
}
}
return mediaList;
}
This code is working perfectly in all of the devices including Android 10 and above. Give it a try.
All the best!
I was trying to fetch file path from Uri given by data.data!! onActivityResult() method in android. When I selected the DCIM folder in File browser I was able to get the file path but when I selected the same file from RECENT section in file browser I was not getting the file path.
Code on Button click:
val intent = Intent();
intent.setType("image/*");
val mimeTypes: Array<String> = arrayOf("image/*", "application/pdf")
intent.putExtra(Intent.EXTRA_MIME_TYPES,mimeTypes)
intent.setAction(Intent.ACTION_OPEN_DOCUMENT);
intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
startActivityForResult(Intent.createChooser(intent, "Select File"), 101);
Code on returning data from onActivityResult() method:
var selectedImagePathFB:String = ""
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (resultCode == RESULT_OK) {
if (requestCode == 101) {
val selectedImageUri:Uri = data?.data!!
selectedImagePathFB = getPath(this#MyContactUsActivity,selectedImageUri);
//selectedImagePathFB = AppUtils().getRealPathFromURI(this#MyContactUsActivity,selectedImageUri)
val url: String = selectedImagePathFB
}
}
}
and getPath(Context,Uri) is common found code from stackoverflow by paulburke:
public static String getPath(final Context context, final Uri uri) {
// DocumentProvider
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT && DocumentsContract.isDocumentUri(context, uri)) {
if (isExternalStorageDocument(uri)) {
final String docId = DocumentsContract.getDocumentId(uri);
final String[] split = docId.split(":");
final String type = split[0];
return Environment.getExternalStorageDirectory() + "/" + split[1];
// TODO handle non-primary volumes
}
// DownloadsProvider
else if (isDownloadsDocument(uri)) {
try {
final String id = DocumentsContract.getDocumentId(uri);
//Log.d(TAG, "getPath: id= " + id);
final Uri contentUri = ContentUris.withAppendedId(Uri.parse("content://downloads/public_downloads"), Long.valueOf(id));
return getDataColumn(context, contentUri, null, null);
}catch (Exception e){
e.printStackTrace();
List<String> segments = uri.getPathSegments();
if(segments.size() > 1) {
String rawPath = segments.get(1);
if(!rawPath.startsWith("/")){
return rawPath.substring(rawPath.indexOf("/"));
}else {
return rawPath;
}
}
}
}
// MediaProvider
else if (isMediaDocument(uri)) {
final String docId = DocumentsContract.getDocumentId(uri);
final String[] split = docId.split(":");
final String type = split[0];
Uri contentUri = null;
if ("image".equals(type)) {
contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
} else if ("video".equals(type)) {
contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
} else if ("audio".equals(type)) {
contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
}
final String selection = "_id=?";
final String[] selectionArgs = new String[]{
split[1]
};
return getDataColumn(context, contentUri, selection, selectionArgs);
}
}
// MediaStore (and general)
else if ("content".equalsIgnoreCase(uri.getScheme())) {
// Return the remote address
if (isGooglePhotosUri(uri))
return uri.getLastPathSegment();
return getDataColumn(context, uri, null, null);
}
// File
else if ("file".equalsIgnoreCase(uri.getScheme())) {
return uri.getPath();
}
return null;
}
public static String getDataColumn(Context context, Uri uri, String selection,
String[] selectionArgs) {
Cursor cursor = null;
final String column = "_data";
final String[] projection = {
column
};
try {
cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs,
null);
if (cursor != null && cursor.moveToFirst()) {
final int column_index = cursor.getColumnIndexOrThrow(column);
return cursor.getString(column_index);
}
}catch (Exception e){
e.printStackTrace();
}finally {
if (cursor != null)
cursor.close();
}
return "nodata";
}
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 isGooglePhotosUri(Uri uri) {
return "com.google.android.apps.photos.content".equals(uri.getAuthority());
}
I am testing on android Q device. Why is that when selecting file from RECENT section in file browser i am not getting any file path meanwhile selecting same file in STORAGE section is returning file path? And is there a workaround also for converting files like PDF or Images in Base64 string if not from file path?
According to your code there is no error. But you have to get Storage permission before getting files from Recent section. Read and Write permission are required.
this is my code when i'm getting image from internal storage (gallery).
In lollipop file path return always null.
if (requestCode == PICK_IMAGE) {
if(resultCode == RESULT_OK){
//image successfully picked
// launching upload activity
Uri selectedImage = data.getData();
String[] filePathColumn = { MediaStore.Images.Media.DATA };
Cursor cursor = getContentResolver().query(selectedImage,filePathColumn, null, null, null);
cursor.moveToFirst();
columnindex = cursor.getColumnIndex(MediaStore.Images.Media.DATA);
file_path = cursor.getString(columnindex);
Log.d(getClass().getName(), "file_path"+file_path);
fileUri = Uri.parse("file://" + file_path);
cursor.close();
launchUploadActivity(true, PICK_IMAGE);
}else if (resultCode == RESULT_CANCELED) {
// user cancelled recording
Toast.makeText(getApplicationContext(),"User cancelled image selection", Toast.LENGTH_SHORT).show();
} else {
// failed to record video
Toast.makeText(getApplicationContext(),"Sorry! failed to pick image", Toast.LENGTH_SHORT).show();
}
Thanx all,I found the solution.
Uri selectedImage = data.getData();
String wholeID = DocumentsContract.getDocumentId(selectedImage);
// Split at colon, use second item in the array
String id = wholeID.split(":")[1];
String[] column = { MediaStore.Images.Media.DATA };
// where id is equal to
String sel = MediaStore.Images.Media._ID + "=?";
Cursor cursor = getContentResolver().
query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
column, sel, new String[]{ id }, null);
String filePath = "";
int columnIndex = cursor.getColumnIndex(column[0]);
if (cursor.moveToFirst()) {
filePath = cursor.getString(columnIndex);
}
cursor.close();
setImageFromIntent(filePath);
Add permission to your manifest -
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
you have to define read permission, before read any content.
EDITED
Update your code -
Uri selectedImage = data.getData();
String[] filePathColumn = { MediaStore.Images.Media.DATA };
Cursor cursor = getContentResolver().query(selectedImage,filePathColumn, null, null, null);
columnindex = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
cursor.moveToFirst();
file_path = cursor.getString(columnindex);
Log.d(getClass().getName(), "file_path"+file_path);
fileUri = Uri.parse("file://" + file_path);
cursor.close();
launchUploadActivity(true, PICK_IMAGE);
So here if any exception in getting data from cursor then it throws exception.
Lollipop decided to take another course with getting files from the system. (Some say it is from KitKat, but I haven't encountered it yet on KitKat). The code below is to get the filepath on lollipop
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT && isMediaDocument(uri))
{
final String docId = DocumentsContract.getDocumentId(uri);
final String[] split = docId.split(":");
final String type = split[0];
Uri contentUri = null;
if ("image".equals(type))
{
contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
}
final String selection = "_id=?";
final String[] selectionArgs = new String[] {
split[1]
};
String filePath = getDataColumn(context, contentUri, selection, selectionArgs);
}
isMediaDocument:
public static boolean isMediaDocument(Uri uri)
{
return "com.android.providers.media.documents".equals(uri.getAuthority());
}
getDataColumn:
private static String getDataColumn(Context context, Uri uri, String selection, String[] selectionArgs)
{
Cursor cursor = null;
final String column = "_data";
final String[] projection = {
column
};
try {
cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs, null);
if (cursor != null && cursor.moveToFirst())
{
final int column_index = cursor.getColumnIndexOrThrow(column);
return cursor.getString(column_index);
}
} finally {
if (cursor != null)
cursor.close();
}
return null;
}
If you still have problems, this is the full answer that checks for images, audio, video, files, etc.
///////////////////create file obj:
private File mFileTemp;
String state = Environment.getExternalStorageState();
if (Environment.MEDIA_MOUNTED.equals(state)) {
mFileTemp = new File(Environment.getExternalStorageDirectory(), InternalStorageContentProvider.TEMP_PHOTO_FILE_NAME);
}
else {
mFileTemp = new File(getFilesDir(), InternalStorageContentProvider.TEMP_PHOTO_FILE_NAME);
}
/////////////////// use in start activity for result
try {
InputStream inputStream = getContentResolver().openInputStream(data.getData());
FileOutputStream fileOutputStream = new FileOutputStream(mFileTemp);
copyStream(inputStream, fileOutputStream);
fileOutputStream.close();
inputStream.close();
imagepath = mFileTemp.getPath();
} catch (Exception e) {
Log.e("TAG", "Error while creating temp file", e);
}
/////////////////
public static void copyStream(InputStream input, OutputStream output)
throws IOException
{
byte[] buffer = new byte[1024];
int bytesRead;
while ((bytesRead = input.read(buffer)) != -1)
{
output.write(buffer, 0, bytesRead);
}
}
public void String(Uri file_uri){
String path = null;
Cursor returnCursor = getContext().getContentResolver().query(file_uri, null,
null, null, null);
if (returnCursor != null && returnCursor.moveToFirst()) {
//to get file name
int nameIndex =
returnCursor.getColumnIndex(OpenableColumns.DISPLAY_NAME);
//string filename will get a filename which you have choosen
String fileName = returnCursor.getString(nameIndex);
//to get full path of image
path = returnCursor.getString(returnCursor.getColumnIndex(MediaStore.MediaColumns.DATA));
}
return path;
}
I want to sen file to server and I need to get real path from uri.
My code:
public String getPathFromURI(Context context, Uri contentUri) {
if ( contentUri.toString().indexOf("file:///") > -1 ){
return contentUri.getPath();
}
Cursor cursor = null;
try {
String[] proj = { MediaStore.Images.Media.DATA };
cursor = context.getContentResolver().query(contentUri, proj, null, null, null);
int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
cursor.moveToFirst();
return cursor.getString(column_index);
}finally {
if (cursor != null) {
cursor.close();
}
}
}
And onActivityResult:
...
imageName = data.getData();
imagePath = getPathFromURI(getBaseContext(),imageName);
Picasso.with(getBaseContext()).load(imageName).into(imageView);
...
How it's possible that image shows in ImageView , but imagePath is ALWAYS null ? :) Thanks
EDIT:
How i send image to server
HttpClient httpClient = new DefaultHttpClient();
HttpContext localContext = new BasicHttpContext();
HttpPost httpPost = new HttpPost([URL TO A SERVER]);
MultipartEntity entity = new MultipartEntity(HttpMultipartMode.BROWSER_COMPATIBLE);
entity.addPart("uploaded_file_1", new FileBody(new File( imagePath )));
httpPost.setEntity(entity);
httpClient.execute(httpPost, localContext);
I went through some answers on stack, and found the solution...
public static String getPathFromURI(final Context context, final Uri uri) {
final boolean isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;
// DocumentProvider
if (isKitKat && DocumentsContract.isDocumentUri(context, uri)) {
// ExternalStorageProvider
if (isExternalStorageDocument(uri)) {
final String docId = DocumentsContract.getDocumentId(uri);
final String[] split = docId.split(":");
final String type = split[0];
if ("primary".equalsIgnoreCase(type)) {
return Environment.getExternalStorageDirectory() + "/" + split[1];
}
}
// DownloadsProvider
else if (isDownloadsDocument(uri)) {
final String id = DocumentsContract.getDocumentId(uri);
final Uri contentUri = ContentUris.withAppendedId(Uri.parse("content://downloads/public_downloads"), Long.valueOf(id));
return getDataColumn(context, contentUri, null, null);
}
// MediaProvider
else if (isMediaDocument(uri)) {
final String docId = DocumentsContract.getDocumentId(uri);
final String[] split = docId.split(":");
final String type = split[0];
Uri contentUri = null;
if ("image".equals(type)) {
contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
} else if ("video".equals(type)) {
contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
} else if ("audio".equals(type)) {
contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
}
final String selection = "_id=?";
final String[] selectionArgs = new String[] {
split[1]
};
return getDataColumn(context, contentUri, selection, selectionArgs);
}
}
// MediaStore (and general)
else if ("content".equalsIgnoreCase(uri.getScheme())) {
return getDataColumn(context, uri, null, null);
}
// File
else if ("file".equalsIgnoreCase(uri.getScheme())) {
return uri.getPath();
}
return null;
}
public static String getDataColumn(Context context, Uri uri, String selection,
String[] selectionArgs) {
Cursor cursor = null;
final String column = "_data";
final String[] projection = {
column
};
try {
cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs,
null);
if (cursor != null && cursor.moveToFirst()) {
final int column_index = cursor.getColumnIndexOrThrow(column);
return cursor.getString(column_index);
}
} finally {
if (cursor != null)
cursor.close();
}
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());
}
This will find the real path in every case even for kitkat (that was the problem... kitkat)
From android 10 you must use app-specific storage for your files. In case you want file from external storage and do something to it like you want to upload it to the server, you need to get the file and make a copy of it to the app-specific storage.
Here is what you can use, assuming you already have the uri of the selected file.
val parcelFileDescriptor =
contentResolver.openFileDescriptor(selectedImageUri!!, "r", null) ?: return
val inputStream = FileInputStream(parcelFileDescriptor.fileDescriptor)
val file = File(cacheDir, contentResolver.getFileName(selectedImageUri!!))
val outputStream = FileOutputStream(file)
inputStream.copyTo(outputStream)
And the function to get the file name from the Uri is
fun ContentResolver.getFileName(fileUri: Uri): String {
var name = ""
val returnCursor = this.query(fileUri, null, null, null, null)
if (returnCursor != null) {
val nameIndex = returnCursor.getColumnIndex(OpenableColumns.DISPLAY_NAME)
returnCursor.moveToFirst()
name = returnCursor.getString(nameIndex)
returnCursor.close()
}
return name
}
Now you can use file.path and it will work.
If you don't want to do like this then for android 10 there is also a temporary solution that is
android:requestLegacyExternalStorage="true"
You can add this to your AndroidManifest.xml inside application tag.
Reference: Android Upload File to Server
Hope this will help, Thank You :)
This code work for me in android 11 and 12
private static String getRealPathFromURI(Uri uri, Context context) {
Uri returnUri = uri;
Cursor returnCursor = context.getContentResolver().query(returnUri, null, null, null, null);
int nameIndex = returnCursor.getColumnIndex(OpenableColumns.DISPLAY_NAME);
int sizeIndex = returnCursor.getColumnIndex(OpenableColumns.SIZE);
returnCursor.moveToFirst();
String name = (returnCursor.getString(nameIndex));
String size = (Long.toString(returnCursor.getLong(sizeIndex)));
File file = new File(context.getFilesDir(), name);
try {
InputStream inputStream = context.getContentResolver().openInputStream(uri);
FileOutputStream outputStream = new FileOutputStream(file);
int read = 0;
int maxBufferSize = 1 * 1024 * 1024;
int bytesAvailable = inputStream.available();
//int bufferSize = 1024;
int bufferSize = Math.min(bytesAvailable, maxBufferSize);
final byte[] buffers = new byte[bufferSize];
while ((read = inputStream.read(buffers)) != -1) {
outputStream.write(buffers, 0, read);
}
Log.e("File Size", "Size " + file.length());
inputStream.close();
outputStream.close();
Log.e("File Path", "Path " + file.getPath());
Log.e("File Size", "Size " + file.length());
} catch (Exception e) {
Log.e("Exception", e.getMessage());
}
return file.getPath();
}
I couldn't get the path for a Marshmallow phone sharing media from Google Photos to my app. I'll try to explain myself why this is probably happening.
I didn't find any official documentation to base my thought, but I'll share them with you to see if with some collaboration from different minds we reach to a solution.
My theory is that Google Photos does not have the media files physically in the phone, they are probably thumbnails or online. So when you share some pics, they are downloaded temporary and probably stored in the Internal Storage of the App so you can't access it (to the path).
The only workaround I found to get the path of the file is copying it to my app internal storage. I don't like it but everything I tried didn't work for me.
Thanks Michal Heneš and Sam .
After a lot of searching I got solution in java.
import android.annotation.SuppressLint;
import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
import android.os.Build;
import android.os.Environment;
import android.provider.DocumentsContract;
import android.provider.MediaStore;
import android.util.Log;
import android.widget.Switch;
import java.io.File;
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.ListIterator;
import java.util.Objects;
import kotlin.Metadata;
import kotlin.collections.CollectionsKt;
import kotlin.jvm.internal.Intrinsics;
import kotlin.text.Regex;
import kotlin.text.StringsKt;
public class UtilsFile {
private final static String PUBLIC_DOWNLOAD_PATH = "content://downloads/public_downloads";
private final static String EXTERNAL_STORAGE_DOCUMENTS_PATH = "com.android.externalstorage.documents";
private final static String DOWNLOAD_DOCUMENTS_PATH = "com.android.providers.downloads.documents";
private final static String MEDIA_DOCUMENTS_PATH = "com.android.providers.media.documents";
private final static String PHOTO_CONTENTS_PATH = "com.google.android.apps.photos.content";
private Boolean isExternalStorageDocument(Uri uri) {
return EXTERNAL_STORAGE_DOCUMENTS_PATH.equals(uri.getAuthority());
}
private Boolean isPublicDocument(Uri uri) {
return PUBLIC_DOWNLOAD_PATH.equals(uri.getAuthority());
}
private Boolean isDownloadsDocument(Uri uri) {
return DOWNLOAD_DOCUMENTS_PATH.equals(uri.getAuthority());
}
private Boolean isMediaDocument(Uri uri) {
return MEDIA_DOCUMENTS_PATH.equals(uri.getAuthority());
}
private Boolean isGooglePhotosUri(Uri uri) {
return MEDIA_DOCUMENTS_PATH.equals(uri.getAuthority());
}
private Boolean isPhotoContentUri(Uri uri) {
return PHOTO_CONTENTS_PATH.equals(uri.getAuthority());
}
private String getDataColumn(Context context, Uri uri, String selection, String[] selectionArgs) {
Cursor cursor = null;
//String column = "_data" REMOVED IN FAVOR OF NULL FOR ALL
//String projection = arrayOf(column) REMOVED IN FAVOR OF PROJECTION FOR ALL
try {
cursor = context.getContentResolver().query(uri, null, selection, selectionArgs, null);
if (cursor != null && cursor.moveToFirst()) {
int columnIndex = cursor.getColumnIndexOrThrow(DocumentsContract.Document.COLUMN_DISPLAY_NAME);
return cursor.getString(columnIndex);
}
} catch (Exception e) {
Log.e("PathUtils", "Error getting uri for cursor to read file: " + e.getMessage());
} finally {
assert cursor != null;
cursor.close();
}
return null;
}
public String getFullPathFromContentUri(final Context context, final Uri uri) {
final boolean isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;
String filePath="";
// DocumentProvider
if (isKitKat && DocumentsContract.isDocumentUri(context, uri)) {
// ExternalStorageProvider
if (isExternalStorageDocument(uri)) {
final String docId = DocumentsContract.getDocumentId(uri);
final String[] split = docId.split(":");
final String type = split[0];
if ("primary".equalsIgnoreCase(type)) {
return Environment.getExternalStorageDirectory() + "/" + split[1];
}//non-primary e.g sd card
else {
if (Build.VERSION.SDK_INT > 20) {
//getExternalMediaDirs() added in API 21
File[] extenal = context.getExternalMediaDirs();
for (File f : extenal) {
filePath = f.getAbsolutePath();
if (filePath.contains(type)) {
int endIndex = filePath.indexOf("Android");
filePath = filePath.substring(0, endIndex) + split[1];
}
}
}else{
filePath = "/storage/" + type + "/" + split[1];
}
return filePath;
}
}
// DownloadsProvider
else if (isDownloadsDocument(uri)) {
String fileName = getDataColumn(context, uri,null, null);
String uriToReturn = null;
if (fileName != null) {
uriToReturn = Uri.withAppendedPath(
Uri.parse(
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).getAbsolutePath()), fileName
).toString();
}
return uriToReturn;
}
// MediaProvider
else if (isMediaDocument(uri)) {
final String docId = DocumentsContract.getDocumentId(uri);
final String[] split = docId.split(":");
final String type = split[0];
Uri contentUri = null;
if ("image".equals(type)) {
contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
} else if ("video".equals(type)) {
contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
} else if ("audio".equals(type)) {
contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
}
final String selection = "_id=?";
final String[] selectionArgs = new String[]{
split[1]
};
Cursor cursor = null;
final String column = "_data";
final String[] projection = {
column
};
try {
cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs,
null);
if (cursor != null && cursor.moveToFirst()) {
final int column_index = cursor.getColumnIndexOrThrow(column);
return cursor.getString(column_index);
}
} finally {
if (cursor != null)
cursor.close();
}
return null;
}
}
// MediaStore (and general)
else if ("content".equalsIgnoreCase(uri.getScheme())) {
return getDataColumn(context, uri, null, null);
}
// File
else if ("file".equalsIgnoreCase(uri.getScheme())) {
return uri.getPath();
}
else if (isPublicDocument(uri)){
String id = DocumentsContract.getDocumentId(uri);
final Uri contentUri = ContentUris.withAppendedId(
Uri.parse(PUBLIC_DOWNLOAD_PATH), Long.parseLong(id));
String[] projection = {MediaStore.Images.Media.DATA};
#SuppressLint("Recycle") Cursor cursor = context.getContentResolver().query(contentUri, projection, null, null, null);
if (cursor != null && cursor.moveToFirst()) {
int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
cursor.moveToFirst();
return cursor.getString(column_index);
}
}
return null;
}
}
Accessing public download files onActivityResult Android 28 Samsung Galaxy S9+ (Verizon)
you can use this funtion for get file from uri in new android and older
fun getFileFromUri(context: Context, uri: Uri?): File? {
uri ?: return null
uri.path ?: return null
var newUriString = uri.toString()
newUriString = newUriString.replace(
"content://com.android.providers.downloads.documents/",
"content://com.android.providers.media.documents/"
)
newUriString = newUriString.replace(
"/msf%3A", "/image%3A"
)
val newUri = Uri.parse(newUriString)
var realPath = String()
val databaseUri: Uri
val selection: String?
val selectionArgs: Array<String>?
if (newUri.path?.contains("/document/image:") == true) {
databaseUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI
selection = "_id=?"
selectionArgs = arrayOf(DocumentsContract.getDocumentId(newUri).split(":")[1])
} else {
databaseUri = newUri
selection = null
selectionArgs = null
}
try {
val column = "_data"
val projection = arrayOf(column)
val cursor = context.contentResolver.query(
databaseUri,
projection,
selection,
selectionArgs,
null
)
cursor?.let {
if (it.moveToFirst()) {
val columnIndex = cursor.getColumnIndexOrThrow(column)
realPath = cursor.getString(columnIndex)
}
cursor.close()
}
} catch (e: Exception) {
Log.i("GetFileUri Exception:", e.message ?: "")
}
val path = realPath.ifEmpty {
when {
newUri.path?.contains("/document/raw:") == true -> newUri.path?.replace(
"/document/raw:",
""
)
newUri.path?.contains("/document/primary:") == true -> newUri.path?.replace(
"/document/primary:",
"/storage/emulated/0/"
)
else -> return null
}
}
return if (path.isNullOrEmpty()) null else File(path)
}
I would like to upload file to server. So I use a file chooser. But I have a problem with some application to get the real path from uri. the case if the content is a v
ideo, audio or image or if I can get the path directly i have no problem. the methode imlemented are :
public String getRealAudioPathFromURI(Uri contentUri) {
String[] proj = { MediaStore.Audio.Media.DATA };
//This method was deprecated in API level 11
//Cursor cursor = managedQuery(contentUri, proj, null, null, null);
CursorLoader cursorLoader = new CursorLoader(
this,
contentUri, proj, null, null, null);
Cursor cursor = cursorLoader.loadInBackground();
int column_index =
cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.DATA);
cursor.moveToFirst();
return cursor.getString(column_index);
}
and it is the some for image and video. but my problem is when content is in this forme:
content://com.dataviz.dxtg.documentprovider/document/file%3A%2F%2F%2Fmnt%2Fsdcard%2FDownload%2Arbres.png
I tried the method
private String getFilePathFromContentUri(Uri selectedVideoUri,
ContentResolver contentResolver) {
String filePath;
String[] filePathColumn = {MediaStore.MediaColumns.DATA};
Cursor cursor = contentResolver.query(selectedVideoUri, filePathColumn, null, null, null);
cursor.moveToFirst();
int columnIndex = cursor.getColumnIndex(filePathColumn[0]);
filePath = cursor.getString(columnIndex);
cursor.close();
return filePath;
}
So how to get the real path from URi and if there is an other content type .
to get my real path is given below:
//Uri return from external activity
orgUri = data.getData();
text1.setText("fichier à envoyer " + orgUri.toString() + "\n");
// imagepath = orgUri.toString() ;
//path converted from Uri
//convertedPath = orgUri.getPath();
if(orgUri.toString().contains(IMAGEMEDIA)){
convertedPath = getRealPathFromURI(orgUri);
} else if(orgUri.toString().contains(AUDIOMEDIA)){
convertedPath = getRealAudioPathFromURI(orgUri);
}
else if(orgUri.toString().contains(VIDEOMEDIA)){
convertedPath = getRealvideoPathFromURI(orgUri);
}else {
if(orgUri.toString().contains("content")){
convertedPath = getFilePathFromContentUri(orgUri,
getApplicationContext().getContentResolver());
} else {
convertedPath = orgUri.getPath();
}
}
try this one
Uri selectedFile = data.getData();
String path = selectedFile.getPath();
it works for me.
if it is not than let me inform i have another way too
This works for me...
public static String getPath(final Context context, final Uri uri) {
final boolean isKitKat = Build.VERSION.SDK_INT >=
Build.VERSION_CODES.KITKAT;
Log.i("URI",uri+"");
String result = uri+"";
// DocumentProvider
// if (isKitKat && DocumentsContract.isDocumentUri(context, uri)) {
if (isKitKat && (result.contains("media.documents"))) {
String[] ary = result.split("/");
int length = ary.length;
String imgary = ary[length-1];
final String[] dat = imgary.split("%3A");
final String docId = dat[1];
final String type = dat[0];
Uri contentUri = null;
if ("image".equals(type)) {
contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
} else if ("video".equals(type)) {
} else if ("audio".equals(type)) {
}
final String selection = "_id=?";
final String[] selectionArgs = new String[] {
dat[1]
};
return getDataColumn(context, contentUri, selection, selectionArgs);
}
else
if ("content".equalsIgnoreCase(uri.getScheme())) {
return getDataColumn(context, uri, null, null);
}
// File
else if ("file".equalsIgnoreCase(uri.getScheme())) {
return uri.getPath();
}
return null;
}
public static String getDataColumn(Context context, Uri uri, String selection,
String[] selectionArgs) {
Cursor cursor = null;
final String column = "_data";
final String[] projection = {
column
};
try {
cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs,
null);
if (cursor != null && cursor.moveToFirst()) {
final int column_index = cursor.getColumnIndexOrThrow(column);
return cursor.getString(column_index);
}
} finally {
if (cursor != null)
cursor.close();
}
return null;
}
It is a problem of decode. So the Solution is to add decode to the method. as given below:
private String getFilePathFromContentUri(Uri selectedVideoUri,
ContentResolver contentResolver) throws UnsupportedEncodingException {
String filePath;
String[] filePathColumn = {MediaStore.MediaColumns.DATA};
Cursor cursor = contentResolver.query(selectedVideoUri, filePathColumn, null, null, null);
cursor.moveToFirst();
int columnIndex = cursor.getColumnIndex(filePathColumn[0]);
filePath = cursor.getString(columnIndex);
cursor.close();
String result = java.net.URLDecoder.decode(filePath, "UTF-8");
return result;
}
my onActivityResult:
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if(resultCode == RESULT_OK){
//image.setImageBitmap(null);
//Uri return from external activity
orgUri = data.getData();
text1.setText("fichier à envoyer " + orgUri.toString() + "\n");
// imagepath = orgUri.toString() ;
//path converted from Uri
//convertedPath = orgUri.getPath();
if(orgUri.toString().contains(IMAGEMEDIA)){
convertedPath = getRealPathFromURI(orgUri);
} else if(orgUri.toString().contains(AUDIOMEDIA)){
convertedPath = getRealAudioPathFromURI(orgUri);
}
else if(orgUri.toString().contains(VIDEOMEDIA)){
convertedPath = getRealvideoPathFromURI(orgUri);
}else {
if(orgUri.toString().contains("content")){
try {
convertedPath = getFilePathFromContentUri(orgUri,
getApplicationContext().getContentResolver());
} catch (UnsupportedEncodingException e) {
e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
}
} else {
convertedPath = orgUri.getPath();
}
}
// text2.setText("Real Path: " + convertedPath + "\n");
imagepath = convertedPath;
uriFromPath = Uri.fromFile(new File(convertedPath));
}
}