private void openCamera(int imageArray){
Intent cameraIntent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
fileUri = Uri.fromFile(new File(Environment.getExternalStorageDirectory()+"/SurveyDA/assets/images","absen_" +
System.currentTimeMillis() + ".jpg"));
Log.d("ddddd : ", String.valueOf(fileUri));
cameraIntent.putExtra(android.provider.MediaStore.EXTRA_OUTPUT, fileUri);
startActivityForResult(cameraIntent, imageArray);
}
when I want open camera, I set the fileuri, and Log success return uri
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == RESULT_OK) {
try {
//getting bitmap object from uri
Log.d("ddddd : ", String.valueOf(fileUri));
bitmapImage[requestCode] = MediaStore.Images.Media.getBitmap(this.getContentResolver(), fileUri);
// Initialize a new ByteArrayStream
ByteArrayOutputStream stream = new ByteArrayOutputStream();
// Compress the bitmap with JPEG format and quality 50%
bitmapImage[requestCode].compress(Bitmap.CompressFormat.JPEG,60,stream);
byte[] byteArray = stream.toByteArray();
Bitmap bitmap = BitmapFactory.decodeByteArray(byteArray,0,byteArray.length);
bitmapImage[requestCode] = Bitmap.createScaledBitmap(bitmap, bitmap.getWidth(), bitmap.getHeight(), false);
//displaying selected image to imageview
imageViews[requestCode].setImageBitmap(bitmapImage[requestCode]);
//calling the method uploadBitmap to upload image
} catch (IOException e) {
e.printStackTrace();
}
}else if(resultCode == Activity.RESULT_CANCELED) {
// User Cancelled the actiongetUriForFile
}
}
but in onActivityResult variable fileuri sometimes get null, and sometimes success return uri. And when I try in other phone Android 8.0.0, there no error.
how to fix that?
java.lang.RuntimeException: Unable to resume activity {com.example.surveyonlineda/com.example.surveyonlineda.Activity.AbsenActivity}: java.lang.RuntimeException: Failure delivering result ResultInfo{who=null, request=100, result=-1, data=null} to activity {com.example.surveyonlineda/com.example.surveyonlineda.Activity.AbsenActivity}: java.lang.NullPointerException
Refer this Document for your issue you will get best solution
as I see, the fileUri is not returned by onActivityResult. You create it before start your cameraIntent. So in case your activity has been destroyed, the fileUri will null. To prevent it, I think you should use onSaveInstanceState to save the fileUri.
Here is an example to save the string fileUri
#Override protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Check whether we're recreating a previously destroyed instance
if (savedInstanceState != null) {
// Restore value of fileUri from saved state
fileUri = savedInstanceState.getString(FILE_URI);
} else {
// Probably initialize values for a new instance
}
}
#Override protected void onSaveInstanceState(Bundle savedInstanceState) {
savedInstanceState.putString(FILE_URI, fileUri);
// Always call the superclass so it can save the view hierarchy state
super.onSaveInstanceState(savedInstanceState);
}
You can try it. it worked for me
Step 1. Create class GetPathFromUri.class
import android.annotation.SuppressLint;
import android.content.ContentUris;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
import android.os.Build;
import android.os.Environment;
import android.provider.DocumentsContract;
import android.provider.MediaStore;
import android.provider.OpenableColumns;
import android.util.Log;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import java.io.*;
public class GetPathFromUri {
#SuppressLint("NewApi")
public static String getPath(final Context context, final Uri uri) {
#SuppressLint("ObsoleteSdkInt") final boolean isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;
// DocumentProvider
if (isKitKat && DocumentsContract.isDocumentUri(context, uri)) {
// ExternalStorageProvider
if (isExternalStorageDocument(uri)) {
final String docId = DocumentsContract.getDocumentId(uri);
final String[] split = docId.split(":");
final String type = split[0];
if ("primary".equalsIgnoreCase(type)) {
return Environment.getExternalStorageDirectory() + "/" + split[1];
}
if ("raw".equalsIgnoreCase(type)) {
return Environment.getExternalStorageDirectory() + "/" + split[1];
}
// TODO handle non-primary volumes
if ("5D68-9217".equalsIgnoreCase(type)) {
return Environment.getExternalStorageDirectory() + "/" + split[1];
}
}
// DownloadsProvider
else if (isDownloadsDocument(uri)) {
final String id = DocumentsContract.getDocumentId(uri);
if (id != null && id.startsWith("raw:")) {
return id.substring(4);
}
String[] contentUriPrefixesToTry = new String[]{
"content://downloads/public_downloads",
"content://downloads/my_downloads"
};
for (String contentUriPrefix : contentUriPrefixesToTry) {
Uri contentUri = ContentUris.withAppendedId(Uri.parse(contentUriPrefix), Long.valueOf(id));
try {
String path = getDataColumn(context, contentUri, null, null);
if (path != null) {
return path;
}
} catch (Exception e) {}
}
// path could not be retrieved using ContentResolver, therefore copy file to accessible cache using streams
String fileName = getFileName(context, uri);
File cacheDir = getDocumentCacheDir(context);
File file = generateFileName(fileName, cacheDir);
String destinationPath = null;
if (file != null) {
destinationPath = file.getAbsolutePath();
saveFileFromUri(context, uri, destinationPath);
}
return destinationPath;
}
// MediaProvider
else if (isMediaDocument(uri)) {
final String docId = DocumentsContract.getDocumentId(uri);
final String[] split = docId.split(":");
final String type = split[0];
Uri contentUri = null;
if ("image".equals(type)) {
contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
} else if ("video".equals(type)) {
contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
} else if ("audio".equals(type)) {
contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
}
final String selection = "_id=?";
final String[] selectionArgs = new String[]{split[1]};
return getDataColumn(context, contentUri, selection, selectionArgs);
}
}
// MediaStore (and general)
else if ("content".equalsIgnoreCase(uri.getScheme())) {
return getDataColumn(context, uri, null, null);
}
// File
else if ("file".equalsIgnoreCase(uri.getScheme())) {
return uri.getPath();
}
return null;
}
/**
* Get the value of the data column for this Uri. This is useful for
* MediaStore Uris, and other file-based ContentProviders.
*
* #param context The context.
* #param uri The Uri to query.
* #param selection (Optional) Filter used in the query.
* #param selectionArgs (Optional) Selection arguments used in the query.
* #return The value of the _data column, which is typically a file path.
*/
private static String getDataColumn(Context context, Uri uri, String selection,
String[] selectionArgs) {
final String column = "_data";
final String[] projection = {column};
try (Cursor cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs,
null)) {
if (cursor != null && cursor.moveToFirst()) {
final int column_index = cursor.getColumnIndexOrThrow(column);
return cursor.getString(column_index);
}
}
return null;
}
/**
* #param uri The Uri to check.
* #return Whether the Uri authority is ExternalStorageProvider.
*/
private static boolean isExternalStorageDocument(Uri uri) {
return "com.android.externalstorage.documents".equals(uri.getAuthority());
}
/**
* #param uri The Uri to check.
* #return Whether the Uri authority is DownloadsProvider.
*/
private static boolean isDownloadsDocument(Uri uri) {
return "com.android.providers.downloads.documents".equals(uri.getAuthority());
}
/**
* #param uri The Uri to check.
* #return Whether the Uri authority is MediaProvider.
*/
private static boolean isMediaDocument(Uri uri) {
return "com.android.providers.media.documents".equals(uri.getAuthority());
}
public static String getFileName(#NonNull Context context, Uri uri) {
String mimeType = context.getContentResolver().getType(uri);
String filename = null;
if (mimeType == null && context != null) {
String path = getPath(context, uri);
if (path == null) {
filename = getName(uri.toString());
} else {
File file = new File(path);
filename = file.getName();
}
} else {
Cursor returnCursor = context.getContentResolver().query(uri, null,
null, null, null);
if (returnCursor != null) {
int nameIndex = returnCursor.getColumnIndex(OpenableColumns.DISPLAY_NAME);
returnCursor.moveToFirst();
filename = returnCursor.getString(nameIndex);
returnCursor.close();
}
}
return filename;
}
public static String getName(String filename) {
if (filename == null) {
return null;
}
int index = filename.lastIndexOf('/');
return filename.substring(index + 1);
}
public static File getDocumentCacheDir(#NonNull Context context) {
File dir = new File(context.getCacheDir(), DOCUMENTS_DIR);
if (!dir.exists()) {
dir.mkdirs();
}
logDir(context.getCacheDir());
logDir(dir);
return dir;
}
public static final String DOCUMENTS_DIR = "documents";
static final String TAG = "FileUtils";
private static final boolean DEBUG = false; // Set to true to enable logging
private static void logDir(File dir) {
if (!DEBUG) return;
Log.d(TAG, "Dir=" + dir);
File[] files = dir.listFiles();
for (File file : files) {
Log.d(TAG, "File=" + file.getPath());
}
}
#Nullable
public static File generateFileName(#Nullable String name, File directory) {
if (name == null) {
return null;
}
File file = new File(directory, name);
if (file.exists()) {
String fileName = name;
String extension = "";
int dotIndex = name.lastIndexOf('.');
if (dotIndex > 0) {
fileName = name.substring(0, dotIndex);
extension = name.substring(dotIndex);
}
int index = 0;
while (file.exists()) {
index++;
name = fileName + '(' + index + ')' + extension;
file = new File(directory, name);
}
}
try {
if (!file.createNewFile()) {
return null;
}
} catch (IOException e) {
Log.w(TAG, e);
return null;
}
logDir(directory);
return file;
}
private static void saveFileFromUri(Context context, Uri uri, String destinationPath) {
InputStream is = null;
BufferedOutputStream bos = null;
try {
is = context.getContentResolver().openInputStream(uri);
bos = new BufferedOutputStream(new FileOutputStream(destinationPath, false));
byte[] buf = new byte[1024];
is.read(buf);
do {
bos.write(buf);
} while (is.read(buf) != -1);
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (is != null) is.close();
if (bos != null) bos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
Step 2:
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == RESULT_OK) {
try {
String path = GetPathFromUri.getPath(this, data.getData())
Glide.with(this).load(path).into(imageView);
// Glide is library https://github.com/bumptech/glide
} catch (IOException e) {
e.printStackTrace();
}
}else if(resultCode == Activity.RESULT_CANCELED) {
// User Cancelled the actiongetUriForFile
}
}
I 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.
Before KitKat (or before the new Gallery) the Intent.ACTION_GET_CONTENT returned a URI like this
content://media/external/images/media/3951.
Using the ContentResolver and quering for
MediaStore.Images.Media.DATA returned the file URL.
In KitKat however the Gallery returns a URI (via "Last") like this:
content://com.android.providers.media.documents/document/image:3951
How do I handle this?
This requires no special permissions, and works with the Storage Access Framework, as well as the unofficial ContentProvider pattern (file path in _data field).
/**
* Get a file path from a Uri. This will get the the path for Storage Access
* Framework Documents, as well as the _data field for the MediaStore and
* other file-based ContentProviders.
*
* #param context The context.
* #param uri The Uri to query.
* #author paulburke
*/
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
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());
}
See an up-to-date version of this method here.
Try this:
if (Build.VERSION.SDK_INT <19){
Intent intent = new Intent();
intent.setType("image/jpeg");
intent.setAction(Intent.ACTION_GET_CONTENT);
startActivityForResult(Intent.createChooser(intent, getResources().getString(R.string.select_picture)),GALLERY_INTENT_CALLED);
} else {
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
intent.addCategory(Intent.CATEGORY_OPENABLE);
intent.setType("image/jpeg");
startActivityForResult(intent, GALLERY_KITKAT_INTENT_CALLED);
}
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode != Activity.RESULT_OK) return;
if (null == data) return;
Uri originalUri = null;
if (requestCode == GALLERY_INTENT_CALLED) {
originalUri = data.getData();
} else if (requestCode == GALLERY_KITKAT_INTENT_CALLED) {
originalUri = data.getData();
final int takeFlags = data.getFlags()
& (Intent.FLAG_GRANT_READ_URI_PERMISSION
| Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
// Check for the freshest data.
getContentResolver().takePersistableUriPermission(originalUri, takeFlags);
}
loadSomeStreamAsynkTask(originalUri);
}
Probably need
#SuppressLint("NewApi")
for
takePersistableUriPermission
Had the same problem, tried the solution above but though it worked generally, for some reason I was getting permission denial on Uri content provider for some images although I had the android.permission.MANAGE_DOCUMENTS permission added properly.
Anyway found other solution which is to force opening image gallery instead of KITKAT documents view with :
// KITKAT
i = new Intent(Intent.ACTION_PICK,android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
startActivityForResult(i, CHOOSE_IMAGE_REQUEST);
and then load the image:
Uri selectedImageURI = data.getData();
input = c.getContentResolver().openInputStream(selectedImageURI);
BitmapFactory.decodeStream(input , null, opts);
EDIT
ACTION_OPEN_DOCUMENT might require you to persist permissions flags etc and generally often results in Security Exceptions...
Other solution is to use the ACTION_GET_CONTENT combined with c.getContentResolver().openInputStream(selectedImageURI) which will work both on pre-KK and KK. Kitkat will use new documents view then and this solution will work with all apps like Photos, Gallery, File Explorer, Dropbox, Google Drive etc...) but remember that when using this solution you have to create image in your onActivityResult() and store it on SD Card for example. Recreating this image from saved uri on next app launch would throw Security Exception on content resolver even when you add permission flags as described in Google API docs (that's what happened when I did some testing)
Additionally the Android Developer API Guidelines suggest:
ACTION_OPEN_DOCUMENT is not intended to be a replacement for ACTION_GET_CONTENT. The one you should use depends on the needs of
your app:
Use ACTION_GET_CONTENT if you want your app to simply read/import
data. With this approach, the app imports a copy of the data, such as
an image file.
Use ACTION_OPEN_DOCUMENT if you want your app to have
long term, persistent access to documents owned by a document
provider. An example would be a photo-editing app that lets users edit
images stored in a document provider.
Just as Commonsware mentioned, you shouldn't assume, that the stream you get via ContentResolver is convertable into file.
What you really should do is to open the InputStream from the ContentProvider, then create a Bitmap out of it. And it works on 4.4 and earlier versions as well, no need for reflection.
//cxt -> current context
InputStream input;
Bitmap bmp;
try {
input = cxt.getContentResolver().openInputStream(fileUri);
bmp = BitmapFactory.decodeStream(input);
} catch (FileNotFoundException e1) {
}
Of course if you handle big images, you should load them with appropriate inSampleSize: http://developer.android.com/training/displaying-bitmaps/load-bitmap.html. But that's another topic.
I believe the responses already posted should get people going in the right direction. However here is what I did that made sense for the legacy code I was updating. The legacy code was using the URI from the gallery to change and then save the images.
Prior to 4.4 (and google drive), the URIs would look like this:
content://media/external/images/media/41
As stated in the question, they more often look like this:
content://com.android.providers.media.documents/document/image:3951
Since I needed the ability to save images and not disturb the already existing code, I just copied the URI from the gallery into the data folder of the app. Then originated a new URI from the saved image file in the data folder.
Here's the idea:
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.setType("image/*");
startActivityForResult(intent), CHOOSE_IMAGE_REQUEST);
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
File tempFile = new File(this.getFilesDir().getAbsolutePath(), "temp_image");
//Copy URI contents into temporary file.
try {
tempFile.createNewFile();
copyAndClose(this.getContentResolver().openInputStream(data.getData()),new FileOutputStream(tempFile));
}
catch (IOException e) {
//Log Error
}
//Now fetch the new URI
Uri newUri = Uri.fromFile(tempFile);
/* Use new URI object just like you used to */
}
Note - copyAndClose() just does file I/O to copy InputStream into a FileOutputStream. The code is not posted.
Just wanted to say that this answer is brilliant and I'm using it for a long time without problems. But some time ago I've stumbled upon a problem that DownloadsProvider returns URIs in format content://com.android.providers.downloads.documents/document/raw%3A%2Fstorage%2Femulated%2F0%2FDownload%2Fdoc.pdf and hence app is crashed with NumberFormatException as it's impossible to parse its uri segments as long. But raw: segment contains direct uri which can be used to retrieve a referenced file. So I've fixed it by replacing isDownloadsDocument(uri) if content with following:
final String id = DocumentsContract.getDocumentId(uri);
if (!TextUtils.isEmpty(id)) {
if (id.startsWith("raw:")) {
return id.replaceFirst("raw:", "");
}
try {
final Uri contentUri = ContentUris.withAppendedId(
Uri.parse("content://downloads/public_downloads"), Long.valueOf(id));
return getDataColumn(context, contentUri, null, null);
} catch (NumberFormatException e) {
Log.e("FileUtils", "Downloads provider returned unexpected uri " + uri.toString(), e);
return null;
}
}
I've combine multiple answers into one working solution that results with file path
Mime type is irrelevant for the example purpose.
Intent intent;
if(Build.VERSION.SDK_INT >= 19){
intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, false);
intent.addFlags(Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION);
}else{
intent = new Intent(Intent.ACTION_GET_CONTENT);
}
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
intent.setType("application/octet-stream");
if(isAdded()){
startActivityForResult(intent, RESULT_CODE);
}
Handling result
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if( requestCode == RESULT_CODE && resultCode == Activity.RESULT_OK) {
Uri uri = data.getData();
if (uri != null && !uri.toString().isEmpty()) {
if(Build.VERSION.SDK_INT >= 19){
final int takeFlags = data.getFlags() & Intent.FLAG_GRANT_READ_URI_PERMISSION;
//noinspection ResourceType
getActivity().getContentResolver()
.takePersistableUriPermission(uri, takeFlags);
}
String filePath = FilePickUtils.getSmartFilePath(getActivity(), uri);
// do what you need with it...
}
}
}
FilePickUtils
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;
public class FilePickUtils {
private static String getPathDeprecated(Context ctx, Uri uri) {
if( uri == null ) {
return null;
}
String[] projection = { MediaStore.Images.Media.DATA };
Cursor cursor = ctx.getContentResolver().query(uri, projection, null, null, null);
if( cursor != null ){
int column_index = cursor
.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
cursor.moveToFirst();
return cursor.getString(column_index);
}
return uri.getPath();
}
public static String getSmartFilePath(Context ctx, Uri uri){
if (Build.VERSION.SDK_INT < 19) {
return getPathDeprecated(ctx, uri);
}
return FilePickUtils.getPath(ctx, uri);
}
#SuppressLint("NewApi")
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 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;
}
/**
* #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());
}
}
Question
How to get an actual file path from a URI
Answer
To my knowledge, we don't need to get the file path from a URI because for most of the cases we can directly use the URI to get our work done (like 1. getting bitmap 2. Sending a file to the server, etc.)
1. Sending to the server
We can directly send the file to the server using just the URI.
Using the URI we can get InputStream, which we can directly send to the server using MultiPartEntity.
Example
/**
* Used to form Multi Entity for a URI (URI pointing to some file, which we got from other application).
*
* #param uri URI.
* #param context Context.
* #return Multi Part Entity.
*/
public MultipartEntity formMultiPartEntityForUri(final Uri uri, final Context context) {
MultipartEntity multipartEntity = new MultipartEntity(HttpMultipartMode.BROWSER_COMPATIBLE, null, Charset.forName("UTF-8"));
try {
InputStream inputStream = mContext.getContentResolver().openInputStream(uri);
if (inputStream != null) {
ContentBody contentBody = new InputStreamBody(inputStream, getFileNameFromUri(uri, context));
multipartEntity.addPart("[YOUR_KEY]", contentBody);
}
}
catch (Exception exp) {
Log.e("TAG", exp.getMessage());
}
return multipartEntity;
}
/**
* Used to get a file name from a URI.
*
* #param uri URI.
* #param context Context.
* #return File name from URI.
*/
public String getFileNameFromUri(final Uri uri, final Context context) {
String fileName = null;
if (uri != null) {
// Get file name.
// File Scheme.
if (ContentResolver.SCHEME_FILE.equals(uri.getScheme())) {
File file = new File(uri.getPath());
fileName = file.getName();
}
// Content Scheme.
else if (ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) {
Cursor returnCursor =
context.getContentResolver().query(uri, null, null, null, null);
if (returnCursor != null && returnCursor.moveToFirst()) {
int nameIndex = returnCursor.getColumnIndex(OpenableColumns.DISPLAY_NAME);
fileName = returnCursor.getString(nameIndex);
returnCursor.close();
}
}
}
return fileName;
}
2. Getting a BitMap from a URI
If the URI is pointing to image then we will get bitmap, else null:
/**
* Used to create bitmap for the given URI.
* <p>
* 1. Convert the given URI to bitmap.
* 2. Calculate ratio (depending on bitmap size) on how much we need to subSample the original bitmap.
* 3. Create bitmap bitmap depending on the ration from URI.
* 4. Reference - http://stackoverflow.com/questions/3879992/how-to-get-bitmap-from-an-uri
*
* #param context Context.
* #param uri URI to the file.
* #param bitmapSize Bitmap size required in PX.
* #return Bitmap bitmap created for the given URI.
* #throws IOException
*/
public static Bitmap createBitmapFromUri(final Context context, Uri uri, final int bitmapSize) throws IOException {
// 1. Convert the given URI to bitmap.
InputStream input = context.getContentResolver().openInputStream(uri);
BitmapFactory.Options onlyBoundsOptions = new BitmapFactory.Options();
onlyBoundsOptions.inJustDecodeBounds = true;
onlyBoundsOptions.inDither = true;//optional
onlyBoundsOptions.inPreferredConfig = Bitmap.Config.ARGB_8888;//optional
BitmapFactory.decodeStream(input, null, onlyBoundsOptions);
input.close();
if ((onlyBoundsOptions.outWidth == -1) || (onlyBoundsOptions.outHeight == -1)) {
return null;
}
// 2. Calculate ratio.
int originalSize = (onlyBoundsOptions.outHeight > onlyBoundsOptions.outWidth) ? onlyBoundsOptions.outHeight : onlyBoundsOptions.outWidth;
double ratio = (originalSize > bitmapSize) ? (originalSize / bitmapSize) : 1.0;
// 3. Create bitmap.
BitmapFactory.Options bitmapOptions = new BitmapFactory.Options();
bitmapOptions.inSampleSize = getPowerOfTwoForSampleRatio(ratio);
bitmapOptions.inDither = true;//optional
bitmapOptions.inPreferredConfig = Bitmap.Config.ARGB_8888;//optional
input = context.getContentResolver().openInputStream(uri);
Bitmap bitmap = BitmapFactory.decodeStream(input, null, bitmapOptions);
input.close();
return bitmap;
}
/**
* For Bitmap option inSampleSize - We need to give value in power of two.
*
* #param ratio Ratio to be rounded of to power of two.
* #return Ratio rounded of to nearest power of two.
*/
private static int getPowerOfTwoForSampleRatio(final double ratio) {
int k = Integer.highestOneBit((int) Math.floor(ratio));
if (k == 0) return 1;
else return k;
}
Comments
Android doesn't provide any methods to get file path from a URI, and in most of the above answers we have hard coded some constants, which may break in feature release (sorry, I may be wrong).
Before going directly going to a solution of the getting file path from a URI, try if you can solve your use case with a URI and Android default methods.
Reference
https://developer.android.com/guide/topics/providers/content-provider-basics.html
https://developer.android.com/reference/android/content/ContentResolver.html
https://hc.apache.org/httpcomponents-client-ga/httpmime/apidocs/org/apache/http/entity/mime/content/InputStreamBody.html
This Android library handles the case changes in KitKat(including the oldere versions - 2.1+):
https://github.com/iPaulPro/aFileChooser
Use the String path = FileUtils.getPath(context, uri) to convert the returned Uri to a path string useable on all OS version.
See more about it here: https://stackoverflow.com/a/20559175/860488
For those who is still using #Paul Burke's code with Android SDK version 23 and above, if your project met the error saying that you are missing EXTERNAL_PERMISSION, and you are very sure you have already added user-permission in your AndroidManifest.xml file. That's because you may in Android API 23 or above and Google make it necessary to guarantee permission again while you make the action to access the file in runtime.
That means: If your SDK version is 23 or above, you are asked for READ & WRITE permission while you are selecting the picture file and want to know the URI of it.
And following is my code, in addition to Paul Burke's solution. I add these code and my project start to work fine.
private static final int REQUEST_EXTERNAL_STORAGE = 1;
private static final String[] PERMISSINOS_STORAGE = {
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE
};
public static void verifyStoragePermissions(Activity activity) {
int permission = ActivityCompat.checkSelfPermission(activity, Manifest.permission.WRITE_EXTERNAL_STORAGE);
if (permission != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(
activity,
PERMISSINOS_STORAGE,
REQUEST_EXTERNAL_STORAGE
);
}
}
And in your activity&fragment where you are asking for the URI:
private void pickPhotoFromGallery() {
CompatUtils.verifyStoragePermissions(this);
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.setType("image/*");
// startActivityForResult(intent, REQUEST_PHOTO_LIBRARY);
startActivityForResult(Intent.createChooser(intent, "éĉİç
§ç"),
REQUEST_PHOTO_LIBRARY);
}
In my case, CompatUtils.java is where I define the verifyStoragePermissions method (as static type so I can call it within other activity).
Also it should make more sense if you make an if state first to see whether the current SDK version is above 23 or not before you call the verifyStoragePermissions method.
This is what I do:
Uri selectedImageURI = data.getData(); imageFile = new File(getRealPathFromURI(selectedImageURI));
private String getRealPathFromURI(Uri contentURI) {
Cursor cursor = getContentResolver().query(contentURI, null, null, null, null);
if (cursor == null) { // Source is Dropbox or other similar local file path
return contentURI.getPath();
} else {
cursor.moveToFirst();
int idx = cursor.getColumnIndex(MediaStore.Images.ImageColumns.DATA);
return cursor.getString(idx);
}
}
NOTE: managedQuery() method is deprecated, so I am not using it.
This answer is from m3n0R on question android get real path by Uri.getPath() and I claim no credit. I just thought that people who haven't solved this issue yet could use this.
I've tried several of the answers here, and I think I have a solution that will work every time and manages permissions as well.
It is based on the clever solution from LEO. This post should contain all the code you need to make this work, and it should work on any phone and Android version ;)
In order to have the ability to pick a file from an SD card, you'll need this in your manifest:
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
Constants:
private static final int PICK_IMAGE = 456; // Whatever number you like
public static final int MY_PERMISSIONS_REQUEST_READ_EXTERNAL = 28528; // Whatever number you like
public static final String FILE_TEMP_NAME = "temp_image"; // Whatever file name you like
Check permission and launchImagePick if possible
if (ContextCompat.checkSelfPermission(getThis(),
Manifest.permission.READ_EXTERNAL_STORAGE)
!= PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(getThis(),
new String[]{Manifest.permission.READ_EXTERNAL_STORAGE},
MY_PERMISSIONS_REQUEST_READ_EXTERNAL);
}
else {
launchImagePick();
}
Permission response
#Override
public void onRequestPermissionsResult(int requestCode,
#NonNull
String permissions[],
#NonNull
int[] grantResults) {
if (manageReadExternalPermissionResponse(this, requestCode, grantResults)) {
launchImagePick();
}
}
Manage permission response
public static boolean manageReadExternalPermissionResponse(final Activity activity, int requestCode, int[] grantResults) {
if (requestCode == MY_PERMISSIONS_REQUEST_READ_EXTERNAL) {
// If request is cancelled, the result arrays are empty.
if (grantResults.length > 0
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// Permission was granted, yay! Do the
// contacts-related task you need to do.
return true;
} else if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_DENIED) {
boolean showRationale = ActivityCompat.shouldShowRequestPermissionRationale(activity,
Manifest.permission.READ_EXTERNAL_STORAGE);
if (!showRationale) {
// The user also CHECKED "never ask again".
// You can either enable some fall back,
// disable features of your app
// or open another dialog explaining
// again the permission and directing to
// the app setting.
} else {
// The user did NOT check "never ask again".
// This is a good place to explain the user
// why you need the permission and ask if he/she wants
// to accept it (the rationale).
}
} else {
// Permission denied, boo! Disable the
// functionality that depends on this permission.
}
}
return false;
}
Launch image pick
private void launchImagePick() {
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.setType("image/*");
intent.addCategory(Intent.CATEGORY_OPENABLE);
startActivityForResult(intent, PICK_IMAGE);
// see onActivityResult
}
Manage Image pick response
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == PICK_IMAGE) {
if (resultCode == Activity.RESULT_OK) {
if (data != null && data.getData() != null) {
try {
InputStream inputStream = getContentResolver().openInputStream(data.getData())
if (inputStream != null) {
// No special persmission needed to store the file like that
FileOutputStream fos = openFileOutput(FILE_TEMP_NAME, Context.MODE_PRIVATE);
final int BUFFER_SIZE = 1 << 10 << 3; // 8 KiB buffer
byte[] buffer = new byte[BUFFER_SIZE];
int bytesRead = -1;
while ((bytesRead = inputStream.read(buffer)) > -1) {
fos.write(buffer, 0, bytesRead);
}
inputStream.close();
fos.close();
File tempImageFile = new File(getFilesDir()+"/"+FILE_TEMP_NAME);
// Do whatever you want with the File
// Delete when not needed anymore
deleteFile(FILE_TEMP_NAME);
}
}
catch (Exception e) {
e.printStackTrace();
}
} else {
// Error display
}
} else {
// The user did not select any image
}
}
}
That's all folks; this works for me on all the telephones I have.
If anyone's interested, I made a working Kotlin version for ACTION_GET_CONTENT:
var path: String = uri.path // uri = any content Uri
val databaseUri: Uri
val selection: String?
val selectionArgs: Array<String>?
if ("/document/image:" in path || "/document/image%3A" in path) {
// files selected from "Documents"
databaseUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI
selection = "_id=?"
selectionArgs = arrayOf(DocumentsContract.getDocumentId(uri).split(":")[1])
} else { // files selected from all other sources, especially on Samsung devices
databaseUri = uri
selection = null
selectionArgs = null
}
try {
val projection = arrayOf(MediaStore.Images.Media.DATA,
MediaStore.Images.Media._ID,
MediaStore.Images.Media.ORIENTATION,
MediaStore.Images.Media.DATE_TAKEN) // some example data you can query
val cursor = context.contentResolver.query(databaseUri,
projection, selection, selectionArgs, null)
if (cursor.moveToFirst()) {
// do whatever you like with the data
}
cursor.close()
} catch (e: Exception) {
Log.e(TAG, e.message, e)
}
Please try to avoid using takePersistableUriPermission method because it raised runtime exception for me.
/**
* Select from gallery.
*/
public void selectFromGallery() {
if (Build.VERSION.SDK_INT < AppConstants.KITKAT_API_VERSION) {
Intent intent = new Intent();
intent.setType("image/*");
intent.setAction(Intent.ACTION_GET_CONTENT);
((Activity)mCalledContext).startActivityForResult(intent,AppConstants.GALLERY_INTENT_CALLED);
} else {
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.setType("image/*");
((Activity)mCalledContext).startActivityForResult(intent, AppConstants.GALLERY_AFTER_KITKAT_INTENT_CALLED);
}
}
OnActivity for result to handle the image data:
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
//gallery intent result handling before kit-kat version
if(requestCode==AppConstants.GALLERY_INTENT_CALLED
&& resultCode == RESULT_OK) {
Uri selectedImage = data.getData();
String[] filePathColumn = {MediaStore.Images.Media.DATA};
Cursor cursor = getContentResolver().query(selectedImage,filePathColumn, null, null, null);
cursor.moveToFirst();
int columnIndex = cursor.getColumnIndex(filePathColumn[0]);
String filePath = cursor.getString(columnIndex);
cursor.close();
photoFile = new File(filePath);
mImgCropping.startCropImage(photoFile,AppConstants.REQUEST_IMAGE_CROP);
}
//gallery intent result handling after kit-kat version
else if (requestCode == AppConstants.GALLERY_AFTER_KITKAT_INTENT_CALLED
&& resultCode == RESULT_OK) {
Uri selectedImage = data.getData();
InputStream input = null;
OutputStream output = null;
try {
//converting the input stream into file to crop the
//selected image from sd-card.
input = getApplicationContext().getContentResolver().openInputStream(selectedImage);
try {
photoFile = mImgCropping.createImageFile();
} catch (IOException e) {
e.printStackTrace();
}catch(Exception e) {
e.printStackTrace();
}
output = new FileOutputStream(photoFile);
int read = 0;
byte[] bytes = new byte[1024];
while ((read = input.read(bytes)) != -1) {
try {
output.write(bytes, 0, read);
} catch (IOException e) {
e.printStackTrace();
}
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
This is a total hack, but here's what I did...
So while playing with setting up a DocumentsProvider, I noticed that the sample code (in getDocIdForFile, around line 450) generates a unique id for a selected document based on the file's (unique) path relative to the specified root you give it (that is, what you set mBaseDir to on line 96).
So the URI ends up looking something like:
content://com.example.provider/document/root:path/to/the/file
As the docs say, it's assuming only a single root (in my case that's Environment.getExternalStorageDirectory() but you may use somewhere else... then it takes the file path, starting at the root, and makes it the unique ID, prepending "root:". So I can determine the path by eliminating the "/document/root:" part from uri.getPath(), creating an actual file path by doing something like this:
public void onActivityResult(int requestCode, int resultCode, Intent data) {
// check resultcodes and such, then...
uri = data.getData();
if (uri.getAuthority().equals("com.example.provider")) {
String path = Environment.getExternalStorageDirectory(0.toString()
.concat("/")
.concat(uri.getPath().substring("/document/root:".length())));
doSomethingWithThePath(path); }
else {
// another provider (maybe a cloud-based service such as GDrive)
// created this uri. So handle it, or don't. You can allow specific
// local filesystem providers, filter non-filesystem path results, etc.
}
I know. It's shameful, but it worked. Again, this relies on you using your own documents provider in your app to generate the document ID.
(Also, there's a better way to build the path that don't assume "/" is the path separator, etc. But you get the idea.)
This worked fine for me:
else if(requestCode == GALLERY_ACTIVITY_NEW && resultCode == Activity.RESULT_OK)
{
Uri uri = data.getData();
Log.i(TAG, "old uri = " + uri);
dumpImageMetaData(uri);
try {
ParcelFileDescriptor parcelFileDescriptor =
getContentResolver().openFileDescriptor(uri, "r");
FileDescriptor fileDescriptor = parcelFileDescriptor.getFileDescriptor();
Log.i(TAG, "File descriptor " + fileDescriptor.toString());
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFileDescriptor(fileDescriptor, null, options);
options.inSampleSize =
BitmapHelper.calculateInSampleSize(options,
User.PICTURE_MAX_WIDTH_IN_PIXELS,
User.PICTURE_MAX_HEIGHT_IN_PIXELS);
options.inJustDecodeBounds = false;
Bitmap bitmap = BitmapFactory.decodeFileDescriptor(fileDescriptor, null, options);
imageViewPic.setImageBitmap(bitmap);
ByteArrayOutputStream stream = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, stream);
// get byte array here
byte[] picData = stream.toByteArray();
ParseFile picFile = new ParseFile(picData);
user.setProfilePicture(picFile);
}
catch(FileNotFoundException exc)
{
Log.i(TAG, "File not found: " + exc.toString());
}
}
Building up on Paul Burke's answer I faced many problems resolving external SD card's URI path as most of the suggested "built-in" functions return paths which do not get resolved to files.
However, this is my approach of his
// TODO handle non-primary volumes.
String resolvedPath = "";
File[] possibleExtSdComposites = context.getExternalFilesDirs(null);
for (File f : possibleExtSdComposites) {
// Reset final path
resolvedPath = "";
// Construct list of folders
ArrayList<String> extSdSplit = new ArrayList<>(Arrays.asList(f.getPath().split("/")));
// Look for folder "<your_application_id>"
int idx = extSdSplit.indexOf(BuildConfig.APPLICATION_ID);
// ASSUMPTION: Expected to be found at depth 2 (in this case ExtSdCard's root is /storage/0000-0000/) - e.g. /storage/0000-0000/Android/data/<your_application_id>/files
ArrayList<String> hierarchyList = new ArrayList<>(extSdSplit.subList(0, idx - 2));
// Construct list containing full possible path to the file
hierarchyList.add(tail);
String possibleFilePath = TextUtils.join("/", hierarchyList);
// If file is found --> success
if (idx != -1 && new File(possibleFilePath).exists()) {
resolvedPath = possibleFilePath;
break;
}
}
if (!resolvedPath.equals("")) {
return resolvedPath;
} else {
return null;
}
Note it depends on hierarchy which might be different on every phone manufacturer - I have not tested them all (it worked well so far on Xperia Z3 API 23 and Samsung Galaxy A3 API 23).
Please confirm if it does not perform well elsewhere.
for this type of uri
content://com.android.providers.media.documents/document/document%3A19298
or uri.getAuthority()is any of these
"com.google.android.apps.docs.storage".equals(uri.getAuthority()) || "com.google.android.apps.docs.storage.legacy".equals(uri.getAuthority());
use this function
private static String getDriveFilePath(Uri uri, Context context) {
Uri returnUri = uri;
Cursor returnCursor = context.getContentResolver().query(returnUri, null, null, null, null);
int nameIndex = returnCursor.getColumnIndex(OpenableColumns.DISPLAY_NAME);
int sizeIndex = returnCursor.getColumnIndex(OpenableColumns.SIZE);
returnCursor.moveToFirst();
String name = (returnCursor.getString(nameIndex));
String size = (Long.toString(returnCursor.getLong(sizeIndex)));
File file = new File(context.getCacheDir(), name);
try {
InputStream inputStream = context.getContentResolver().openInputStream(uri);
FileOutputStream outputStream = new FileOutputStream(file);
int read = 0;
int maxBufferSize = 1 * 1024 * 1024;
int bytesAvailable = inputStream.available();
//int bufferSize = 1024;
int bufferSize = Math.min(bytesAvailable, maxBufferSize);
final byte[] buffers = new byte[bufferSize];
while ((read = inputStream.read(buffers)) != -1) {
outputStream.write(buffers, 0, read);
}
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();
}
#paul burke's answer works fine for both camera and gallery pictures for API level 19 and above, but it doesn't work if your Android project's minimum SDK is set to below 19, and some answers referring above doesn't work for both gallery and camera. Well, I have modified #paul burke's code which works for API level below 19. Below is the code.
public static String getPath(final Context context, final Uri uri) {
final boolean isKitKat = Build.VERSION.SDK_INT >=
Build.VERSION_CODES.KITKAT;
Log.i("URI",uri+"");
String result = uri+"";
// DocumentProvider
// if (isKitKat && DocumentsContract.isDocumentUri(context, uri)) {
if (isKitKat && (result.contains("media.documents"))) {
String[] ary = result.split("/");
int length = ary.length;
String imgary = ary[length-1];
final String[] dat = imgary.split("%3A");
final String docId = dat[1];
final String type = dat[0];
Uri contentUri = null;
if ("image".equals(type)) {
contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
}
else if ("video".equals(type)) {
}
else if ("audio".equals(type)) {
}
final String selection = "_id=?";
final String[] selectionArgs = new String[] {
dat[1]
};
return getDataColumn(context, contentUri, selection, selectionArgs);
}
else
if ("content".equalsIgnoreCase(uri.getScheme())) {
return getDataColumn(context, uri, null, null);
}
// File
else if ("file".equalsIgnoreCase(uri.getScheme())) {
return uri.getPath();
}
return null;
}
public static String getDataColumn(Context context, Uri uri, String selection,
String[] selectionArgs) {
Cursor cursor = null;
final String column = "_data";
final String[] projection = {
column
};
try {
cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs,
null);
if (cursor != null && cursor.moveToFirst()) {
final int column_index = cursor.getColumnIndexOrThrow(column);
return cursor.getString(column_index);
}
}
finally {
if (cursor != null)
cursor.close();
}
return null;
}
The answer to your question is that you need to have permissions. Type the following code in your manifest.xml file:
<uses-sdk android:minSdkVersion="8" android:targetSdkVersion="18" />
<uses-permission android:name="android.permission.READ_CONTACTS" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"></uses-permission>
<uses-permission android:name="android.permission.WRITE_OWNER_DATA"></uses-permission>
<uses-permission android:name="android.permission.READ_OWNER_DATA"></uses-permission>`
It worked for me...
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);
}