I am starting an intent to pick a file, I do pick a file and I get a URI, which I obviously can't use.
I am trying to convert this Uri to a legit file path and for that I use this method
public string GetPathToImage(global::Android.Net.Uri uri)
{
string path = null;
// The projection contains the columns we want to return in our query.
string[] projection = new[] { global::Android.Provider.MediaStore.Images.Media.InterfaceConsts.Data };
using (global::Android.Database.ICursor cursor = ManagedQuery(uri, projection, null, null, null))
{
if (cursor != null)
{
int columnIndex = cursor.GetColumnIndexOrThrow(global::Android.Provider.MediaStore.Images.Media.InterfaceConsts.Data);
cursor.MoveToFirst();
path = cursor.GetString(columnIndex);
}
}
return path;
}
Problem: this method returns a null string. But I need a working one.
Any suggestions?
Related
I'm taking picture from camera and saving in a public folder(Pictures/myFolder) and I'm storing the Uri from picture to reload to my views, but I need build a File with real path, but I cant recover the path and all the codes they find on the internet give me null pointer, how can i recover the real path?
Uri example:
content://media/content://br.com.technolog.darwinchecklist.fileprovider/darwin_checklist_images/DARWIN_20180827_114154_460340375.jpg/images/media
Method that does not work
public String getRealPathFromURI(Uri uri) {
String path = "";
if (getContentResolver() != null) {
Cursor cursor = getContentResolver().query(uri, null, null, null, null);
if (cursor != null) {
cursor.moveToFirst();
int idx = cursor.getColumnIndex(MediaStore.Images.ImageColumns.DATA);
path = cursor.getString(idx);
cursor.close();
}
}
return path;
}
Ref: Get Real Path For Uri Android
getRealpathFromUri(Uri uri)
{
String[] filePathColumn = {MediaStore.Images.Media.DATA};
Cursor cursor = getContentResolver().query(uri, filePathColumn, null, null, null);
if (cursor == null)
{ // Source is Dropbox or other similar local file path
result = contentURI.getPath();
}
else
{
if(cursor.moveToFirst()){
int columnIndex = cursor.getColumnIndex(filePathColumn[0]);
//String yourRealPath = cursor.getString(columnIndex);
path = cursor.getString(columnIndex);
}
cursor.close();
}
return path;
}
I'm using the following code to get the real path of a document from an Uri:
/**
* Retrieve filename from Uri
*
* #param uri Uri following the schemes: "file" or "content"
* #param contentResolver ContentResolver to resolve content scheme
*
* #return filename if operation succeded. Can be null.
*/
public static String getFileName(#NonNull final Uri uri, #NonNull final ContentResolver contentResolver) {
String filename = "";
if (ContentResolver.SCHEME_FILE.equals(uri.getScheme())) {
filename = uri.getLastPathSegment();
} else if (ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) {
try {
Cursor cursor = contentResolver.query(uri, null, null, null, null);
int index = cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME);
cursor.moveToFirst();
filename = cursor.getString(index);
cursor.close();
} catch (Exception e) {
Log.e(TAG, "Exception when retrieving file name: " + e.getMessage());
}
}
return filename;
}
I have two applications, one contains content provider and other app receives data using content resolver. If i add any data form provider that should be displayed from receiver in second app, this is the expected functionality.But after adding data once I remove first app from stack then second app displays null cursor,If I keep first app in stack, then second app displays correct value .(This issue only comes in one plus devices)
code snippet where cursor value coming null is,
Cursor c = getContentResolver().query(CONTENT_URI, null, null, null,
null);
may be it will help you
private String uriToFilename(Uri uri) {
String path = null;
if (Build.VERSION.SDK_INT < 11) {
path = getRealPathFromURI_BelowAPI11(this, uri);
} else if (Build.VERSION.SDK_INT < 19) {
path = getRealPathFromURI_API11to18(this, uri);
} else {
path = getRealPathFromURI_API19(this, uri);
}
return path;
}
BelowAPI11
public static String getRealPathFromURI_BelowAPI11(Context context, Uri contentUri) {
String[] proj = {MediaStore.Images.Media.DATA};
Cursor 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);
}
API11to18
public static String getRealPathFromURI_API11to18(Context context, Uri contentUri) {
String[] proj = {MediaStore.Images.Media.DATA};
String result = null;
CursorLoader cursorLoader = new CursorLoader(
context,
contentUri, proj, null, null, null);
Cursor cursor = cursorLoader.loadInBackground();
if (cursor != null) {
int column_index =
cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
cursor.moveToFirst();
result = cursor.getString(column_index);
}
return result;
}
API19
public static String getRealPathFromURI_API19(Context context, Uri uri) {
Log.e("uri", uri.getPath());
String filePath = "";
if (DocumentsContract.isDocumentUri(context, uri)) {
String wholeID = DocumentsContract.getDocumentId(uri);
Log.e("wholeID", wholeID);
// Split at colon, use second item in the array
String[] splits = wholeID.split(":");
if (splits.length == 2) {
String id = splits[1];
String[] column = {MediaStore.Images.Media.DATA};
// where id is equal to
String sel = MediaStore.Images.Media._ID + "=?";
Cursor cursor = context.getContentResolver().query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
column, sel, new String[]{id}, null);
int columnIndex = cursor.getColumnIndex(column[0]);
if (cursor.moveToFirst()) {
filePath = cursor.getString(columnIndex);
}
cursor.close();
}
} else {
filePath = uri.getPath();
}
return filePath;
}
Enable Don’t optimize inside Settings to resolve one plus issue.
Settings –> Battery –> Battery Optimization –> Your App –> Don’t optimize
enter image description here
I am trying to access file from device. All works goods but when i browse and select file from google drive it gives null path. I have seen many question but didn't got the answer. One solution which i got below only gives me the file name.
public static String getGDriveDataColumn(Context context, Uri uri, String selection,
String[] selectionArgs) {
Cursor cursor = null;
final String column = "_display_name";
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;
}
Is it possible to get that file? Because that file is on the drive and not on the device. Please help me how can i get that file.
Most of the code snippets I've seen here and there about prompting user to pick a file or image, have the onActivityResult method use a function like the one below to get the chosen file path.
My question is why go through all that, when Uri has the ready to use function Uri.getPath() ? Are there advantages or dissadvantages in the one approach or the other?
onActivityResult code
Uri source = data.getData();
String fileName=getRealPathFromURI(this, source);
get path function
public static String getRealPathFromURI(Context context, Uri contentUri) {
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();
}
}
}
I actually had my app crashing using the getRealPathMethod when I picked a file/image from dropbox...while using the Uri.getPath() method i had no problem whatsoever. So..what's the deal here? Am I missing something?
Try like this way
final String [] consDirNames = new String[constDir.length];
// directory names
for(int i=0;i<constDir.length;i++){
consDirNames[i]=constDir[i].getName();
File booths[]= constDir[i].listFiles(new FileFilter() {
#Override
public boolean accept(File pathname) {
// TODO Auto-generated method stub
return pathname.getName().endsWith(".pdf");
}
}); ;
consDirMap.put(consDirNames[i], booths);
fileMap.put(consDirNames[i],constDir[i].getAbsolutePath() );
}
I call startActivityForResult with Intent ACTION_GET_CONTENT. Some app returns me data with this Uri:
content://media/external/images/media/18122
I don't know if it is image or video or some custom content. How do I use ContentResolver to get the actual file name or content title from this Uri?
#Durairaj's answer is specific to getting the path of a file. If what you're searching for is the file's actual name (since you should be using Content Resolution, at which point you'll probably get a lot of content:// URIs) you'll need to do the following:
(Code copied from Durairaj's answer and modified)
String[] projection = {MediaStore.MediaColumns.DISPLAY_NAME};
Cursor metaCursor = cr.query(uri, projection, null, null, null);
if (metaCursor != null) {
try {
if (metaCursor.moveToFirst()) {
fileName = metaCursor.getString(0);
}
} finally {
metaCursor.close();
}
}
The main piece to note here is that we're using MediaStore.MediaColumns.DISPLAY_NAME, which returns the actual name of the content. You might also try MediaStore.MediaColumns.TITLE, as I'm not sure what the difference is.
You can get file name from this code, or any other field by modifying the projection
String[] projection = {MediaStore.MediaColumns.DATA};
ContentResolver cr = getApplicationContext().getContentResolver();
Cursor metaCursor = cr.query(uri, projection, null, null, null);
if (metaCursor != null) {
try {
if (metaCursor.moveToFirst()) {
path = metaCursor.getString(0);
}
} finally {
metaCursor.close();
}
}
return path;
To get filename, you can use new DocumentFile format.
DocumentFile documentFile = DocumentFile.fromSingleUri(this, data.getdata());
String fileName = documentFile.getName();
For anyone using Kotlin who has the same problem, you can define an extension method to get the file name and size (in bytes) in one fell swoop. If it is unable to retrieve the fields, it returns null.
fun Uri.contentSchemeNameAndSize(): Pair<String, Int>? {
return contentResolver.query(this, null, null, null, null)?.use { cursor ->
if (!cursor.moveToFirst()) return#use null
val name = cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME)
val size = cursor.getColumnIndex(OpenableColumns.SIZE)
cursor.getString(name) to cursor.getInt(size)
}
}
Use it thusly
val nameAndSize = yourUri.contentNameAndSize()
// once you've confirmed that is not null, you can then do
val (name, size) = nameAndSize
It might throw an exception, but it hasn't ever done so for me (as long as the URI is a valid content:// URI).
private static String getRealPathFromURI(Context context, Uri contentUri)
{
String[] proj = { MediaStore.Images.Media.DATA };
CursorLoader loader = new CursorLoader(context, contentUri, proj, null, null, null);
Cursor cursor = loader.loadInBackground();
int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
cursor.moveToFirst();
String result = cursor.getString(column_index);
cursor.close();
return result;
}
The accepted answer is not complete. There are more checks missed out.
Here is what I have arrived at after a read of all the answers presented here as well what some Airgram has done in their SDKs - A utility that I have open sourced on Github:
https://github.com/mankum93/UriUtilsAndroid/tree/master/app/src/main/java/com/androiduriutils
Usage
As simple as calling, UriUtils.getDisplayNameSize(). It provides both the name and size of the content.
Note: Only works with a content:// Uri
Here is a glimpse on the code:
/**
* References:
* - https://www.programcreek.com/java-api-examples/?code=MLNO/airgram/airgram-master/TMessagesProj/src/main/java/ir/hamzad/telegram/MediaController.java
* - https://stackoverflow.com/questions/5568874/how-to-extract-the-file-name-from-uri-returned-from-intent-action-get-content
*
* #author Manish#bit.ly/2HjxA0C
* Created on: 03-07-2020
*/
public final class UriUtils {
public static final int CONTENT_SIZE_INVALID = -1;
/**
* #param context context
* #param contentUri content Uri, i.e, of the scheme <code>content://</code>
* #return The Display name and size for content. In case of non-determination, display name
* would be null and content size would be {#link #CONTENT_SIZE_INVALID}
*/
#NonNull
public static DisplayNameAndSize getDisplayNameSize(#NonNull Context context, #NonNull Uri contentUri){
final String scheme = contentUri.getScheme();
if(scheme == null || !scheme.equals(ContentResolver.SCHEME_CONTENT)){
throw new RuntimeException("Only scheme content:// is accepted");
}
final DisplayNameAndSize displayNameAndSize = new DisplayNameAndSize();
displayNameAndSize.size = CONTENT_SIZE_INVALID;
String[] projection = new String[]{MediaStore.Images.Media.DATA, OpenableColumns.DISPLAY_NAME, OpenableColumns.SIZE};
Cursor cursor = context.getContentResolver().query(contentUri, projection, null, null, null);
try {
if (cursor != null && cursor.moveToFirst()) {
// Try extracting content size
int sizeIndex = cursor.getColumnIndex(OpenableColumns.SIZE);
if (sizeIndex != -1) {
displayNameAndSize.size = cursor.getLong(sizeIndex);
}
// Try extracting display name
String name = null;
// Strategy: The column name is NOT guaranteed to be indexed by DISPLAY_NAME
// so, we try two methods
int nameIndex = cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME);
if (nameIndex != -1) {
name = cursor.getString(nameIndex);
}
if (nameIndex == -1 || name == null) {
nameIndex = cursor.getColumnIndex(MediaStore.Images.Media.DATA);
if (nameIndex != -1) {
name = cursor.getString(nameIndex);
}
}
displayNameAndSize.displayName = name;
}
}
finally {
if(cursor != null){
cursor.close();
}
}
// We tried querying the ContentResolver...didn't work out
// Try extracting the last path segment
if(displayNameAndSize.displayName == null){
displayNameAndSize.displayName = contentUri.getLastPathSegment();
}
return displayNameAndSize;
}
}
You can use the solution proposed by Durairaj with the following as the projection array:
String[] projection = { "_data" };