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
}
}
Related
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");
}
I'm trying to upload a image to php, for that I need to send a File to the server. So I am trying to create a file from the data parameter.
But I got this error Cannot resolve constructor File
Here's my code:
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == RESULT_OK) {
// Get the url from data
Uri selectedImageUri = data.getData();
if (null != selectedImageUri) {
// File
File imageFilePath = new File(selectedImageUri);
The appropriate way is to getContentResolver().openInputStream(uri_of_your_file); and using a FileOutputStream to your desired path and then use that file.
As from Commonsware answer
You can use ContentResolver and openInputStream() to get an
InputStream on the content represented by the Uri. You can create a
FileOutputStream on some file that you control. And, you can use Java
I/O to copy from the InputStream to the OutputStream, making your own
copy of the content in a file that you control.
Sample code for doing that,
InputStream in = getContentResolver().openInputStream("your_uri_here");
OutputStream out = new FileOutputStream(new File("your_file_here"));
byte[] buf = new byte[1024];
int len;
while((len=in.read(buf))>0){
out.write(buf,0,len);
}
out.close();
in.close();
#GeekDroid's answer is correct, but I thought I would provide more info to help clarify.
I've also created a library that will return the file path from an Uri when selecting a File from MediaStore.
I've created a class that will copy/create a new file inside your application's directory. This is done on the background thread, as it should be done.
I have also created a callback interface to get the "status" and display a ProgressBar
Here is the interface(You can change the name and callbacks to whatever):
interface CallBackTask {
void onCopyPreExecute();
void onCopyProgressUpdate(int progress);
void onCopyPostExecute(String path, boolean wasSuccessful, String reason);
}
Here is the class to copy the file:
public class CopyFileAsyncTask extends AsyncTask<Uri, Integer, String> {
private Uri mUri;
private CallBackTask callback;
private WeakReference<Context> mContext;
private String pathPlusName;
private File folder;
private Cursor returnCursor;
private InputStream is = null;
private String errorReason = "";
DownloadAsyncTask(Uri uri, Context context, CallBackTask callback) {
this.mUri = uri;
mContext = new WeakReference<>(context);
this.callback = callback;
}
#Override
protected void onPreExecute() {
callback.onCopyPreExecute();
Context context = mContext.get();
if (context != null) {
folder = context.getExternalFilesDir("Temp");
returnCursor = context.getContentResolver().query(mUri, null, null, null, null);
try {
is = context.getContentResolver().openInputStream(mUri);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
}
#Override
protected void onProgressUpdate(Integer... values) {
super.onProgressUpdate(values);
int post = values[0];
callback.onCopyProgressUpdate(post);
}
#Override
protected String doInBackground(Uri... params) {
File file = null;
int size = -1;
try {
try {
if (returnCursor != null && returnCursor.moveToFirst()){
if (mUri.getScheme() != null)
if (mUri.getScheme().equals("content")) {
int sizeIndex = returnCursor.getColumnIndex(OpenableColumns.SIZE);
size = (int) returnCursor.getLong(sizeIndex);
}else if (mUri.getScheme().equals("file")) {
File ff = new File(mUri.getPath());
size = (int) ff.length();
}
}
}
finally {
if (returnCursor != null)
returnCursor.close();
}
pathPlusName = folder + "/" + getFileName(mUri, mContext.get());
file = new File(folder + "/" + getFileName(mUri, mContext.get()));
BufferedInputStream bis = new BufferedInputStream(is);
FileOutputStream fos = new FileOutputStream(file);
byte[] data = new byte[1024];
long total = 0;
int count;
while ((count = bis.read(data)) != -1) {
if (!isCancelled()) {
total += count;
if (size != -1) {
publishProgress((int) ((total * 100) / size));
}
fos.write(data, 0, count);
}
}
fos.flush();
fos.close();
} catch (IOException e) {
errorReason = e.getMessage();
}
return file.getAbsolutePath();
}
private String getFileName(Uri uri, Context context) {
String result = null;
if (uri.getScheme() != null) {
if (uri.getScheme().equals("content")) {
Cursor cursor = context.getContentResolver().query(uri, null, null, null, null);
if (cursor != null && cursor.moveToFirst()) {
result = cursor.getString(cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME));
}
if (cursor != null) {
cursor.close();
}
}
}
if (result == null) {
result = uri.getPath();
assert result != null;
int cut = result.lastIndexOf('/');
if (cut != -1) {
result = result.substring(cut + 1);
}
}
return result;
}
protected void onPostExecute(String result) {
if(result == null){
callback.onCopyPostExecute(pathPlusName, false, errorReason);
}else {
callback.onCopyPostExecute(pathPlusName, true, "");
}
}
}
In your Activity you should do the following:
import android.annotation.SuppressLint;
import android.app.AlertDialog;
import android.net.Uri;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.ContextThemeWrapper;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.Button;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;
public class ExampleActivity extends AppCompatActivity implements CallBackTask{
Button someBtn;
Uri someUri = .... //This is just an example, you should provide your own Uri
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_example);
someBtn = findViewById(R.id.someBtn);
someBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
CopyFileAsyncTask asyntask = new CopyFileAsyncTask(someUri, ExampleActivity.this, ExampleActivity.this);
asyntask.execute();
}
});
}
ProgressBar mProgressBar;
TextView percentText;
private AlertDialog mdialog;
#Override
public void onCopyPreExecute() {
final AlertDialog.Builder mPro = new AlertDialog.Builder(new ContextThemeWrapper(this, R.style.myDialog));
#SuppressLint("InflateParams") final View mPView = LayoutInflater.from(this).inflate(R.layout.dailog_layout, null);
percentText = mPView.findViewById(R.id.percentText);
mProgressBar = mPView.findViewById(R.id.mProgressBar);
mProgressBar.setMax(100);
mPro.setView(mPView);
mdialog = mPro.create();
mdialog.show();
}
#Override
public void onCopyProgressUpdate(int progress) {
String progressPlusPercent = progress + "%";
percentText.setText(progressPlusPercent);
mProgressBar.setProgress(progress);
}
#Override
public void onCopyPostExecute(String path, boolean wasSuccessful, String reason) {
if (mdialog != null && mdialog.isShowing()) {
mdialog.cancel();
}
if (wasSuccessful){
Toast.makeText(this, "File was created at - "+path, Toast.LENGTH_SHORT).show();
}else{
Toast.makeText(this, "Error - "+reason, Toast.LENGTH_SHORT).show();
}
}
}
You can cancel the copying of the file at any time, by calling:
if (asyntask!=null){
asyntask.cancel(true);
}
If you want to implement it exactly as I did and display a ProgressBar while the file is being copied, then here is the layout and style of my dialog:
R.style.myDialog:
<resources>
<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<!-- Customize your theme here. -->
<item name="colorPrimary">#color/colorPrimary</item>
<item name="colorPrimaryDark">#color/colorPrimaryDark</item>
<item name="colorAccent">#color/colorAccent</item>
</style>
<style name="myDialog" parent="Theme.AppCompat.Dialog.Alert">
<item name="android:windowNoTitle">true</item>
<item name="android:background">#fff</item>
<item name="android:windowBackground">#null</item>
<item name="android:windowFrame">#null</item>
<item name="android:windowIsFloating">true</item>
<item name="android:backgroundDimEnabled">true</item>
</style>
</resources>
R.layout.dailog_layout:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<RelativeLayout
android:id="#+id/loadContent"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:padding="20dp">
<RelativeLayout
android:id="#+id/dotRel"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="#+id/percentText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_marginBottom="15dp"
android:text="0 %"
android:textColor="#android:color/black"
android:textSize="25sp" />
<ProgressBar
android:id="#+id/mProgressBar"
style="#android:style/Widget.ProgressBar.Horizontal"
android:layout_width="match_parent"
android:layout_height="5dp"
android:layout_below="#+id/percentText"
android:progressDrawable="#drawable/progressbar" />
</RelativeLayout>
</RelativeLayout>
</RelativeLayout>
Here is the dialog while the file is being copied:
Conclusion:
With the above, your file will be copied to /storage/emulated/0/Android/data/yourPackageName/files/Temp/YourFile.jpg. While the files are being copied a progress dialog will be displayed indicating the progress as a percentage (this is useful for when copying large files). If there was an error while copying the file, the reason will be provided in onCopyPostExecute
This will work with file and content Uri's.
You can try this;
try {
Uri uri = data.getData();
String selectedFilePath = FilePath.getPath(getActivity(), uri);
final File file = new File(selectedFilePath);
new UploadFileToServer().execute(file);
}
catch (Exception e)
{
e.printStackTrace();
}
and define FilePath class like this;
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;
public class FilePath {
/**
* Method for return file path of Gallery image/ Document / Video / Audio
*
* #param context
* #param uri
* #return path of the selected image file from gallery
*/
public static String getPath(final Context context, final Uri uri) {
// check here to KITKAT or new version
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];
}
}
// 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 the remote address
if (isGooglePhotosUri(uri))
return uri.getLastPathSegment();
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.
*/
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 index = cursor.getColumnIndexOrThrow(column);
return cursor.getString(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());
}
/**
* #param uri
* The Uri to check.
* #return Whether the Uri authority is Google Photos.
*/
public static boolean isGooglePhotosUri(Uri uri) {
return "com.google.android.apps.photos.content".equals(uri
.getAuthority());
}
}
One line solution for your problem
File imageFile = new File(selectedImageUri.getPath());
You missed
.getPath()
How to create file using android Uri
It may seem difficult to create a java.io.File from an android.net.Uri, since there is no direct way to convert an android.net.Uri into java.net.URI. But if you have the ApplicationContext you can do it very easily.
Here's how to do it from inside a fragment class.
fun createFile(uri: Uri) {
try {
requireContext().applicationContext.contentResolver.openFileDescriptor(uri, "w")?.use { fd ->
FileOutputStream(fd).use { fos ->
// do your job on the FileOutputStream
// also use background thread
fos.close()
}
}
} catch (e: Exception) {
}
}
Note: File operations throws multiple exceptions, so handle them carefully. And also do file operations in worker threads.
you can use this funtion for get file from uri in new android and older:
fun getFileFromUri(context: Context, uri: Uri?): File? {
uri ?: return null
uri.path ?: return null
var newUriString = uri.toString()
newUriString = newUriString.replace(
"content://com.android.providers.downloads.documents/",
"content://com.android.providers.media.documents/"
)
newUriString = newUriString.replace(
"/msf%3A", "/image%3A"
)
val newUri = Uri.parse(newUriString)
var realPath = String()
val databaseUri: Uri
val selection: String?
val selectionArgs: Array<String>?
if (newUri.path?.contains("/document/image:") == true) {
databaseUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI
selection = "_id=?"
selectionArgs = arrayOf(DocumentsContract.getDocumentId(newUri).split(":")[1])
} else {
databaseUri = newUri
selection = null
selectionArgs = null
}
try {
val column = "_data"
val projection = arrayOf(column)
val cursor = context.contentResolver.query(
databaseUri,
projection,
selection,
selectionArgs,
null
)
cursor?.let {
if (it.moveToFirst()) {
val columnIndex = cursor.getColumnIndexOrThrow(column)
realPath = cursor.getString(columnIndex)
}
cursor.close()
}
} catch (e: Exception) {
Log.i("GetFileUri Exception:", e.message ?: "")
}
val path = realPath.ifEmpty {
when {
newUri.path?.contains("/document/raw:") == true -> newUri.path?.replace(
"/document/raw:",
""
)
newUri.path?.contains("/document/primary:") == true -> newUri.path?.replace(
"/document/primary:",
"/storage/emulated/0/"
)
else -> return null
}
}
return if (path.isNullOrEmpty()) null else File(path)
}
I am trying to access a file using Storage Access Framework which I have stored in locally and send it to server. but when ever I try to get file using URI I get NullPointerException. However I get the URI of file. but catches exception when converting to file by getting path.
Minimum API is 17
uriString =
content://com.android.providers.downloads.documents/document/349
warantyButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Intent intent = new Intent(Intent. ACTION_OPEN_DOCUMENT );
intent.addCategory(Intent.CATEGORY_OPENABLE);
intent.setType("*/*");
Intent i = Intent.createChooser(intent, "File");
getActivity().startActivityForResult(i, FILE_REQ_CODE);
//Toast.makeText(getContext(),"Files",Toast.LENGTH_SHORT).show();
}
});
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == FILE_REQ_CODE) {
if (resultCode == RESULT_OK) {
String path="";
Uri uri = data.getData();
if (uri != null) {
try {
file = new File(getPath(getContext(),uri));
if(file!=null){
ext = getMimeType(uri);
sendFileToServer(file,ext);
}
} catch (Exception e) {
Toast.makeText(getContext(),getString(R.string.general_error_retry),Toast.LENGTH_SHORT).show();
e.printStackTrace();
}
}
}
}
}
public static String getPath(Context context, Uri uri) throws URISyntaxException {
if ("content".equalsIgnoreCase(uri.getScheme())) {
String[] projection = { "_data" };
Cursor cursor = null;
try {
cursor = context.getContentResolver().query(uri, projection, null, null, null);
int column_index = cursor.getColumnIndexOrThrow("_data");
if (cursor.moveToFirst()) {
return cursor.getString(column_index);
}
} catch (Exception e) {
// Eat it
}
}
else if ("file".equalsIgnoreCase(uri.getScheme())) {
return uri.getPath();
}
return null;
}
I am trying to access a file using Storage Access Framework which I have stored in locally and send it to server.
Your users are welcome to choose anything they want, which does not include files that you can access directly (e.g., in Google Drive, on removable storage).
but catches exception when converting to file by getting path
You cannot "convert to file by getting path". The path portion of a content Uri is a meaningless set of characters that identifies the particular piece of content. Next, you will think that all computers have a file on their local filesystem at the path /questions/43818723/unable-to-access-file-from-uri, just because https://stackoverflow.com/questions/43818723/unable-to-access-file-from-uri happens to be a valid Uri.
So, get rid of getPath().
Use ContentResolver and openInputStream() to get an InputStream on the content. Either use that stream directly or use it in conjunction with a FileOutputStream on your own file, to make a local copy of the content that you can use as a file.
#CommonsWare answer is correct
here is code snippet
To read file content from Uri :
// Use ContentResolver to access file from Uri
InputStream inputStream = null;
try {
inputStream = mainActivity.getContentResolver().openInputStream(uri);
assert inputStream != null;
// read file content
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
String mLine;
StringBuilder stringBuilder = new StringBuilder();
while ((mLine = bufferedReader.readLine()) != null) {
stringBuilder.append(mLine);
}
Log.d(TAG, "reading file :" + stringBuilder);
To save file from Uri to local copy inside your app dir :
String dirPath = "/data/user/0/-your package name -/newLocalFile.name"
try (InputStream ins = mainActivity.getContentResolver().openInputStream(uri)) {
File dest = new File(dirPath);
try (OutputStream os = new FileOutputStream(dest)) {
byte[] buffer = new byte[4096];
int length;
while ((length = ins.read(buffer)) > 0) {
os.write(buffer, 0, length);
}
os.flush();
} catch (Exception e) {
e.printStackTrace();
}
} catch (Exception e) {
e.printStackTrace();
}
Try Below Code For Getting Path:
public String getPath(Uri uri) throws URISyntaxException {
final boolean needToCheckUri = Build.VERSION.SDK_INT >= 19;
String selection = null;
String[] selectionArgs = null;
// Uri is different in versions after KITKAT (Android 4.4), we need to
// deal with different Uris.
if (needToCheckUri && DocumentsContract.isDocumentUri(mainActivity, uri)) {
if (isExternalStorageDocument(uri)) {
final String docId = DocumentsContract.getDocumentId(uri);
final String[] split = docId.split(":");
return Environment.getExternalStorageDirectory() + "/" + split[1];
} else if (isDownloadsDocument(uri)) {
final String id = DocumentsContract.getDocumentId(uri);
uri = ContentUris.withAppendedId(
Uri.parse("content://downloads/public_downloads"), Long.valueOf(id));
} else if (isMediaDocument(uri)) {
final String docId = DocumentsContract.getDocumentId(uri);
final String[] split = docId.split(":");
final String type = split[0];
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;
}
selection = "_id=?";
selectionArgs = new String[] {
split[1]
};
}
}
if ("content".equalsIgnoreCase(uri.getScheme())) {
String[] projection = {
MediaStore.Images.Media.DATA
};
Cursor cursor = null;
try {
cursor = mainActivity.getContentResolver()
.query(uri, projection, selection, selectionArgs, null);
int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
if (cursor.moveToFirst()) {
return cursor.getString(column_index);
}
} catch (Exception e) {
}
} else if ("file".equalsIgnoreCase(uri.getScheme())) {
return uri.getPath();
}
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());
}`
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.
I am trying to get an image from the gallery app from one of the folders from the Google+ synced photos. After selecting the image, the Uri is being passed back correctly. But when I try to get the actual path of that image on the storage device, so that I can use it, it crashes. The problem seems to be specifically with the picasa content provider.
Tested on Nexus S and Nexus 7, and other devices as well.
E/AndroidRuntime(14572): java.lang.RuntimeException: Failure delivering result ResultInfo{who=null, request=1, result=-1, data=Intent { dat=content://com.google.android.gallery3d.provider/picasa/item/5427003652908228690 }}
Here, the dat field seems to be correctly passing the Uri, but when I try to fetch the image's location, it crashes with the following error.
W/GalleryProvider(14381): unsupported column: _data
Seems that the content provider for Picasa albums doesn't have a _data field.
The code for getting the location is:
// imageUri is the Uri from above.
String[] proj = { MediaStore.Images.Media.DATA };
Cursor cursor = context.getContentResolver().query(imageUri, proj,null, null, null);
int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
cursor.moveToFirst();
String filePath = cursor.getString(column_index);
cursor.close();
The only columns that seem to be supported for this image are:
[user_account, picasa_id, _display_name, _size, mime_type, datetaken, latitude, longitude, orientation]
How do we get the actual location of this image. And if we are not supposed to work with this image, these images shouldn't be shown to the user in the first place.
The Intent to launch the gallery app is:
Intent intent = new Intent();
intent.setType("image/*");
intent.setAction(Intent.ACTION_GET_CONTENT);
I wasted now lots of hours and now i found a solution which works in all cases without any magic downloading in special threads or something. The following method returns a stream from the content which the user selected and this works with everything in the wild.
FileInputStream getSourceStream(Uri u) throws FileNotFoundException {
FileInputStream out = null;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
ParcelFileDescriptor parcelFileDescriptor =
mContext.getContentResolver().openFileDescriptor(u, "r");
FileDescriptor fileDescriptor = parcelFileDescriptor.getFileDescriptor();
out = new FileInputStream(fileDescriptor);
} else {
out = (FileInputStream) mContext.getContentResolver().openInputStream(u);
}
return out;
}
After a lot of research, I felt that there were too many workarounds to do something which seems to be quite simple. So, I went ahead a wrote a small library that handles all the complex if elses and happens to work for all possible scenarios that I can think of. Do give it a try and see if this helps.
http://techdroid.kbeanie.com/2013/03/easy-image-chooser-library-for-android.html
This is an initial implementation. Although it handles almost every situation, there could be a few bugs. If you use this library, please let me know your feedback and if at all it could be improved any further.
I faced the same problem about year ago.. I show you my solution (code is quite messy, please refactor it).
So, you have the image URI which was returned from gallery:
ImageInfo getImage(URI imageUri) {
ImageInfo result = null;
final String[] cursorColumns = {MediaStore.Images.Media.DATA, MediaStore.Images.Media.ORIENTATION};
// some devices (OS versions return an URI of com.android instead of com.google.android
if (imageUri.toString().startsWith("content://com.android.gallery3d.provider")) {
// use the com.google provider, not the com.android provider.
imageUri = Uri.parse(imageUri.toString().replace("com.android.gallery3d","com.google.android.gallery3d"));
}
Cursor cursor = App.getContext().getContentResolver().query(imageUri, cursorColumns, null, null, null);
if (cursor != null) {
int dataColumnIndex = cursor.getColumnIndex(MediaStore.Images.ImageColumns.DATA);
int orientationColumnIndex = cursor.getColumnIndex(MediaStore.Images.ImageColumns.ORIENTATION);
cursor.moveToFirst();
// if it is a picasa image on newer devices with OS 3.0 and up
if (imageUri.toString().startsWith("content://com.google.android.gallery3d")) {
result = new ImageInfo(downloadImage(imageUri), "0");
} else { // it is a regular local image file
result = new ImageInfo(cursor.getString(dataColumnIndex), cursor.getString(orientationColumnIndex));
}
cursor.close();
} else {
result = new ImageInfo(downloadImage(imageUri), "0");
}
return result;
}
And now we need function to download image:
private String downloadImage(URI imageUri) {
File cacheDir;
// if the device has an SD card
if (android.os.Environment.getExternalStorageState().equals(android.os.Environment.MEDIA_MOUNTED)) {
cacheDir = new File(android.os.Environment.getExternalStorageDirectory(),".OCFL311");
} else {
// it does not have an SD card
cacheDir = App.getContext().getCacheDir();
}
if(!cacheDir.exists()) cacheDir.mkdirs();
File f = new File(cacheDir, PUT_HERE_FILE_NAME_TO_STORE_IMAGE);
try {
InputStream is = null;
if (imageUri.toString().startsWith("content://com.google.android.gallery3d")) {
is = App.getContext().getContentResolver().openInputStream(imageUri);
} else {
is = new URL(imageUri.toString()).openStream();
}
OutputStream os = new FileOutputStream(f);
Utils.InputToOutputStream(is, os);
return f.getAbsolutePath();
} catch (Exception ex) {
Log.d(this.getClass().getName(), "Exception: " + ex.getMessage());
// something went wrong
ex.printStackTrace();
return null;
}
}
ImageInfo is my class to store path to image and its orientation.
public static class ImageInfo {
public final String filePath;
public final String imageOrientation;
public ImageInfo(String filePath, String imageOrientation) {
this.filePath = filePath;
if (imageOrientation == null) imageOrientation = "0";
this.imageOrientation = imageOrientation;
}
}
Based on #drindt answer, below codes give downloaded temporary File path from Google Photo cloud-synced-but-not-in-device file.
#SuppressLint("NewApi")
public static String getFilePath(final Context context, final Uri uri) {
// Google photo uri example
// content://com.google.android.apps.photos.contentprovider/0/1/mediakey%3A%2FAF1QipMObgoK_wDY66gu0QkMAi/ORIGINAL/NONE/114919
if ("content".equalsIgnoreCase(uri.getScheme())) {
String result = getDataColumn(context, uri, null, null); //
if (TextUtils.isEmpty(result))
if (uri.getAuthority().contains("com.google.android")) {
try {
File localFile = createImageFile(context, null);
FileInputStream remoteFile = getSourceStream(context, uri);
if(copyToFile(remoteFile, localFile))
result = localFile.getAbsolutePath();
remoteFile.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return result;
}
// 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.
*/
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;
}
/**
* Copy data from a source stream to destFile.
* Return true if succeed, return false if failed.
*/
private static boolean copyToFile(InputStream inputStream, File destFile) {
if (inputStream == null || destFile == null) return false;
try {
OutputStream out = new FileOutputStream(destFile);
try {
byte[] buffer = new byte[4096];
int bytesRead;
while ((bytesRead = inputStream.read(buffer)) >= 0) {
out.write(buffer, 0, bytesRead);
}
} finally {
out.close();
}
return true;
} catch (IOException e) {
return false;
}
}
public static String getTimestamp() {
try {
return new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.ROOT).format(new Date());
} catch (RuntimeException e) {
return new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.getDefault()).format(new Date());
}
}
public static File createImageFile(Context context, String imageFileName) throws IOException {
if (TextUtils.isEmpty(imageFileName))
imageFileName = getTimestamp(); // make random filename if you want.
final File root;
imageFileName = imageFileName;
root = context.getExternalCacheDir();
if (root != null && !root.exists())
root.mkdirs();
return new File(root, imageFileName);
}
public static FileInputStream getSourceStream(Context context, Uri u) throws FileNotFoundException {
FileInputStream out = null;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
ParcelFileDescriptor parcelFileDescriptor =
context.getContentResolver().openFileDescriptor(u, "r");
FileDescriptor fileDescriptor = null;
if (parcelFileDescriptor != null) {
fileDescriptor = parcelFileDescriptor.getFileDescriptor();
out = new FileInputStream(fileDescriptor);
}
} else {
out = (FileInputStream) context.getContentResolver().openInputStream(u);
}
return out;
}
Below trick worked for me, what i am doing here is if there is any authority url in URI, then i am creating a temporary image using below code & returning the Content URI of the same.
I have answered similar question here as well..
public static String getImageUrlWithAuthority(Context context, Uri uri) {
InputStream is = null;
if (uri.getAuthority() != null) {
try {
is = context.getContentResolver().openInputStream(uri);
Bitmap bmp = BitmapFactory.decodeStream(is);
return writeToTempImageAndGetPathUri(context, bmp).toString();
} catch (FileNotFoundException e) {
e.printStackTrace();
}finally {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return null;
}
public static Uri writeToTempImageAndGetPathUri(Context inContext, Bitmap inImage) {
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
inImage.compress(Bitmap.CompressFormat.JPEG, 100, bytes);
String path = MediaStore.Images.Media.insertImage(inContext.getContentResolver(), inImage, "Title", null);
return Uri.parse(path);
}
I used this approach, works fine for me,
hope this will helps you ....
ACTIVITYRESULT_CHOOSEPICTURE is the int you use when calling startActivity(intent, requestCode);
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if(requestCode == ACTIVITYRESULT_CHOOSEPICTURE) {
BitmapFactory.Options options = new BitmapFactory.Options();
final InputStream ist = ontext.getContentResolver().openInputStream(intent.getData());
final Bitmap bitmap = BitmapFactory.decodeStream(ist, null, options);
ist.close();
}
}
if above code doesn't work than just refer this link... it will surly shows the way
http://dimitar.me/how-to-get-picasa-images-using-the-image-picker-on-android-devices-running-any-os-version/
Finally ended with a classic solution...By using Document.util, which covers all authority :-1-Inside your onActivityResult():-
case GALLERY_CAPTURE_IMAGE_REQUEST_CODE:
String filePath = DocumentUtils.getPath(MainContainerActivity.this,data.getData();
break;
2- Create class DocumentUtils:-
public class DocumentUtils {
#TargetApi(Build.VERSION_CODES.KITKAT)
public static String getPath(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 the remote address
String url;
if (isGooglePhotosUri(uri)) {
url = getDataColumnWithAuthority(context, uri, null, null);
return getDataColumn(context, Uri.parse(url), null, null);
}
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.
*/
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;
}
/**
* Function for fixing synced folder image picking bug
*
* **/
public static String getDataColumnWithAuthority(Context context, Uri uri, String selection, String[] selectionArgs) {
Bitmap bitmap = null;
InputStream is = null;
if (uri.getAuthority()!=null){
try {
is = context.getContentResolver().openInputStream(uri);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
Bitmap bmp = BitmapFactory.decodeStream(is);
return ImageLoader.getImageUri(context,bmp).toString();
}
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());
}
/**
* #param uri The Uri to check.
* #return Whether the Uri authority is Google Photos.
*/
public static boolean isGooglePhotosUri(Uri uri) {
if(uri.getAuthority()!=null)
return true;
return false;
}
}
3- Also you will need following function in ImageLoader.java:-
public static Uri getImageUri(Context inContext, Bitmap inImage) {
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
inImage.compress(Bitmap.CompressFormat.JPEG, 100, bytes);
String path = MediaStore.Images.Media.insertImage(inContext.getContentResolver(), inImage, "Title", null);
return Uri.parse(path);
}