Unexpected file path and FileNotFoundException in ContentResolver - Android - android

I'm trying to feed MediaRecorder with a filePath to save a video and in order to do that I use insert method which returns a Uri. I then take this Uri and query for the DATA column to obtain my file path to then pass it to mediaRecorder.setOutputFile(). To my surprise, even though I pass contentValues map with DISPLAY_NAME set in format timestamp.mp4, the file path I end up with is compeletely different and has a .3gp suffix.
Below is the code fragment which inserts the media and retrieves the filePath.
String timeStamp = new SimpleDateFormat("yyyyMMddHHmmss").format(new Date());
Uri mediaStoreUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
ContentValues contentValues = new ContentValues();
contentValues.put(MediaStore.Video.Media.DISPLAY_NAME, timeStamp + ".mp4");
contentValues.put(MediaStore.Video.Media.MIME_TYPE, "video/mp4");
Uri videoUri = getContentResolver().insert(mediaStoreUri, contentValues);
String videoPath = getRealUriPath(videoUri);
mMediaRecorder.setOutputFile(videoPath);
and the method getRealUriPath looks as follows
private String getRealUriPath(Uri uri) {
Cursor cursor = null;
final String column = MediaStore.MediaColumns.DATA;
final String[] projection = {
column
};
try {
cursor = getContentResolver().query(uri, projection, null, null,
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;
}
When I start recording with the mMediaRecorder, an exception is thrown which looks as follows:
07-31 19:08:36.240 1895-1895/com.example.opencv101 E/CameraActivity: MediaRecorder failed to prepare.
java.io.FileNotFoundException: /storage/emulated/0/video/1627751307861.3gp: open failed: ENOENT (No such file or directory)
I don't understand two things:
Why does the filePath end with 1627751307861.3gp ?
Why do I get the FileNotFoundException since I'm trying to access the file I've just added using the insert method?
I double checked that the WRITE_EXTERNAL_STORAGE permissions are granted.

Related

Android - Get absolute file path from uri, picked from Downloads

I am trying to get the absolute file path from the uri. But can't get it for the files downloaded with some download manager.
For example, I have downloaded an audio and stored it in /storage/emulated/0/MIUI/.ringtone/Our Street (30-secs version)_&_7f2f552b-b5b8-41a0-94de-4b3b065b7c00.mp3. If I pick this file from Downloads section of file picker I got the following uri content://com.android.providers.downloads.documents/document/19 and I can not calculate the absolute path from this uri.
But if I pick the file from original directory i.e /storage/emulated/0/MIUI/.ringtone/ I got this uri content://com.android.externalstorage.documents/document/primary%3AMIUI%2F.ringtone%2FOur%20Street%20(30-secs%20version)_%26_7f2f552b-b5b8-41a0-94de-4b3b065b7c00.mp3 and I can get the absolute file path from this url.
How could I get the absolute file path while picked from Downloads?
I am opening file picker using following code:
Intent chooseFile = new Intent(Intent.ACTION_GET_CONTENT);
chooseFile.addCategory(Intent.CATEGORY_OPENABLE);
chooseFile.setType("*/*");
chooseFile.putExtra(Intent.EXTRA_ALLOW_MULTIPLE,false);
startActivityForResult(Intent.createChooser(chooseFile, "Select Audio"), PICK_AUDIO_RESULT_CODE);
For parsing absolute file path from uri I'm using following code:
final String id = DocumentsContract.getDocumentId(uri);
final Uri contentUri = ContentUris.withAppendedId(
Uri.parse("content://downloads/public_downloads"), Long.valueOf(id)
);
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 null;

java.lang.IllegalArgumentException: All requested items must be referenced by specific ID (Android)

I'm getting this exception upon calling MediaStore.createWriteRequest(contentResolver, uris). As in Anrdroid Q and above we have to make createWriteRequest to write on storage. So I'm trying the following code and getting the exception.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
List<Uri> uris = new ArrayList<>();
uris.add(mediaUri);
MediaStore.createWriteRequest(contentResolver, uris);
//code
}
Your Uri path is wrong that's the reason the error message is shown.
Invalid Uri Path: content://com.abc.photoapp.provider/external_files/emulated/0/Pictures/camara/1623819097267.jpg
Valid Path is :
content://media/external/images/media/52703
Here, I explain the file path to delete media step by step.
Step 1:
Suppose You have a file path like this
"/storage/emulated/0/tempPic/export_image.jpg"
File tempFile=new File("/storage/emulated/0/tempPic/export_image.jpg");
long mediaID=getFilePathToMediaID(tempFile.getAbsolutePath(), context);
public long getFilePathToMediaID(String songPath, Context context)
{
long id = 0;
ContentResolver cr = context.getContentResolver();
Uri uri = MediaStore.Files.getContentUri("external");
String selection = MediaStore.Audio.Media.DATA;
String[] selectionArgs = {songPath};
String[] projection = {MediaStore.Audio.Media._ID};
String sortOrder = MediaStore.Audio.Media.TITLE + " ASC";
Cursor cursor = cr.query(uri, projection, selection + "=?", selectionArgs, null);
if (cursor != null) {
while (cursor.moveToNext()) {
int idIndex = cursor.getColumnIndex(MediaStore.Audio.Media._ID);
id = Long.parseLong(cursor.getString(idIndex));
}
}
return id;
}
Step 2:
Create media id to Uri
Uri Uri_one = ContentUris.withAppendedId( MediaStore.Images.Media.getContentUri("external"),mediaID);
// content://media/external/images/media/52703
The content Uri change according to your file type:
If Image then : MediaStore.Images.Media.getContentUri("external")
If Video then : MediaStore.Video.Media.getContentUri("external")
Step 3:
Prepare and call to delete
List<Uri> uris=new ArrayList<>();
uris.add(<Add Paht : Uri_one >);
uris.add(<Add Paht : Uri_two >);
uris.add(<Add Paht : Uri_three >);
requestDeletePermission( context,uris);
enter image description here
After you call the method ask permission dialog. requestDeletePermission method is return result on onActivityResult method.
The above method support android 11 (Target SDK Version 30 ) and a greater version. You do not require manage_external_storage permission for media file delete. You can use media like Video, Audio, and Images.
If you want to delete a document file so you must require manage_external_storage permission.

Android: Get file path from Uri of file in SD card

We are trying to fetch the path of a file that is saved in SD Card, to pass on to a utility. However when we use the URI to open a cursor, only two columns are being fetched, the path (_data column) is missing. Please let me know how to fetch the path. The query works fine for any file that is in internal storage.
Scheme is "content".
Code snippet
cursor = context.getContentResolver().query(uri, null, null, null, null);
if (null != cursor && cursor.moveToFirst())
{
int testcolCount = cursor.getColumnCount();
for (int i = 0; i < testcolCount; i++)
{
String colName = cursor.getColumnName(i);
String colValue = cursor.getString(i);
System.out.println("" + i + ": " + colName + ":" + colValue + "\n");
}
//This prints only two columns, _display_name and _size
}
Don't try and get the path at all, with Android 10 and above file paths outside of your App's private directories are useless because you won't have permission to access them.
See https://developer.android.com/training/data-storage#scoped-storage
Use the contentResolver to get a FileDescriptor to pass on to the Utility
Note From https://developer.android.com/reference/android/provider/MediaStore.MediaColumns.html#DATA
This constant was deprecated in API level 29.
Apps may not have filesystem permissions to directly access this path. Instead of trying to open this path directly, apps should use ContentResolver#openFileDescriptor(Uri, String) to gain access.
try this code i am using this function to get real path from uri:
private String getRealPathFromURI(Context mContext, Uri contentURI) {
String result = null;
Cursor cursor = null;
try {
String[] proj = {MediaStore.Video.Media.DATA};
ContentResolver mContentResolver = mContext.getContentResolver();
String mime = mContentResolver.getType(contentURI);
cursor = mContentResolver.query(contentURI, proj, null, null, null);
if (cursor == null) {
return null;
} else {
cursor.moveToFirst();
int column_index = cursor.getColumnIndex(MediaStore.Images.Media.DATA);
if (column_index > -1)
result = cursor.getString(column_index);
cursor.close();
}
} catch (Exception e) {
return null;
} finally {
if (cursor != null)
cursor.close();
}
return result;
}
it will return a string which is real path of your file.
hope it will help you.
The default File manager was the one causing this problem - not returning "DATA" column and returning Authority as "com.lenovo.FileBrowser.FileProvider". When I used another file manager, the Authority was "media". Also got the path column using "DATA" while running the ContenResolver. Thanks to all for taking the effort to help out.

I am getting IllegalArgumentException during picking a document file from download manager ,which is happening only for oreo

Here I am attaching the logs :
Caused by: java.lang.IllegalArgumentException: Unknown URI: content://downloads/public_downloads/1587
at android.database.DatabaseUtils.readExceptionFromParcel(DatabaseUtils.java:165)
at android.database.DatabaseUtils.readExceptionFromParcel(DatabaseUtils.java:135)
at android.content.ContentProviderProxy.query(ContentProviderNative.java:418)
I am using this code which is working fine.But for the case of download manager it is throwing exception at first line of 'try' block
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;
I already tried this: Android getting file path from content URI using contentResolver
and this: java.lang.IllegalArgumentException: Unknown URI content and some others related to this question but not any one of them resolves my problem.
I was getting the same error Unknown URI: content://downloads/public_downloads. I managed to solve this by changing contentUri and by using InputStream methods to fetch file from Download directory. In some of devices changing contentUri to content://downloads/my_downloads works. Checkout this answer for full solution.

Converting file:// scheme to content:// scheme

I am running to the problem with using Droid X's Files app and Astro file manager to select an image file. This two apps return the selected image with the scheme "file://" while Gallery returns the image with the scheme "content://". How do I convert the first schema to the second. Or how do I decode the image with the second format?
You probably want to convert content:// to file://
For gallery images, try something like this:
Uri myFileUri;
Cursor cursor = context.getContentResolver().query(uri,new String[]{android.provider.MediaStore.Images.ImageColumns.DATA}, null, null, null);
if(cursor.moveToFirst())
{
myFileUri = Uri.parse(cursor.getString(0)).getPath();
}
cursor.close
Here, the problem is that, for all files we can't have a content Uri (content://). Because content uri is for those files which are part of MediaStore. Eg: images, audio & video.
However, for supported files, we can find its absolute path. Like for images as follows-
File myimageFile = new File(path);
Uri content_uri=getImageContentUri(this,myimageFile);
The generic method is as follows.
public static Uri getImageContentUri(Context context, File imageFile) {
String filePath = imageFile.getAbsolutePath();
Cursor cursor = context.getContentResolver().query(
MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
new String[] { MediaStore.Images.Media._ID },
MediaStore.Images.Media.DATA + "=? ",
new String[] { filePath }, null);
if (cursor != null && cursor.moveToFirst()) {
int id = cursor.getInt(cursor
.getColumnIndex(MediaStore.MediaColumns._ID));
Uri baseUri = Uri.parse("content://media/external/images/media");
return Uri.withAppendedPath(baseUri, "" + id);
} else {
if (imageFile.exists()) {
ContentValues values = new ContentValues();
values.put(MediaStore.Images.Media.DATA, filePath);
return context.getContentResolver().insert(
MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
} else {
return null;
}
}}
Use ContentResolver.openInputStream() or related methods to access the byte stream. You shouldn't generally be worrying about whether it is a file: or content: URI.
http://developer.android.com/reference/android/content/ContentResolver.html#openInputStream(android.net.Uri)

Categories

Resources