I'm not going to print out the entire stack trace cause it's huge, but essentially I'm trying to create a FileHandle for the file 'document/image:136635' and I'm getting no such file or directory.
com.badlogic.gdx.utils.GdxRuntimeException: Couldn't load file: /document/image:136635
Caused by: android.system.ErrnoException: open failed: ENOENT (No such file or directory)
So I'm using the path 'document/image:136635' because I launched an activity for the android gallery app so the user can select a photo of themselves for the avatar. The selection seems to works ok, we can select an image and my program continues afterwards, but they when I try to create a filehandle for the image so I can actually draw it in my game I have problems. When I analyse the data returned from the activity the path of the photo they selected comes back as 'document/image:136635'. Is that a valid path for an image ordinarily? If I use a file viewer on my phone I can see that there is a document folder but nothing is in it.
Any advice appreciated. Thanks.
edit: So the info in the URI is (in order):
image:136635
image/jpeg
IMG_20190702_175942.jpg
1562065182000
5
1285506
So I can get the actual filename, but still not the real path? I don't think...
private static final int GALLERY_PICK = 1;
Intent galleryIntent = new Intent(Intent.ACTION_PICK,
android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
startActivityForResult(galleryIntent, GALLERY_PICK);
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == GALLERY_PICK && resultCode == RESULT_OK && data != null &&
data.getData() != null) {
Uri uri = data.getData();
try {
String filePath = getPathNew(this,uri); //return actual path
} catch (IOException e) {
e.printStackTrace();
}
}
}
To get Actual Path--
@SuppressLint("NewApi")
public static String getPathNew(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];
}
// TODO handle non-primary volumes
}
// 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;
}
/**
* @param uri The Uri to check.
* @return Whether the Uri authority is ExternalStorageProvider.
*/
public static boolean isExternalStorageDocument(Uri uri) {
return "com.android.externalstorage.documents".equals(uri.getAuthority());
}
/**
* @param uri The Uri to check.
* @return Whether the Uri authority is DownloadsProvider.
*/
public static boolean isDownloadsDocument(Uri uri) {
return "com.android.providers.downloads.documents".equals(uri.getAuthority());
}
/**
* @param uri The Uri to check.
* @return Whether the Uri authority is MediaProvider.
*/
public static boolean isMediaDocument(Uri uri) {
return "com.android.providers.media.documents".equals(uri.getAuthority());
}
add file READ WRITE
permissions in your manifest
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
unfortunately uri.getPath() does not seem to return the actual filepath. e.g. it returns /document/image:136635, when in actual fact the file is /pictures/screenshots/Screenshot_2019-07-02-27-34-789.jpeg. I need the actual filepath so I can create a libgdx texture
@user8810083 see my edited answer.. getPathNew() will give you actual path of image.
I think getting closer but now I'm getting permission denied with this new getpathnew method. I tried the solution in this post stackoverflow.com/a/33292700/8810083 but am having some difficulty getting ActivityCompat to work with libgdx
After api 23 that is not enough. You can see they explain in that thread
getDataColumn(context, uri, null, null); will return path after api 19