File picker in xamarin forms application - android

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.

Related

Android variable at "onActivityResult" sometime null value on KITKAT

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
}
}

Android: Get file name and extension of any file

The issue I have, is that i can't extract the file exetension from files choosen on a smartphone with Android 9. The problem doesn't appear on devices with Android 8 or less.
When the user has choosen any kind of file the onActivityResult gets called. In this method I call getPath from FileUtils class, so I can extract the file extension.
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
Uri uri = new Uri.Builder().build();
if (resultCode == RESULT_OK) {
switch (requestCode) {
case PICKFILE_REQUEST_CODE: {
String path = new File(data.getData().getPath()).getAbsolutePath();
if (path != null) {
uri = data.getData();
path = FileUtils.getPath(getApplicationContext().getContentResolver(), uri);
name = path.substring(path.lastIndexOf("."));
extension = path.substring(path.lastIndexOf(".") + 1);
}
break;
}
}
}
getPath() from FileUtils class (from this repo) evaluates the file via URI which kind of file it is, but responsible for that case is following part:
public static String getPath(final ContentResolver cr, final Uri uri) {
if (isDownloadsDocument(uri)) {
final String id = DocumentsContract.getDocumentId(uri);
final List<Uri> uris = new ArrayList<>();
uris.add(ContentUris.withAppendedId(
Uri.parse("content://downloads/public_downloads"), Long.valueOf(id)));
uris.add(ContentUris.withAppendedId(
Uri.parse("content://downloads/my_downloads"), Long.valueOf(id)));
uris.add(ContentUris.withAppendedId(
Uri.parse("content://downloads/all_downloads"), Long.valueOf(id)));
String res;
for (int i = 0; i < uris.size(); i++) {
res = getDataColumn(cr, uris.get(i), null, null);
if (res != null) return res;
}
}
}
getDataColumn() queries the column of the file in which the physical path of the file is saved:
public static String getDataColumn(ContentResolver cr,
Uri uri, String selection,
String[] selectionArgs) {
Cursor cursor = null;
final String[] projection = {"_data"};
String col = "";
try {
cursor = cr.query(uri, projection, selection, selectionArgs,null);
if (cursor != null && cursor.moveToFirst()) {
final int column_index = cursor.getColumnIndexOrThrow("_data");
col = cursor.getString(column_index);
}
}finally{ if (cursor != null) cursor.close();}
return col;
}
When I'm testing the it the path I get looks for example like: E/AddItemActivity: result, path: /storage/emulated/0/Download/SampleVideo_176x144_1mb.3gp.
But with Android 9 the path is always empty.
For the solution I am using the MediaStore to extract the name and extension of a choosen file. So I replace code in onActivityResult with following code:
String path = new File(data.getData().getPath()).getAbsolutePath();
if(path != null){
uri = data.getData();
String filename;
Cursor cursor = getContentResolver().query(uri,null,null,null,null);
if(cursor == null) filename=uri.getPath();
else{
cursor.moveToFirst();
int idx = cursor.getColumnIndex(MediaStore.Files.FileColumns.DISPLAY_NAME);
filename = cursor.getString(idx);
cursor.close();
}
String name = filename.substring(0,filename.lastIndexOf("."));
String extension = filename.substring(filename.lastIndexOf(".")+1);
}
So with MediaStore.File.FileColumns.DISPLAY_NAME it's possible to get the file name and extension from any file choosen with a file chooser.
fun Uri.getFileNameWithExtension(context: Context): String? {
val name = this.path?.let { path -> File(path).name }.orEmpty()
val extension = MimeTypeMap.getSingleton()
.getExtensionFromMimeType(getMimeType(context)).orEmpty()
return if (name.isNotEmpty() && extension.isNotEmpty()) "$name.$extension" else null
}
fun Uri.getMimeType(context: Context): String? {
return when (scheme) {
ContentResolver.SCHEME_CONTENT -> context.contentResolver.getType(this)
ContentResolver.SCHEME_FILE -> MimeTypeMap.getSingleton().getMimeTypeFromExtension(
MimeTypeMap.getFileExtensionFromUrl(toString()).toLowerCase(Locale.US)
)
else -> null
}
}

Unable to access file from uri

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());
}`

Get file path from URI

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 "";
}

Getting an image from Gallery on from the Picasa//Google + synced folders doesn't work

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);
}

Categories

Resources