I have Uri for Image file.
I use this code for gets file path from Uri:
public String getRealPathFromURI(Uri contentUri) {
Cursor cursor = null;
try {
String[] proj = { MediaStore.Images.Media.DATA };
cursor = mContext.getContentResolver().query(contentUri, proj, null, null, null);
int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
cursor.moveToFirst();
return cursor.getString(column_index);
} catch (Exception e) {
Log.message(e.getMessage());
} finally {
if (cursor != null) {
cursor.close();
}
}
return null;
}
If I choose image from Gallery app(Android 4.4.2, arm-emu),
uri.getPath = /external/images/media/16 and it work's fine (My file path: /storage/sdcard/Download/0_cf15a_7800a7e5_orig.jpg)
If I choose image from Documents app(Android 4.4.2, arm-emu),
I have uri.getPath = /document/image:16 and function getRealPathFromURI returns null.
How I can return correct path to file for boths action?
My Code Is:-
#Override
public void onClick(View v) {
final File root = new File(Environment.getExternalStorageDirectory() + File.separator + "Photohunt" + File.separator);
root.mkdirs();
final String fname = Common.getUniqueImageFilename();
final File sdImageMainDirectory = new File(root, fname);
outputFileUri = Uri.fromFile(sdImageMainDirectory);
// Camera.
final List<Intent> cameraIntents = new ArrayList<Intent>();
final Intent captureIntent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
final PackageManager packageManager = mContext.getPackageManager();
final List<ResolveInfo> listCam = packageManager.queryIntentActivities(captureIntent, 0);
for(ResolveInfo res : listCam) {
final String packageName = res.activityInfo.packageName;
final Intent intent = new Intent(captureIntent);
intent.setComponent(new ComponentName(res.activityInfo.packageName, res.activityInfo.name));
intent.setPackage(packageName);
intent.putExtra(MediaStore.EXTRA_OUTPUT, outputFileUri);
cameraIntents.add(intent);
}
// Filesystem.
final Intent galleryIntent = new Intent();
galleryIntent.setType("image/*");
galleryIntent.setAction(Intent.ACTION_GET_CONTENT);
// Chooser of filesystem options.
final Intent chooserIntent = Intent.createChooser(galleryIntent, "Select Source");
// Add the camera options.
chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, cameraIntents.toArray(new Parcelable[]{}));
startActivityForResult(chooserIntent, PICTURE_REQUEST_CODE);
}
Handle activity result:
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data)
{
if(resultCode == Activity.RESULT_OK)
{
if(requestCode == PICTURE_REQUEST_CODE)
{
final boolean isCamera;
if(data == null)
{
isCamera = true;
}
else
{
final String action = data.getAction();
if(action == null)
{
isCamera = false;
}
else
{
isCamera = action.equals(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
}
}
Uri selectedImageUri;
if(isCamera)
{
selectedImageUri = outputFileUri;
}
else
{
selectedImageUri = data == null ? null : data.getData();
}
Log.variable("uri", selectedImageUri.getPath());
ConfirmImageFragment fragment = new ConfirmImageFragment(selectedImageUri, mContestId);
FragmentTransaction transaction = getSherlockActivity().getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.main_container, fragment);
transaction.addToBackStack(null);
transaction.commit();
}
}
super.onActivityResult(requestCode, resultCode, data);
}
Loading selected file into ImageView works fine for both state:
private void loadImage() {
try {
Bitmap bitmap = MediaStore.Images.Media.getBitmap(mContext.getContentResolver(), mUri);
mImage.setImageBitmap(bitmap);
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
Solution:
public class RealPathUtil {
#SuppressLint("NewApi")
public static String getRealPathFromURI_API19(Context context, Uri uri){
String filePath = "";
String wholeID = DocumentsContract.getDocumentId(uri);
// 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 = 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();
return filePath;
}
#SuppressLint("NewApi")
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;
}
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);
}
}
http://hmkcode.com/android-display-selected-image-and-its-real-path/
A simpler version of the accepted answer that will detect the API level and use the correct method :
#TargetApi(Build.VERSION_CODES.KITKAT)
public static String getFilePath(Context context, Uri uri)
{
int currentApiVersion;
try
{
currentApiVersion = android.os.Build.VERSION.SDK_INT;
}
catch(NumberFormatException e)
{
//API 3 will crash if SDK_INT is called
currentApiVersion = 3;
}
if (currentApiVersion >= Build.VERSION_CODES.KITKAT)
{
String filePath = "";
String wholeID = DocumentsContract.getDocumentId(uri);
// 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 = 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();
return filePath;
}
else if (currentApiVersion <= Build.VERSION_CODES.HONEYCOMB_MR2 && currentApiVersion >= Build.VERSION_CODES.HONEYCOMB)
{
String[] proj = {MediaStore.Images.Media.DATA};
String result = null;
CursorLoader cursorLoader = new CursorLoader(
context,
uri, 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;
}
else
{
String[] proj = {MediaStore.Images.Media.DATA};
Cursor cursor = context.getContentResolver().query(uri, proj, null, null, null);
int column_index
= cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
cursor.moveToFirst();
return cursor.getString(column_index);
}
}
Here's my solution, using all tricks I've found so far, which I use on my own app too (here) :
FileUtilEx.kt
fun Closeable?.closeSilently() {
if (this != null) try {
this.close()
} catch (e: Exception) {
}
}
object FileUtilEx {
fun getFilePathFromUri(context: Context, uri: Uri, includeUriMappingTechnique: Boolean = true, tryToGetWritePermission: Boolean = false): ClosableFileHolder? {
var file: File
uri.path?.let {
file = File(it)
if (file.exists() && file.canRead()) {
// Log.d("AppLog", "got real file")
return ClosableFileHolder(file)
}
}
if (uri.scheme == "file") {
try {
val jUri = java.net.URI(uri.scheme, uri.schemeSpecificPart, uri.fragment)
file = File(jUri)
if (file.exists() && file.canRead()) {
// Log.d("AppLog", "got real file")
return ClosableFileHolder(file)
}
} catch (e: Exception) {
}
try {
val uriStr = uri.toString()
val decodePath = URLDecoder.decode(uriStr, "UTF-8")
file = File(decodePath)
if (file.exists() && file.canRead()) {
// Log.d("AppLog", "got real file")
return ClosableFileHolder(file)
}
} catch (e: UnsupportedEncodingException) {
}
}
val authority = uri.authority
if (uri.scheme == "content") {
//handles "Files" app, and many others
getRealPathFromUri(context, uri)?.let {
file = File(it)
if (file.exists() && file.canRead()) {
// Log.d("AppLog", "got real file")
return ClosableFileHolder(file)
}
}
}
if (includeUriMappingTechnique) {
val fileUsingUriMappingTechnique = getFileUsingUriMappingTechnique(context, uri, tryToGetWritePermission)
if (fileUsingUriMappingTechnique != null)
return fileUsingUriMappingTechnique
}
getFilePathFromDocumentUri(context, uri)?.let { filePath ->
file = File(filePath)
if (file.exists() && file.canRead())
return ClosableFileHolder(file)
}
return null
}
private fun getRealPathFromUri(context: Context, contentUri: Uri): String? {
try {
context.contentResolver.query(contentUri, arrayOf(MediaStore.Images.Media.DATA), null, null, null)?.use { cursor ->
val columnIndex = cursor.getColumnIndex(MediaStore.Images.Media.DATA)
if (columnIndex < 0 || cursor.count <= 0)
return null
cursor.moveToFirst()
return cursor.getString(columnIndex)
}
} catch (e: Exception) {
e.printStackTrace()
}
return null
}
fun getFileUsingUriMappingTechnique(context: Context, androidUri: Uri, tryToGetWritePermission: Boolean = false): ClosableFileHolder? {
var parcelFileDescriptor: ParcelFileDescriptor? = null
for (i in 0..1)
try {
parcelFileDescriptor = context.contentResolver.openFileDescriptor(androidUri, if (tryToGetWritePermission && i == 0) "w" else "r")
if (parcelFileDescriptor != null) {
val fd: Int = parcelFileDescriptor.fd
val linkFileName = "/proc/self/fd/$fd"
if (VERSION.SDK_INT >= VERSION_CODES.O) {
val realFilePath = Files.readSymbolicLink(Paths.get(linkFileName))
val file = realFilePath.toFile()
if (file.exists() && file.canRead()) {
parcelFileDescriptor.closeSilently()
return ClosableFileHolder(file)
}
}
val file = File(linkFileName)
if (file.exists() && file.canRead())
return ClosableFileHolder(file, parcelFileDescriptor)
parcelFileDescriptor.closeSilently()
}
} catch (e: Exception) {
parcelFileDescriptor.closeSilently()
parcelFileDescriptor = null
}
return null
}
private fun getFilePathFromDocumentUri(context: Context, uri: Uri): String? {
// https://stackoverflow.com/questions/5657411/android-getting-a-file-uri-from-a-content-uri
// DocumentProvider
if (VERSION.SDK_INT >= VERSION_CODES.KITKAT && DocumentFile.isDocumentUri(context, uri)) {
// ExternalStorageProvider
if ("com.android.externalstorage.documents" == uri.authority) {
val docId = DocumentsContract.getDocumentId(uri)
val split = docId.split(":".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
val type = split[0]
// This is for checking Main Memory
return if ("primary".equals(type, ignoreCase = true)) {
if (split.size > 1) {
Environment.getExternalStorageDirectory().absolutePath + "/" + split[1] + "/"
} else {
Environment.getExternalStorageDirectory().absolutePath + "/"
}
// This is for checking SD Card
} else {
"storage" + "/" + docId.replace(":", "/")
}
}
}
return null
}
}
ClosableFileHolder.kt
class ClosableFileHolder(val file: File, private val parcelFileDescriptor: ParcelFileDescriptor? = null) : Closeable {
fun isUsingUriMappingTechnique(): Boolean = parcelFileDescriptor != null
override fun close() {
parcelFileDescriptor.closeSilently()
}
protected fun finalize() {
parcelFileDescriptor.closeSilently()
}
}
Usage:
FileUtilEx.getFilePathFromUri(context, uri, false)?.use {
val file = it.file
...
}
The tryToGetWritePermission parameter is in case you want to access the file, but it's in fact not available normally (like in SAF), so it's offered you in a different place. This is useful in case you want to access the file but don't care where it really exists.
Make sure you give permission in Manifest.
Wasted 2 hours trying various methods without giving permissions :/
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
I think this should work. A generalized code for getting URI from path :
String path = yourAndroidURI.uri.getPath()
File file = new File(new URI(path));
So I tried basically ever answer on the stack but this was the only one that worked for me. It is important to think about the uri as a "promise" that an image lives where it points to. This does not mean there is a file at that location but if you ask correctly you will get an image. attachementPath is the path to the image (can be used like a regular file). See below:
try {
InputStream input = getActivity().getContentResolver().openInputStream(imageUri);
File file = new File(getActivity().getCacheDir(), "cacheFileAppeal.png");
try {
OutputStream output = new FileOutputStream(file);
try {
try {
byte[] buffer = new byte[4 * 1024]; // or other buffer size
int read;
if (input != null) {
while ((read = input.read(buffer)) != -1) {
output.write(buffer, 0, read);
}
}
output.flush();
} finally {
output.close();
attachmentPath = file.getAbsolutePath();
}
} catch (Exception e) {
e.printStackTrace(); // handle exception, define IOException and others
}
} finally {
try {
if (input != null) {
input.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
} catch (FileNotFoundException e) {
e.printStackTrace();
}
public static int getIdFromUri(Uri uri, String constantId)
{
Cursor c = ContentMaster.getContentResolver().query(uri, new String[]{constantId}, null, null, null);
int res = -1;
if(c != null && c.getCount() > 0)
{
c.moveToFirst();
res = c.getInt(0);
c.close();
}
return res;
}
public static Uri getUriWithId(Uri baseUri,int contactId)
{
Uri u = ContentUris.withAppendedId(baseUri, contactId);
if(u != null)
return u;
return Uri.EMPTY;
}
public static String getRealPathFromURI(Uri uri)
{
if(uri == null)
return "";
if ("file".equalsIgnoreCase(uri.getScheme()))
return uri.getPath();
String[] pro = { MediaStore.Images.Media.DATA };
String result = null;
Cursor cursor;
if(VERSION.SDK_INT > 18)
{
//String wholeID = DocumentsContract.getDocumentId(uri);
//String id = wholeID.split(":")[1];
String id = String.valueOf(getIdFromUri(uri, Images.Media._ID));
String[] column = { MediaStore.Images.Media.DATA };
String where = MediaStore.Images.Media._ID + "=?";
Uri u = uri;
if(isMediaDocument(uri))
{
if (getUriMediaDocumentType(uri).equals("image"))
{
if(isExternalStorageDocument(uri))
u = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
else
u = MediaStore.Images.Media.INTERNAL_CONTENT_URI;
}
else if (getUriMediaDocumentType(uri).equals("video"))
{
if(isExternalStorageDocument(uri))
u = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
else
u = MediaStore.Video.Media.INTERNAL_CONTENT_URI;
}
else if (getUriMediaDocumentType(uri).equals("audio"))
{
if(isExternalStorageDocument(uri))
u = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
else
u = MediaStore.Audio.Media.INTERNAL_CONTENT_URI;
}
}
else if(isDownloadsDocument(uri))
{
u = getUriWithId(Uri.parse("content://downloads/public_downloads"), Integer.getInteger(id));
}
cursor = getContentResolver().query(u, column, where, new String[]{id}, null);
}
else if(VERSION.SDK_INT > 10)
{
CursorLoader cursorLoader = new CursorLoader(SystemMaster.getContext(), uri, pro, null, null, null);
cursor = cursorLoader.loadInBackground();
}
else
{
cursor = SystemMaster.getContext().getContentResolver().query(uri, pro, null, null, null);
}
if(cursor != null && cursor.getCount() > 0)
{
cursor.moveToFirst();
result = cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media.DATA));
cursor.close();
}
return result;
}
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 String getUriMediaDocumentType(Uri uri)
{
if(isMediaDocument(uri))
{
//TODO
return "image";
}
return "";
}
Related
Sorry for the long post.
I want to upload different types of files to our server from Android using API.
I am using the below code for file pick
Intent pickDocument = new Intent(Intent.ACTION_GET_CONTENT);
pickDocument.addCategory(Intent.CATEGORY_OPENABLE);
pickDocument.setType("*/*");
activity.startActivityForResult(Intent.createChooser(pickDocument, "ChooseFile"), requestCode);
And I am using the below class to get the file path from URI.
public class UriUtils {
private static Uri contentUri = null;
private static MimeTypeMap mimeType = MimeTypeMap.getSingleton();
#SuppressLint("NewApi")
public static String getPathFromUri(final Context context, final Uri uri) {
// check here to is it KITKAT or new version
final boolean isKitKatOrAbove = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;
String selection = null;
String[] selectionArgs = null;
// DocumentProvider
if (isKitKatOrAbove && DocumentsContract.isDocumentUri(context, uri)) {
// ExternalStorageProvider
if (isExternalStorageDocument(uri)) {
final String docId = DocumentsContract.getDocumentId(uri);
final String[] split = docId.split(":");
final String type = split[0];
String fullPath = getPathFromExtSD(split);
if (fullPath != "") {
return fullPath;
} else {
return null;
}
} else if (isDownloadsDocument(uri)) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
final String id;
Cursor cursor = null;
try {
cursor = context.getContentResolver().query(uri, new String[]{MediaStore.MediaColumns.DISPLAY_NAME}, null, null, null);
if (cursor != null && cursor.moveToFirst()) {
String fileName = cursor.getString(0);
String path = Environment.getExternalStorageDirectory().toString() + "/Download/" + fileName;
if (!TextUtils.isEmpty(path)) {
return path;
}
}
} finally {
if (cursor != null)
cursor.close();
}
id = DocumentsContract.getDocumentId(uri);
if (!TextUtils.isEmpty(id)) {
if (id.startsWith("raw:")) {
return id.replaceFirst("raw:", "");
}
String[] contentUriPrefixesToTry = new String[]{
"content://downloads/public_downloads",
"content://downloads/my_downloads"
};
for (String contentUriPrefix : contentUriPrefixesToTry) {
try {
final Uri contentUri = ContentUris.withAppendedId(Uri.parse(contentUriPrefix), Long.valueOf(id));
return getDataColumn(context, contentUri, null, null);
} catch (NumberFormatException e) {
//In Android 8 and Android P the id is not a number
return uri.getPath().replaceFirst("^/document/raw:", "").replaceFirst("^raw:", "");
}
}
}
} else {
final String id = DocumentsContract.getDocumentId(uri);
if (id.startsWith("raw:")) {
return id.replaceFirst("raw:", "");
}
try {
contentUri = ContentUris.withAppendedId(
Uri.parse("content://downloads/public_downloads"), Long.valueOf(id));
} catch (NumberFormatException e) {
e.printStackTrace();
}
if (contentUri != null) {
return getDataColumn(context, contentUri, null, null);
}
}
} else if (isMediaDocument(uri)) {
final String docId = DocumentsContract.getDocumentId(uri);
final String[] split = docId.split(":");
final String type = split[0];
selection = "_id=?";
selectionArgs = new String[]{split[1]};
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;
}
return getDataColumn(context, contentUri, selection, selectionArgs);
} else if (isGoogleDriveUri(uri)) {
return getDriveFilePath(uri, context);
}
} else if ("content".equalsIgnoreCase(uri.getScheme())) {
if (isGooglePhotosUri(uri)) {
return uri.getLastPathSegment();
}
if (isGoogleDriveUri(uri)) {
return getDriveFilePath(uri, context);
}
if (Build.VERSION.SDK_INT == Build.VERSION_CODES.N) {
return getMediaFilePathForN(uri, context);
} else {
return copyFromSource(uri, context);
}
} else if ("file".equalsIgnoreCase(uri.getScheme())) {
return uri.getPath();
}
return null;
}
private static boolean fileExists(String filePath) {
File file = new File(filePath);
return file.exists();
}
private static String getPathFromExtSD(String[] pathData) {
final String type = pathData[0];
final String relativePath = "/" + pathData[1];
String fullPath = "";
if ("primary".equalsIgnoreCase(type)) {
fullPath = Environment.getExternalStorageDirectory() + relativePath;
if (fileExists(fullPath)) {
return fullPath;
}
}
fullPath = System.getenv("SECONDARY_STORAGE") + relativePath;
if (fileExists(fullPath)) {
return fullPath;
}
fullPath = System.getenv("EXTERNAL_STORAGE") + relativePath;
if (fileExists(fullPath)) {
return fullPath;
}
return fullPath;
}
private static String getDriveFilePath(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.getCacheDir(), 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);
}
inputStream.close();
outputStream.close();
} catch (Exception e) {
e.printStackTrace();
}
return file.getPath();
}
private static String getMediaFilePathForN(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);
}
inputStream.close();
outputStream.close();
} catch (Exception e) {
e.printStackTrace();
}
return file.getPath();
}
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 index = cursor.getColumnIndexOrThrow(column);
return cursor.getString(index);
}
} finally {
if (cursor != null)
cursor.close();
}
return null;
}
private static String copyFromSource(Uri uri, Context context) {
ContentResolver contentResolver = context.getContentResolver();
String fileExtension = getFileExtension(uri, contentResolver);
String fileName = queryName(uri, contentResolver);
if (fileName == null)
fileName = getFileName(fileExtension);
// the file which will be the new cached file
File filePath = context.getExternalFilesDir(Environment.DIRECTORY_DOCUMENTS);
File outputFile = new File(filePath, fileName);
try {
InputStream inputStream = context.getContentResolver().openInputStream(uri);
FileOutputStream outputStream = new FileOutputStream(outputFile);
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);
}
inputStream.close();
outputStream.close();
} catch (Exception e) {
e.printStackTrace();
}
return outputFile.getAbsolutePath();
}
#SuppressLint("Recycle")
private static String queryName(Uri uri, ContentResolver contentResolver) {
Cursor returnCursor = contentResolver.query(uri, null, null, null, null);
if (returnCursor == null)
return null;
int nameIndex = returnCursor.getColumnIndex(OpenableColumns.DISPLAY_NAME);
if (nameIndex == -1)
return null;
returnCursor.moveToFirst();
String name = returnCursor.getString(nameIndex);
returnCursor.close();
return name;
}
private static String getFileExtension(Uri uri, ContentResolver contentResolver) {
return mimeType.getExtensionFromMimeType(contentResolver.getType(uri));
}
private static String getFileName(String fileExtension) {
return System.currentTimeMillis() + fileExtension + "";
}
private static boolean isExternalStorageDocument(Uri uri) {
return "com.android.externalstorage.documents".equals(uri.getAuthority());
}
private static boolean isDownloadsDocument(Uri uri) {
return "com.android.providers.downloads.documents".equals(uri.getAuthority());
}
private static boolean isMediaDocument(Uri uri) {
return "com.android.providers.media.documents".equals(uri.getAuthority());
}
private static boolean isGooglePhotosUri(Uri uri) {
return "com.google.android.apps.photos.content".equals(uri.getAuthority());
}
private static boolean isGoogleDriveUri(Uri uri) {
return "com.google.android.apps.docs.storage".equals(uri.getAuthority()) || "com.google.android.apps.docs.storage.legacy".equals(uri.getAuthority());
}
}
This code is working fine in Android 10 and below. But I am getting issue in Android 12
If I pick a file which is a document(doc, pdf, excel, txt) other than an image, video, and audio, I am getting path null.
In Android 12(Pixel 3), I got below URI
content://com.android.providers.media.documents/document/document%3A27958
So according to the above code, this is Media Document.
private static boolean isMediaDocument(Uri uri) {
return "com.android.providers.media.documents".equals(uri.getAuthority());
}
And If the file is media I am handling only 3 types of files
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;
}
How to get contentUri if there are document files(doc, excel, pdf, txt)?
This is working for me.
if ("image".equals(type)) {
uri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
} else if ("video".equals(type)) {
uri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
} else if ("audio".equals(type)) {
uri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
}else if ("document".equals(type)) {
uri = MediaStore.Files.getContentUri("external");
}
You can save your document files in an temp folder and return its address.
For example, Telegram messenger stores these types of files in this path:
Android\data\org.telegram.messenger\cache\sharing
Example for your code:
String tempPath = getPathFromUri(context, uri);
if (tempPath == null) {
tempPath = MediaController.copyFileToCache(uri, "file");
if (tempPath == null) {
showAttachmentError();
return;
}
}
The below shows the way how I tried and it gives me NulllPointException: Uri While selecting a PDF file from the recent files folder in Android 11.
Please let me know How to get pdf file path from recent folder
if (Build.VERSION.SDK_INT == Build.VERSION_CODES.R) {
if (Environment.isExternalStorageManager()) {
//todo when permission is granted
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
intent.addCategory(Intent.CATEGORY_OPENABLE);
intent.setType("*/*");
String[] mimetypes = {"image/*", "application/*"};
intent.putExtra(Intent.EXTRA_MIME_TYPES, mimetypes);
intent.putExtra(DocumentsContract.EXTRA_INITIAL_URI, path);
startActivityForResult(intent, REQ_PDF);
} else {
//request for the permission
Intent intent = new Intent(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION);
Uri uri = Uri.fromParts("package", getPackageName(), null);
intent.setData(uri);
startActivity(intent);
}
} else {
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
intent.addCategory(Intent.CATEGORY_OPENABLE);
intent.setType("*/*");
String[] mimetypes = {"image/*", "application/*"};
intent.putExtra(Intent.EXTRA_MIME_TYPES, mimetypes);
intent.putExtra(DocumentsContract.EXTRA_INITIAL_URI, path);
startActivityForResult(intent, REQ_PDF);
}
}
});
#SuppressLint({"SetTextI18n", "NewApi"})
#Override
public void onActivityResult(int requestCode, int resultCode, #Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
InputStream inputStream = null;
try {
if (requestCode == REQ_PDF && resultCode == RESULT_OK && data != null) {
path = data.getData();
inputStream = this.getContentResolver().openInputStream(path);
byte[] pdfInBytes = new byte[inputStream.available()];
inputStream.read(pdfInBytes);
// Toast.makeText(getContext(), ""+value, Toast.LENGTH_SHORT).show();
String encodedCode = Base64.encodeToString(pdfInBytes, Base64.DEFAULT);
filePath = PathUtil.getPathFromUri(this, path);
// filePath= FileUtils.getPath(this,path);
if (filePath == null) {
// Toast.makeText(this, "null", Toast.LENGTH_SHORT).show();
SharedPrefMannager.showAlertDialog(InvoiceGenerationActivity.this, "Alert!", "Please select a file from internal storage", true);
} else {
file = new File(filePath);
file_size = Integer.parseInt(String.valueOf(file.length() / 1024));
}
tv_attachFile.setText("Change File");
tv_fileLocation.setVisibility(View.VISIBLE);
tv_fileLocation.setText(filePath);
//Toast.makeText(getContext(), encodedCode, Toast.LENGTH_SHORT).show();
}
} catch (IOException e) {
e.printStackTrace();
Toast.makeText(InvoiceGenerationActivity.this, "Something went wrong " + e, Toast.LENGTH_SHORT).show();
}
}
public class PathUtil
{
private static Uri contentUri = null;
#SuppressLint("NewApi")
public static String getPathFromUri(final Context context, final Uri uri) {
// check here to is it KITKAT or new version
final boolean isKitKatOrAbove = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;
String selection = null;
String[] selectionArgs = null;
// DocumentProvider
if (isKitKatOrAbove && DocumentsContract.isDocumentUri(context, uri)) {
// ExternalStorageProvider
if (isExternalStorageDocument(uri)) {
String docId = DocumentsContract.getDocumentId(uri);
String[] split = docId.split(":");
final String type = split[0];
String fullPath = getPathFromExtSD(split);
if (fullPath != "") {
return fullPath;
} else {
return null;
}
//return getPathFromExtSD(split);
/* String fullPath =Environment.getExternalStorageState() + "/" + split[1];
if (fullPath != "") {
return fullPath;
} else {
return null;
}*/
}
// DownloadsProvider
else if (isDownloadsDocument(uri)) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
final String id;
Cursor cursor = null;
try {
cursor = context.getContentResolver().query(uri, new String[]{MediaStore.MediaColumns.DISPLAY_NAME}, null, null, null);
if (cursor != null && cursor.moveToFirst()) {
String fileName = cursor.getString(0);
String path = getExternalStorageDirectory().toString() + "/Download/" + fileName;
if (!TextUtils.isEmpty(path)) {
return path;
}
}
} finally {
if (cursor != null)
cursor.close();
}
id = DocumentsContract.getDocumentId(uri);
if (!TextUtils.isEmpty(id)) {
if (id.startsWith("raw:")) {
return id.replaceFirst("raw:", "");
}
String[] contentUriPrefixesToTry = new String[]{
"content://downloads/public_downloads",
"content://downloads/my_downloads",
"content://downloads/all_downloads"
};
for (String contentUriPrefix : contentUriPrefixesToTry) {
try {
final Uri contentUri = ContentUris.withAppendedId(Uri.parse(contentUriPrefix), Long.valueOf(id));
return getDataColumn(context, contentUri, null, null);
} catch (NumberFormatException e) {
//In Android 8 and Android P the id is not a number
return uri.getPath().replaceFirst("^/document/raw:", "").replaceFirst("^raw:", "");
}
}
}
} else {
final String id = DocumentsContract.getDocumentId(uri);
if (id.startsWith("raw:")) {
return id.replaceFirst("raw:", "");
}
try {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
contentUri = ContentUris.withAppendedId(
Uri.parse("content://downloads/public_downloads"), Long.parseLong(id)); //public
}
if (contentUri != null) {
return getDataColumn(context, contentUri, null, null);
}
} catch (NumberFormatException e) {
e.printStackTrace();
Toast.makeText(context, "" + e, Toast.LENGTH_SHORT).show();
}
}
}
// 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 ("application".equals(type)) {
contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI; //MediaStore.Video.Media.EXTERNAL_CONTENT_URI
} else if ("audio".equals(type)) {
contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
}
selection = "_id=?";
selectionArgs = new String[]{split[1]};
return getDataColumn(context, contentUri, selection,
selectionArgs);
} else if (isGoogleDriveUri(uri)) {
return getDriveFilePath(uri, context);
}
} else if ("content".equalsIgnoreCase(uri.getScheme())) {
if (isGooglePhotosUri(uri)) {
return uri.getLastPathSegment();
}
if (isGoogleDriveUri(uri)) {
return getDriveFilePath(uri, context);
}
if (Build.VERSION.SDK_INT == Build.VERSION_CODES.N) {
return getMediaFilePathForN(uri, context);
} else {
return getDataColumn(context, uri, null, null);
}
}
// File
else if ("file".equalsIgnoreCase(uri.getScheme())) {
return uri.getPath();
}
return null;
}
private static boolean fileExists(String filePath) {
File file = new File(filePath);
return file.exists();
}
private static String getPathFromExtSD(String[] pathData) {
String type = pathData[0];
String relativePath = "/" + pathData[1];
String fullPath = "";
if ("primary".equalsIgnoreCase(type)) {
fullPath = getExternalStorageDirectory() + relativePath;
if (fileExists(fullPath)) {
return fullPath;
}
}
fullPath = System.getenv("SECONDARY_STORAGE") + relativePath;
if ((null == fullPath) || (fullPath.length() == 0)) {
fullPath = System.getenv("SECONDARY_SDCARD_STORAGE");
return fullPath;
}
/* if (fileExists(fullPath)) {
return fullPath;
}*/
fullPath = System.getenv("EXTERNAL_STORAGE") + relativePath;
if ((null == fullPath) || (fullPath.length() == 0)) {
fullPath = System.getenv("EXTERNAL_SDCARD_STORAGE");
return fullPath;
}
/* if (fileExists(fullPath)) {
return fullPath;
}*/
return fullPath;
}
private static String getDriveFilePath(Uri uri, Context context) {
Uri returnUri = uri;
Cursor returnCursor = context.getContentResolver().query(returnUri, null, null, null, null);
InputStream inputStream = null;
FileOutputStream outputStream = 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.getCacheDir(), name);
try {
inputStream = context.getContentResolver().openInputStream(uri);
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());
} finally {
if (inputStream != null) {
try {
inputStream.close();
} catch (Exception e) {
}
}
if (outputStream != null) {
try {
outputStream.close();
} catch (Exception e) {
}
}
}
return file.getPath();
}
private static String getMediaFilePathForN(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();
}
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 index = cursor.getColumnIndexOrThrow(column);
return cursor.getString(index);
}
} catch (Exception e) {
// Toast.makeText(context, "Something went wrong", Toast.LENGTH_SHORT).show();
} finally {
if (cursor != null)
cursor.close();
}
return null;
}
private static boolean isExternalStorageDocument(Uri uri) {
return "com.android.externalstorage.documents".equals(uri.getAuthority());
}
private static boolean isDownloadsDocument(Uri uri) {
return "com.android.providers.downloads.documents".equals(uri.getAuthority());
}
private static boolean isMediaDocument(Uri uri) {
return "com.android.providers.media.documents".equals(uri.getAuthority());
}
private static boolean isGooglePhotosUri(Uri uri) {
return "com.google.android.apps.photos.content".equals(uri.getAuthority());
}
private static boolean isGoogleDriveUri(Uri uri) {
return "com.google.android.apps.docs.storage".equals(uri.getAuthority()) || "com.google.android.apps.docs.storage.legacy".equals(uri.getAuthority());
}
}
Any help would be appreciated. I am testing on an android R device. Why is it that when selecting the file from a RECENT section in the file browser I am not getting any file path meanwhile selecting the same file in the STORAGE section is returning file path?
I have added only that else part and it's working fine. thank you for helping. referece
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;
}else {
contentUri = MediaStore.Files.getContentUri("external");
}
private void openCamera(int imageArray){
Intent cameraIntent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
fileUri = Uri.fromFile(new File(Environment.getExternalStorageDirectory()+"/SurveyDA/assets/images","absen_" +
System.currentTimeMillis() + ".jpg"));
Log.d("ddddd : ", String.valueOf(fileUri));
cameraIntent.putExtra(android.provider.MediaStore.EXTRA_OUTPUT, fileUri);
startActivityForResult(cameraIntent, imageArray);
}
when I want open camera, I set the fileuri, and Log success return uri
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == RESULT_OK) {
try {
//getting bitmap object from uri
Log.d("ddddd : ", String.valueOf(fileUri));
bitmapImage[requestCode] = MediaStore.Images.Media.getBitmap(this.getContentResolver(), fileUri);
// Initialize a new ByteArrayStream
ByteArrayOutputStream stream = new ByteArrayOutputStream();
// Compress the bitmap with JPEG format and quality 50%
bitmapImage[requestCode].compress(Bitmap.CompressFormat.JPEG,60,stream);
byte[] byteArray = stream.toByteArray();
Bitmap bitmap = BitmapFactory.decodeByteArray(byteArray,0,byteArray.length);
bitmapImage[requestCode] = Bitmap.createScaledBitmap(bitmap, bitmap.getWidth(), bitmap.getHeight(), false);
//displaying selected image to imageview
imageViews[requestCode].setImageBitmap(bitmapImage[requestCode]);
//calling the method uploadBitmap to upload image
} catch (IOException e) {
e.printStackTrace();
}
}else if(resultCode == Activity.RESULT_CANCELED) {
// User Cancelled the actiongetUriForFile
}
}
but in onActivityResult variable fileuri sometimes get null, and sometimes success return uri. And when I try in other phone Android 8.0.0, there no error.
how to fix that?
java.lang.RuntimeException: Unable to resume activity {com.example.surveyonlineda/com.example.surveyonlineda.Activity.AbsenActivity}: java.lang.RuntimeException: Failure delivering result ResultInfo{who=null, request=100, result=-1, data=null} to activity {com.example.surveyonlineda/com.example.surveyonlineda.Activity.AbsenActivity}: java.lang.NullPointerException
Refer this Document for your issue you will get best solution
as I see, the fileUri is not returned by onActivityResult. You create it before start your cameraIntent. So in case your activity has been destroyed, the fileUri will null. To prevent it, I think you should use onSaveInstanceState to save the fileUri.
Here is an example to save the string fileUri
#Override protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Check whether we're recreating a previously destroyed instance
if (savedInstanceState != null) {
// Restore value of fileUri from saved state
fileUri = savedInstanceState.getString(FILE_URI);
} else {
// Probably initialize values for a new instance
}
}
#Override protected void onSaveInstanceState(Bundle savedInstanceState) {
savedInstanceState.putString(FILE_URI, fileUri);
// Always call the superclass so it can save the view hierarchy state
super.onSaveInstanceState(savedInstanceState);
}
You can try it. it worked for me
Step 1. Create class GetPathFromUri.class
import android.annotation.SuppressLint;
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.provider.OpenableColumns;
import android.util.Log;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import java.io.*;
public class GetPathFromUri {
#SuppressLint("NewApi")
public static String getPath(final Context context, final Uri uri) {
#SuppressLint("ObsoleteSdkInt") 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];
}
if ("raw".equalsIgnoreCase(type)) {
return Environment.getExternalStorageDirectory() + "/" + split[1];
}
// TODO handle non-primary volumes
if ("5D68-9217".equalsIgnoreCase(type)) {
return Environment.getExternalStorageDirectory() + "/" + split[1];
}
}
// DownloadsProvider
else if (isDownloadsDocument(uri)) {
final String id = DocumentsContract.getDocumentId(uri);
if (id != null && id.startsWith("raw:")) {
return id.substring(4);
}
String[] contentUriPrefixesToTry = new String[]{
"content://downloads/public_downloads",
"content://downloads/my_downloads"
};
for (String contentUriPrefix : contentUriPrefixesToTry) {
Uri contentUri = ContentUris.withAppendedId(Uri.parse(contentUriPrefix), Long.valueOf(id));
try {
String path = getDataColumn(context, contentUri, null, null);
if (path != null) {
return path;
}
} catch (Exception e) {}
}
// path could not be retrieved using ContentResolver, therefore copy file to accessible cache using streams
String fileName = getFileName(context, uri);
File cacheDir = getDocumentCacheDir(context);
File file = generateFileName(fileName, cacheDir);
String destinationPath = null;
if (file != null) {
destinationPath = file.getAbsolutePath();
saveFileFromUri(context, uri, destinationPath);
}
return destinationPath;
}
// 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;
}
/**
* Get the value of the data column for this Uri. This is useful for
* MediaStore Uris, and other file-based ContentProviders.
*
* #param context The context.
* #param uri The Uri to query.
* #param selection (Optional) Filter used in the query.
* #param selectionArgs (Optional) Selection arguments used in the query.
* #return The value of the _data column, which is typically a file path.
*/
private static String getDataColumn(Context context, Uri uri, String selection,
String[] selectionArgs) {
final String column = "_data";
final String[] projection = {column};
try (Cursor 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);
}
}
return null;
}
/**
* #param uri The Uri to check.
* #return Whether the Uri authority is ExternalStorageProvider.
*/
private 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.
*/
private 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.
*/
private static boolean isMediaDocument(Uri uri) {
return "com.android.providers.media.documents".equals(uri.getAuthority());
}
public static String getFileName(#NonNull Context context, Uri uri) {
String mimeType = context.getContentResolver().getType(uri);
String filename = null;
if (mimeType == null && context != null) {
String path = getPath(context, uri);
if (path == null) {
filename = getName(uri.toString());
} else {
File file = new File(path);
filename = file.getName();
}
} else {
Cursor returnCursor = context.getContentResolver().query(uri, null,
null, null, null);
if (returnCursor != null) {
int nameIndex = returnCursor.getColumnIndex(OpenableColumns.DISPLAY_NAME);
returnCursor.moveToFirst();
filename = returnCursor.getString(nameIndex);
returnCursor.close();
}
}
return filename;
}
public static String getName(String filename) {
if (filename == null) {
return null;
}
int index = filename.lastIndexOf('/');
return filename.substring(index + 1);
}
public static File getDocumentCacheDir(#NonNull Context context) {
File dir = new File(context.getCacheDir(), DOCUMENTS_DIR);
if (!dir.exists()) {
dir.mkdirs();
}
logDir(context.getCacheDir());
logDir(dir);
return dir;
}
public static final String DOCUMENTS_DIR = "documents";
static final String TAG = "FileUtils";
private static final boolean DEBUG = false; // Set to true to enable logging
private static void logDir(File dir) {
if (!DEBUG) return;
Log.d(TAG, "Dir=" + dir);
File[] files = dir.listFiles();
for (File file : files) {
Log.d(TAG, "File=" + file.getPath());
}
}
#Nullable
public static File generateFileName(#Nullable String name, File directory) {
if (name == null) {
return null;
}
File file = new File(directory, name);
if (file.exists()) {
String fileName = name;
String extension = "";
int dotIndex = name.lastIndexOf('.');
if (dotIndex > 0) {
fileName = name.substring(0, dotIndex);
extension = name.substring(dotIndex);
}
int index = 0;
while (file.exists()) {
index++;
name = fileName + '(' + index + ')' + extension;
file = new File(directory, name);
}
}
try {
if (!file.createNewFile()) {
return null;
}
} catch (IOException e) {
Log.w(TAG, e);
return null;
}
logDir(directory);
return file;
}
private static void saveFileFromUri(Context context, Uri uri, String destinationPath) {
InputStream is = null;
BufferedOutputStream bos = null;
try {
is = context.getContentResolver().openInputStream(uri);
bos = new BufferedOutputStream(new FileOutputStream(destinationPath, false));
byte[] buf = new byte[1024];
is.read(buf);
do {
bos.write(buf);
} while (is.read(buf) != -1);
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (is != null) is.close();
if (bos != null) bos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
Step 2:
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == RESULT_OK) {
try {
String path = GetPathFromUri.getPath(this, data.getData())
Glide.with(this).load(path).into(imageView);
// Glide is library https://github.com/bumptech/glide
} catch (IOException e) {
e.printStackTrace();
}
}else if(resultCode == Activity.RESULT_CANCELED) {
// User Cancelled the actiongetUriForFile
}
}
I am working on a address book like Android SDK 14+ app. The users should be able to pick an image from the Gallery to add it to a contact entry.
Running the following code to pick and copy the image is no problem in API 14-20 but does not work in API 21+. The file is not found anymore:
protected void pickFoto() {
if (filePermissionsRequired()) {
askForFilePermissions(new PermissionRequestCompletionHandler() {
#Override
public void onPermissionRequestResult(boolean permissionGranted) {
if (permissionGranted)
addOrEditReceipt();
}
});
return;
}
Intent pickPhotoIntent = new Intent(Intent.ACTION_PICK, android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
startActivityForResult(pickPhotoIntent , PICK_FOTO_ACTION);
}
protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
super.onActivityResult(requestCode, resultCode, intent);
if (resultCode == Activity.RESULT_OK) {
switch (requestCode) {
...
case PICK_FOTO_ACTION: {
Uri imageUri = intent.getData();
String[] filePathColumn = {MediaStore.Images.Media.DATA};
Cursor cursor = getContentResolver().query(imageUri, filePathColumn, null, null, null);
cursor.moveToFirst();
int columnIndex = cursor.getColumnIndex(filePathColumn[0]);
String filePath = cursor.getString(columnIndex);
cursor.close();
File imgFile = new File(filePath);
if (imgFile.exists())
// use the file...
else
Toast.makeText(this, "Image file not found", Toast.LENGTH_LONG).show();
break;
}
}
public interface PermissionRequestCompletionHandler {
void onPermissionRequestResult(boolean permissionGranted);
}
private PermissionRequestCompletionHandler permissionRequestCompletionHandler;
public boolean filePermissionsRequired() {
if (Build.VERSION.SDK_INT >= 23)
return checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED;
else
return false;
}
public boolean askForFilePermissions(PermissionRequestCompletionHandler completionHandler) {
if (Build.VERSION.SDK_INT >= 23) {
permissionRequestCompletionHandler = completionHandler;
boolean hasPermission = this.checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED;
if (!hasPermission) {
this.requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE}, 1);
return true;
}
}
permissionRequestCompletionHandler = null;
return false;
}
The app has runtime permissions to access the Gallery. So what am I doing wrong? How to access the file on newer API versions?
}
try below code to open the camera and getting result:
File file = new File(Environment.getExternalStorageDirectory() + "/DCIM/", "image" + System.currentTimeMillis() + ".png");
Uri imageUri = Uri.fromFile(file);
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);
startActivityForResult(intent, PICK_FOTO_ACTION);
for getting result :
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == Activity.RESULT_OK) {
switch (requestCode) {
case PICK_FOTO_ACTION: {
Uri imageUri = imageUri;
File imgFile = new File(imageUri.getPath());
if (imgFile.exists())
// use the file...
else
Toast.makeText(this, "Image file not found", Toast.LENGTH_LONG).show();
break;
}
}
}
for getting actual path from uri :
public String getPath(Uri uri)
{
String[] projection = { MediaStore.Images.Media.DATA };
Cursor cursor = managedQuery(uri, projection, null, null, null);
if (cursor == null) return null;
int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
cursor.moveToFirst();
String s=cursor.getString(column_index);
cursor.close();
return s;
}
remove unwanted uri part :
public String RemoveUnwantedString(String pathUri){
//pathUri = "content://com.google.android.apps.photos.contentprovider/-1/2/content://media/external/video/media/5213/ORIGINAL/NONE/2106970034"
String[] d1 = pathUri.split("content://");
for (String item1:d1) {
if (item1.contains("media/")) {
String[] d2 = item1.split("/ORIGINAL/");
for (String item2:d2) {
if (item2.contains("media/")) {
pathUri = "content://" + item2;
break;
}
}
break;
}
}
//pathUri = "content://media/external/video/media/5213"
return pathUri;
}
For versions 21 and higher you can do this , you need to add a condition to check the SDK version for this. Exectute this code in the API 21+ condition block.
String wholeID = DocumentsContract.getDocumentId(imageUri );
String id = wholeID.split(":")[1];
String sel = MediaStore.Images.Media._ID + "=?";
cursor =
getContentResolver().query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
projection, sel, new String[]{ id }, null);
try
{
int column_index = cursor
.getColumnIndex(MediaStore.Images.Media.DATA);
cursor.moveToFirst();
path = cursor.getString(column_index).toString();
cursor.close();
}
catch(NullPointerException e) {
}
Call the Gallery with belo code
public static final int SELECT_IMAGE_FROM_GALLERY_CODE = 701;
public static void callGallery(Activity activity) {
Intent intent = new Intent();
intent.setType("image/*");
intent.setAction(Intent.ACTION_GET_CONTENT);
activity.startActivityForResult(Intent.createChooser(intent, "Complete action using"),
SELECT_IMAGE_FROM_GALLERY_CODE);
}
In OnActivityResult, read URI and read path from uri.
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == CommonUtils.SELECT_IMAGE_FROM_GALLERY_CODE) {
if (data != null) {
Uri selectedImageUri = data.getData();
// get path from Uri
String imagepath = getPath(this, selectedImageUri);
if (null != imagepath && (!imagepath.isEmpty())) {
// if the image path is not null and not empty, copy image to sdcard
try {
copyDirectoryOrFile(new File(imagepath), new File(myTargetImageFilePath));
} catch (IOException e) {
e.printStackTrace();
}
// load the image into imageView with the help og glide.
loadImageWithGlide(myImageViewContactImage,
myTargetImageFilePath, myDefaultImagePath, myErrorImagePath, false);
} else {
Toast.makeText(this, "Error: Photo selection failed.", Toast.LENGTH_LONG).show();
}
}
}
}
public void loadImageWithGlide(ImageView theImageViewToLoadImage,
String theLoadImagePath, int theDefaultImagePath, int theErrorImagePath,
boolean theIsSkipMemoryCache) {
if (theIsSkipMemoryCache) {
Glide.with(ProfileActivity.this) //passing context
.load(theLoadImagePath) //passing your url to load image.
.placeholder(theDefaultImagePath) //this would be your default image (like default profile or logo etc). it would be loaded at initial time and it will replace with your loaded image once glide successfully load image using url.
.error(theErrorImagePath)//in case of any glide exception or not able to download then this image will be appear . if you won't mention this error() then nothing to worry placeHolder image would be remain as it is.
.diskCacheStrategy(DiskCacheStrategy.ALL) //using to load into cache then second time it will load fast.
//.animate(R.anim.fade_in) // when image (url) will be loaded by glide then this face in animation help to replace url image in the place of placeHolder (default) image.
.centerCrop()
.into(theImageViewToLoadImage); //pass imageView reference to appear the image.
} else {
Glide.with(ProfileActivity.this)
.load(theLoadImagePath)
.diskCacheStrategy(DiskCacheStrategy.NONE)
.skipMemoryCache(true)
.centerCrop()
.into(theImageViewToLoadImage);
}
}
public static String getPath(Context theCtx, Uri uri) {
try {
Cursor cursor = (theCtx).getContentResolver().query(uri, null, null, null, null);
cursor.moveToFirst();
String document_id = cursor.getString(0);
document_id = document_id.substring(document_id.lastIndexOf(":") + 1);
cursor.close();
cursor = (theCtx).getContentResolver().query(
MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
null, MediaStore.Images.Media._ID + " = ? ", new String[]{document_id}, null);
cursor.moveToFirst();
String path = cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media.DATA));
cursor.close();
return path;
} catch (Exception e) {
return null;
}
}
public static void copyDirectoryOrFile(File sourceLocation, File targetLocation)
throws IOException {
if (sourceLocation.isDirectory()) {
if (!targetLocation.exists() && !targetLocation.mkdirs()) {
throw new IOException("Cannot create directory " + targetLocation.getAbsolutePath());
}
String[] children = sourceLocation.list();
for (int i = 0; i < children.length; i++) {
copyDirectoryOrFile(new File(sourceLocation, children[i]),
new File(targetLocation, children[i]));
}
} else {
File directory = targetLocation.getParentFile();
if (directory != null && !directory.exists() && !directory.mkdirs()) {
throw new IOException("Cannot create directory " + directory.getAbsolutePath());
}
InputStream in = new FileInputStream(sourceLocation);
OutputStream out = new FileOutputStream(targetLocation);
// Copy the bits from instream to outstream
byte[] buf = new byte[1024];
int len;
while ((len = in.read(buf)) > 0) {
out.write(buf, 0, len);
}
in.close();
if (out != null) {
try {
out.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}
To load image with glide, add following dependency in app gradle file
compile 'com.github.bumptech.glide:glide:3.7.0'
I using a renderer to pick a file from the system to and showing it in the application. I used
Intent intent = new Intent(Intent.ActionOpenDocument);
intent.SetType("file/*");
intent.AddCategory(Intent.CategoryOpenable);
String[] mimeTypes = { "text/csv", "text/comma-separated-values" ,"application/pdf","image/*"};
intent.SetType("*/*");
intent.PutExtra(Intent.ExtraMimeTypes, mimeTypes);
((FormsAppCompatActivity)Forms.Context).StartActivityForResult(intent, 7007);
And i got the data in OnActivityResult in MainActivity . Now that i have the Android.Net.Uri with me i want to find the absolute file path . here i used
public String getRealPathFromURI(Android.Net.Uri contentUri)
{
String res = null;
String[] proj = {Android.Provider.MediaStore.Images.Media.InterfaceConsts.Data};
ICursor cursor = ContentResolver.Query(contentUri, proj, null, null, null);
if (cursor.MoveToFirst())
{
int column_index = cursor.GetColumnIndexOrThrow(Android.Provider.MediaStore.Images.Media.InterfaceConsts.Data);
res = cursor.GetString(column_index);
}
cursor.Close();
return res;
}
I am testing in a Marshmallow device but i am getting null value as return every time. Any Guidance?
You can take a look to this plugin...
There is a IOUtil.cs class
public class IOUtil
{
public static string getPath (Context context, Android.Net.Uri uri)
{
bool isKitKat = Build.VERSION.SdkInt >= BuildVersionCodes.Kitkat;
// DocumentProvider
if (isKitKat && DocumentsContract.IsDocumentUri (context, uri)) {
// ExternalStorageProvider
if (isExternalStorageDocument (uri)) {
var docId = DocumentsContract.GetDocumentId (uri);
string [] split = docId.Split (':');
var type = split [0];
if ("primary".Equals (type, StringComparison.OrdinalIgnoreCase)) {
return Android.OS.Environment.ExternalStorageDirectory + "/" + split [1];
}
// TODO handle non-primary volumes
}
// DownloadsProvider
else if (isDownloadsDocument (uri)) {
string id = DocumentsContract.GetDocumentId (uri);
Android.Net.Uri contentUri = ContentUris.WithAppendedId (
Android.Net.Uri.Parse ("content://downloads/public_downloads"), long.Parse (id));
return getDataColumn (context, contentUri, null, null);
}
// MediaProvider
else if (isMediaDocument (uri)) {
var docId = DocumentsContract.GetDocumentId (uri);
string [] split = docId.Split (':');
var type = split [0];
Android.Net.Uri contentUri = null;
if ("image".Equals (type)) {
contentUri = MediaStore.Images.Media.ExternalContentUri;
} else if ("video".Equals (type)) {
contentUri = MediaStore.Video.Media.ExternalContentUri;
} else if ("audio".Equals (type)) {
contentUri = MediaStore.Audio.Media.ExternalContentUri;
}
var selection = "_id=?";
var selectionArgs = new string [] {
split[1]
};
return getDataColumn (context, contentUri, selection, selectionArgs);
}
}
// MediaStore (and general)
else if ("content".Equals (uri.Scheme, StringComparison.OrdinalIgnoreCase)) {
return getDataColumn (context, uri, null, null);
}
// File
else if ("file".Equals (uri.Scheme, StringComparison.OrdinalIgnoreCase)) {
return uri.Path;
}
return null;
}
public static string getDataColumn (Context context, Android.Net.Uri uri, string selection,
string [] selectionArgs)
{
ICursor cursor = null;
var column = "_data";
string [] projection = {
column
};
try {
cursor = context.ContentResolver.Query (uri, projection, selection, selectionArgs,
null);
if (cursor != null && cursor.MoveToFirst ()) {
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 bool isExternalStorageDocument (Android.Net.Uri uri)
{
return "com.android.externalstorage.documents".Equals (uri.Authority);
}
/**
* #param uri The Uri to check.
* #return Whether the Uri authority is DownloadsProvider.
*/
public static bool isDownloadsDocument (Android.Net.Uri uri)
{
return "com.android.providers.downloads.documents".Equals (uri.Authority);
}
/**
* #param uri The Uri to check.
* #return Whether the Uri authority is MediaProvider.
*/
public static bool isMediaDocument (Android.Net.Uri uri)
{
return "com.android.providers.media.documents".Equals (uri.Authority);
}
public static byte [] readFile (string file)
{
try {
return readFile (new File (file));
} catch (Exception ex) {
System.Diagnostics.Debug.Write (ex);
return new byte [0];
}
}
public static byte [] readFile (File file)
{
// Open file
var f = new RandomAccessFile (file, "r");
try {
// Get and check length
long longlength = f.Length ();
var length = (int)longlength;
if (length != longlength)
throw new IOException ("Filesize exceeds allowed size");
// Read file and return data
byte [] data = new byte [length];
f.ReadFully (data);
return data;
} catch (Exception ex) {
System.Diagnostics.Debug.Write (ex);
return new byte [0];
} finally {
f.Close ();
}
}
public static string GetMimeType (string url)
{
string type = null;
var extension = MimeTypeMap.GetFileExtensionFromUrl (url);
if (extension != null) {
type = MimeTypeMap.Singleton.GetMimeTypeFromExtension (extension);
}
return type;
}
}
it works in this way
protected override void OnActivityResult (int requestCode, [GeneratedEnum] Result resultCode, Intent data)
{
base.OnActivityResult (requestCode, resultCode, data);
if (resultCode == Result.Canceled) {
// Notify user file picking was cancelled.
OnFilePickCancelled ();
Finish ();
} else {
System.Diagnostics.Debug.Write (data.Data);
try {
var _uri = data.Data;
var filePath = IOUtil.getPath (context, _uri);
if (string.IsNullOrEmpty (filePath))
filePath = _uri.Path;
var file = IOUtil.readFile (filePath);
var fileName = GetFileName (context, _uri);
OnFilePicked (new FilePickerEventArgs (file, fileName, filePath));
} catch (Exception readEx) {
// Notify user file picking failed.
OnFilePickCancelled ();
System.Diagnostics.Debug.Write (readEx);
} finally {
Finish ();
}
}
}
Instead of using Android specific code in your Forms project, you can also use one of the FilePicker plugins that are available on NuGet. You can use this directly in your Forms project instead of jumping into an Android implementation.
The currently most actively maintained package is this one: https://github.com/jfversluis/FilePicker-Plugin-for-Xamarin-and-Windows (note: I'm one of the contributors to the project).
Picking files is as easy as calling var result = await PickFile() and checking the result object. See also the sample code mentioned in the README.md of the Github project.