Get file name from Uri in Android - android

I have an Uri build using below code
final Uri fileUri = DocumentsContract.buildChildDocumentsUriUsingTree(rootUri, docId);
that contains value:
content://com.android.externalstorage.documents/tree/primary%Sample/document/primary%Sample%2FMedia%2F.Hide%2FScreenshot_1615959401.png/children
Below is my code to access the name and mime type of file:
ContentResolver contentResolver = getContentResolver();
Cursor cursor = contentResolver.query(fileUri, new String[]{DocumentsContract.Document.COLUMN_DOCUMENT_ID, DocumentsContract.Document.COLUMN_DISPLAY_NAME, DocumentsContract.Document.COLUMN_MIME_TYPE}, null, null, null);
try {
if (cursor != null && cursor.moveToFirst())
{
//Here cursor.moveToFirst() returns false
}
} catch(Exception e)
{
e.printStackTrace();
}
I want to access the name of file like Screenshot_1615959401.png, mime type file like image/png from above Uri but cursor.moveToFirst() returns 0. Why record is not found even Uri is valid. Because I try to use this Uri to load image and ImageView is displaying the image correctly using above Uri.
Any Help would be highly appreciated as I spent lots of time googling and read on SO but didn't find any solution or root cause of it.

Below is my code to access the name and mime type of file:
That Uri is not for a document. It is for the roster of child documents for a document tree, where the tree is identified by docId. childDocumentsUri is the core of the name of the method that you are calling.
Why record is not found even Uri is valid
It is not valid for your desired action.
If you wish to build a Uri for a document, given a document ID and a tree, use buildDocumentUriUsingTree(), not buildChildDocumentsUriUsingTree().

Related

Andriod 10 How to check file exist

In Android Q, save pictures in app-specific directory,
path like = /data/user/0/xxx.xxx.xxx/files/phone/abc.jpg
not save in the external storage, use Device FileExplorer to view,
need to check if file exist, avoid to download again
,but in Android Q file.exist() not work
File newFile = new File(path);
newFile.exists();
always return false
this question. I need to use MediaStore or SAF to resolver it.
or other function to check it.
If I use MediaStore to check. use ContentResolver. May be like this:
public void getPhotoCursor(Uri uri) {
Cursor cursor = getContentResolver().query(uri, null, null, null, null, null);
try {
if (cursor != null && cursor.moveToFirst()) {
String displayName = cursor.getString(cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME));
}
} finally {
cursor.close();
}
}
But I can't get the Uri form app-specific directory. If I get the Uri, how to use file descriptor to check.
or use SAF to check.
File testFile = new File(getExternalFilesDir()+"phone", "abc.jpg");
FileProvider.getUriForFile(,,testFile);
Intent testIntent = new Intent(Intent.ACTION_VIEW);
testIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
testIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
testIntent.setDataAndType();
startActivity(testIntent);
In the ActivityResult to check it
Any help will be apperciated
is my fault, every time open APP I will delete all the .jpg from APP-specific.
so into APP I want to check avoid download again. file exist always return false.

Getting file path from uri on emulator

I want to get file path from Uri for a video. The following method works fine when testing with a real device, however, it fails (returns null) when testing on emulator.
public String getRealPathFromURI(Context context, Uri contentUri) {
Cursor cursor = null;
try {
String[] proj = {MediaStore.Video.Media.DATA};
cursor = context.getContentResolver().query(contentUri, proj, null, null, null);
int column_index = cursor.getColumnIndexOrThrow(MediaStore.Video.Media.DATA);
cursor.moveToFirst();
return cursor.getString(column_index);
} catch (Exception e) {
e.printStackTrace();
} finally {
if (cursor != null) {
cursor.close();
}
}
return null;
}
What is the correct way of getting file path from uri on emulator?
The following method works fine when testing with a real device
Only on the the device that you tried, and only for the app that you tried. Particularly on Android 4.4+, your approach will be unreliable. That is because a Uri is not a file. On older versions of Android, for a Uri from the MediaStore, your approach might work.
Nowadays, do not attempt to get a file for a Uri. Consume the Uri as you are supposed to, using methods on ContentResolver to get an InputStream, the MIME type, etc.
What is the correct way of getting file path from uri on emulator?
There is none. There does not have to be a file path associated with a Uri, let alone a path that your app is able to access using Java file I/O.
As CommonsWare mentioned, an Uri is NOT a File. The general way to deal with Uri is to use an inputstream and save the content as a file (assuming that's what you are looking for). What i typically do is
get the metadata associated with the Uri (to get title / type of data / size)
get the content via an input stream to save it on the device as a file.
Take a look at the "Examine document metadata" and "get an inputstream" on this page: https://developer.android.com/guide/topics/providers/document-provider.html

Get a Content URI from a File URI?

I am using the DownloadManager to download an image to the system's gallery and then in the Broadcast receiver (once the download succeeds) using an Intent to set the image as the wallpaper.
Everything was working fine but then recently on 4.4 I started to get an exception in the Photos/Google+ app because it is expecting a content URI and not a file URI.
So my question is if anyone knows how to convert a full file path/URI (file://) into a content style URI (content://)?
Sorry for the lack of source code, I am away from the computer that has the source, but I hope the question makes sense without it, get a content style uri from a full path.
EDIT:
The image is copied into the system's gallery or media gallery, not saved within my apps internal storeage.
Here is an example of what I want to convert:
file:///storage/emulated/0/Pictures/Rockstar/image.jpg
to
content://media/internal/images/media/445
EDIT 2:
Here is the error that I get from the Google+ app:
04-21 10:50:35.090: E/AndroidRuntime(7220): FATAL EXCEPTION: main
04-21 10:50:35.090: E/AndroidRuntime(7220): Process: com.google.android.apps.plus, PID: 7220
04-21 10:50:35.090: E/AndroidRuntime(7220): java.lang.RuntimeException: Unable to resume activity
{com.google.android.apps.plus/com.google.android.apps.photos.phone.SetWallpaperActivity}:
java.lang.IllegalArgumentException: Image URI must be of the content scheme type
Here is the code that I use to let the user set the wallpaper:
String uriString = c.getString(c.getColumnIndex(DownloadManager.COLUMN_LOCAL_URI));
Uri u = Uri.parse(uriString);
Intent wall_intent = new Intent(Intent.ACTION_ATTACH_DATA);
wall_intent.setDataAndType(u, "image/*");
wall_intent.putExtra("mimeType", "image/*");
Intent chooserIntent = Intent.createChooser(wall_intent,
"Set As");
chooserIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
try {
context.startActivity(chooserIntent);
}
Where uriString is:
file:///storage/emulated/0/Pictures/Rockstar/image.jpg
I was able to figure it out. It was a combination of the code found here: Converting android image URI and scanning the media file after downloading.
So after the file finished downloading I get the path and do the following:
String uriString = c.getString(c.getColumnIndex(DownloadManager.COLUMN_LOCAL_URI));
//Update the System
Uri u = Uri.parse(uriString);
context.sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, u));
//Get the abs path using a file, this is important
File wallpaper_file = new File(u.getPath());
Uri contentURI = getImageContentUri(context, wallpaper_file.getAbsolutePath());
For some reason starting the media scanner, newing the file, and getting the absolute path are important, I'm not exactly sure why but I can't spend any more time on this!
The way to convert from a file URI to a content URI is as follows (taken from the linked StackOver flow post:
public static Uri getImageContentUri(Context context, String absPath) {
Log.v(TAG, "getImageContentUri: " + absPath);
Cursor cursor = context.getContentResolver().query(
MediaStore.Images.Media.EXTERNAL_CONTENT_URI
, new String[] { MediaStore.Images.Media._ID }
, MediaStore.Images.Media.DATA + "=? "
, new String[] { absPath }, null);
if (cursor != null && cursor.moveToFirst()) {
int id = cursor.getInt(cursor.getColumnIndex(MediaStore.MediaColumns._ID));
return Uri.withAppendedPath(MediaStore.Images.Media.EXTERNAL_CONTENT_URI , Integer.toString(id));
} else if (!absPath.isEmpty()) {
ContentValues values = new ContentValues();
values.put(MediaStore.Images.Media.DATA, absPath);
return context.getContentResolver().insert(
MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
} else {
return null;
}
}
Maybe this will help someone in the future.
So my question is if anyone knows how to convert a full file path/URI (file://) into a content style URI (content://)?
Implement a ContentProvider. FileProvider offers an out-of-the-box solution for serving up local files.
I'm not sure about the technique you are using to set the wallpaper but the easiest way is probably to use WallpaperManager.setStream() which doesn't require any URI.
Also note that a file URI only works between apps if the file is publicly accessible so a content URI is a more general solution.
Using a content URI implies that a ContentProvider will serve the file. Which one depends on where your file is located.
If your app has a direct read access to the file, you can implement a content provider in your app by using for example the FileProvider class of the support library, but this should really only be used if the file is located in the private data storage of your app.
If the image is added to the system media gallery, you should probably use the URI provided by the MediaStore.

Resolving the path while recieving data from an external app

i am implementing the functionality to save file in my app which is being sent by some exteral application.
i have provided support for single and mulitple files. Provided handling for all kind of files.
But i am not able to handle the following scenario.
I view a file from an email client -> View it in QuickOffice -> Click on send -> Choose my app->Then click on save in my app.
In that i get the path in following wrapped in the exception
java.io.FileNotFoundException: /file:/data/data/com.qo.android.sp.oem/files/temp/Error.log: open failed: ENOENT (No such file or directory)
I have seen this post which is quite useful for handling uri which has content scheme
Get filename and path from URI from mediastore
Below is my code
Uri uri = (Uri) iterator.next();
if ("content".equals(uri.getScheme())) {
filePath = getFilePathFromContentUri(uri, hostAcitvity.getContentResolver());
}
else {
filePath = uri.getPath();
}
fileName = uri.getLastPathSegment();
fileSize = hostAcitvity.getContentResolver().openInputStream(uri).available();
Code for getFilePathFromContentUri
private String getFilePathFromContentUri(Uri selectedVideoUri, ContentResolver contentResolver)
{
String filePath;
String[] filePathColumn = { 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;
}
Then i wrap the path in a FileInputStream which is throwing the above exception
Not able to resolve the file path properly. Is this the correct way of finding the path ?
cheers,
Saurav
I have seen this post which is quite useful for handling uri which has content scheme
That never worked reliably and will work even less reliably in the future.
Is this the correct way of finding the path ?
No, because there is no requirement that every Uri map to a path on a filesystem that you can access.
Use getInputStream() on ContentResolver to get an InputStream on the Uri, and consume the data that way.

Fetching attachments with custom extension in my Android application

What I am trying to achieve is sounds very familiar, it has been posted many times here and there in Stack Overflow as well, but I'm unable to get it done.
The scenario is, I receive a mail with attachment having custom extension in it. The extension is recognized by my app and it needs the FilePath to process it.
Currently, when I get the attachment in my app using getIntent().getData() all I get is path of the form content://
I have seen methods to convert media content of the type content:// to FilePath like /sdcard/file.ext but I was unable to convert the attachment using that. May be its obvious.
Is there any way that I can process the content:// type without actually downloading it.
Currently from the k9 mail app, when I get the custom extension, it shows my app in the list and opens it through it, but I need FilePath like /sdcard/file.ext and I'm only able to get content:// type.
I hope I made the question clear.
Please Help.
Regards.
A content:// Uri does not necessarily point to a file on the sdcard.
It is more likely that it points to any kind of data stored in a database
or to a content provider that gives you access to the private file storage of another app.
I think the later one is the case with mail attachments (if the content provider is not requesting it directly from a web server). So converting the content:// Uri to a path will not work.
I did the following (not sure if it works also for k9 mail app)
Uri uri = intent.getData();
if (uri.getScheme().equals("content")) {
String fileName = ContentProviderUtils.getAttachmentName(this, uri);
if (fileName.toLowerCase().endsWith(".ext")) {
InputStream is = this.getContentResolver().openInputStream(uri);
// do something
} else {
// not correct extension
return;
}
} else if (uri.getScheme().equals("file")) {
String path = uri.getPath();
if (path.toLowerCase().endsWith(".ext")) {
InputStream is = new FileInputStream(path);
// do something
} else {
// not correct extension
return;
}
}
The attachment name can be found by
public static String getAttachmentName(Context ctxt, Uri contentUri) {
Cursor cursor = ctxt.getContentResolver().query(contentUri, new String[]{MediaStore.MediaColumns.DISPLAY_NAME}, null, null, null);
String res = "";
if (cursor != null){
cursor.moveToFirst();
int nameIdx = cursor.getColumnIndex(MediaStore.MediaColumns.DISPLAY_NAME);
res = cursor.getString(nameIdx);
cursor.close();
}
return res;
}

Categories

Resources