My tablet have Internal Storage,USB Storage,External SD card Storage.I need to access External SD card.Still I cannot get the correct answer.
You can access to SD card via adb like:
adb shell cd \$EXTERNAL_STORAGE
Or you may go over getExternalStorageState() .
If you have SD card, you can use Environment.getExternalStorageDirectory() to get root path of your SD card.
in onActivityResult you will get data
Uri selectedImageUri = data.getData();
String path = App.getPath(getActivity(), selectedImageUri);
use this method toget your file path
#TargetApi(19)
#SuppressLint("NewApi")
public static String getPath(final Activity 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
} 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);
} 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();
}
}
if (uri == null) {
// TODO perform some logging or show user feedback
return null;
} else {
// try to retrieve the image from the media store first
// this will only work for images selected from gallery
String[] projection = {MediaStore.Images.Media.DATA};
Cursor cursor = context.managedQuery(uri, projection, null, null, null);
if (cursor != null) {
int column_index = cursor
.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
cursor.moveToFirst();
return cursor.getString(column_index);
}
// this is our fallback here
return uri.getPath();
}
}
public static boolean isMediaDocument(Uri uri) {
return "com.android.providers.media.documents".equals(uri
.getAuthority());
}
public static boolean isDownloadsDocument(Uri uri) {
return "com.android.providers.downloads.documents".equals(uri
.getAuthority());
}
public static boolean isGooglePhotosUri(Uri uri) {
return "com.google.android.apps.photos.content".equals(uri
.getAuthority());
}
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;
}
public static boolean isExternalStorageDocument(Uri uri) {
return "com.android.externalstorage.documents".equals(uri
.getAuthority());
}
Try this way
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent" android:layout_height="fill_parent"
android:orientation="vertical">
<TextView android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="#string/hello" />
<EditText android:id="#+id/myInputText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ems="10" android:lines="5"
android:minLines="3" android:gravity="top|left"
android:inputType="textMultiLine">
<requestFocus />
</EditText>
<Button android:id="#+id/saveInternalStorage"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Save to Internal Storage" />
<Button android:id="#+id/getInternalStorage"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Display from Internal Storage" />
<Button android:id="#+id/saveExternalStorage"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Save to External Storage" />
<Button android:id="#+id/getExternalStorage"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Display from External Storage" />
<TextView android:id="#+id/responseText"
android:layout_width="wrap_content"
android:layout_height="wrap_content" android:padding="5dp"
android:text=""
android:textAppearance="?android:attr/textAppearanceMedium" />
</LinearLayout>
AndroidStorageActivity.java
import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import android.app.Activity;
import android.content.Context;
import android.content.ContextWrapper;
import android.os.Bundle;
import android.os.Environment;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
public class AndroidStorageActivity extends Activity implements OnClickListener{
private String filename = "MySampleFile.txt";
private String filepath = "MyFileStorage";
File myInternalFile;
File myExternalFile;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
ContextWrapper contextWrapper = new ContextWrapper(getApplicationContext());
File directory = contextWrapper.getDir(filepath, Context.MODE_PRIVATE);
myInternalFile = new File(directory , filename);
Button saveToInternalStorage =
(Button) findViewById(R.id.saveInternalStorage);
saveToInternalStorage.setOnClickListener(this);
Button readFromInternalStorage =
(Button) findViewById(R.id.getInternalStorage);
readFromInternalStorage.setOnClickListener(this);
Button saveToExternalStorage =
(Button) findViewById(R.id.saveExternalStorage);
saveToExternalStorage.setOnClickListener(this);
Button readFromExternalStorage =
(Button) findViewById(R.id.getExternalStorage);
readFromExternalStorage.setOnClickListener(this);
//check if external storage is available and not read only
if (!isExternalStorageAvailable() || isExternalStorageReadOnly()) {
saveToExternalStorage.setEnabled(false);
}
else {
myExternalFile = new File(getExternalFilesDir(filepath), filename);
}
}
public void onClick(View v) {
EditText myInputText = (EditText) findViewById(R.id.myInputText);
TextView responseText = (TextView) findViewById(R.id.responseText);
String myData = "";
switch (v.getId()) {
case R.id.saveInternalStorage:
try {
FileOutputStream fos = new FileOutputStream(myInternalFile);
fos.write(myInputText.getText().toString().getBytes());
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
myInputText.setText("");
responseText
.setText("MySampleFile.txt saved to Internal Storage...");
break;
case R.id.getInternalStorage:
try {
FileInputStream fis = new FileInputStream(myInternalFile);
DataInputStream in = new DataInputStream(fis);
BufferedReader br =
new BufferedReader(new InputStreamReader(in));
String strLine;
while ((strLine = br.readLine()) != null) {
myData = myData + strLine;
}
in.close();
} catch (IOException e) {
e.printStackTrace();
}
myInputText.setText(myData);
responseText
.setText("MySampleFile.txt data retrieved from Internal Storage...");
break;
case R.id.saveExternalStorage:
try {
FileOutputStream fos = new FileOutputStream(myExternalFile);
fos.write(myInputText.getText().toString().getBytes());
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
myInputText.setText("");
responseText
.setText("MySampleFile.txt saved to External Storage...");
break;
case R.id.getExternalStorage:
try {
FileInputStream fis = new FileInputStream(myExternalFile);
DataInputStream in = new DataInputStream(fis);
BufferedReader br =
new BufferedReader(new InputStreamReader(in));
String strLine;
while ((strLine = br.readLine()) != null) {
myData = myData + strLine;
}
in.close();
} catch (IOException e) {
e.printStackTrace();
}
myInputText.setText(myData);
responseText
.setText("MySampleFile.txt data retrieved from Internal Storage...");
break;
}
}
private static boolean isExternalStorageReadOnly() {
String extStorageState = Environment.getExternalStorageState();
if (Environment.MEDIA_MOUNTED_READ_ONLY.equals(extStorageState)) {
return true;
}
return false;
}
private static boolean isExternalStorageAvailable() {
String extStorageState = Environment.getExternalStorageState();
if (Environment.MEDIA_MOUNTED.equals(extStorageState)) {
return true;
}
return false;
}
}
you will get output like this
its so easy to get the paths of internal and external sd card paths.
for that we just need to use the reflection mehtod and no need of rooting or signing of app.
Add the following permission in manifest.
uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"
Code:
final Class surfaceControlClass = Class.forName("android.os.storage.StorageManager");
Method method1 = surfaceControlClass.getMethod("getVolumePaths")
method1.setAccessible(true);
final Object object = context.getSystemService(Context.STORAGE_SERVICE);
String[] volumes = method1.invoke(object)
Related
Here's what I would like to do in my app:
allow user to select files and store paths to them inside a database
display names of those files
allow user to click on filename and open the chosen file
So I'd like to get real path to file and store it. The user will only be allowed to get files from internal/external storage so, as I assume, the real path will always exist. I've been looking for solutions and pretty much everyone asks only about images/audio/video and uses MediaStore in their solutions (and I, as of now, have no idea what this is, and I can get Uri without using it). I'd like a solution that would work with any type of file, if that's possible.
Here's how I'm getting Uri:
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.addFlags(FLAG_GRANT_READ_URI_PERMISSION);
intent.setType("*/*");
startActivityForResult(Intent.createChooser(intent, "Choose File"), 1);
and I'm storing the received information in onActivityResult method.
So i get Uri and store it as a string which looks like, for example, content://com.android.providers.downloads.documents/document/4588. How do I convert it to a real filepath?
Sharing my Fileutils file from one of my projects
public class FileUtils {
public static String getFilePath(Context context, Uri uri) throws URISyntaxException {
String selection = null;
String[] selectionArgs = null;
// Uri is different in versions after KITKAT (Android 4.4), we need to
if (Build.VERSION.SDK_INT >= 19 && DocumentsContract.isDocumentUri(context
.getApplicationContext(), 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]
};
} else if (isGoogleDriveFile(uri)) {
String mimeType = context.getContentResolver().getType(uri);
Cursor returnCursor =
context.getContentResolver().query(uri, null, null, null, null);
int nameIndex = returnCursor.getColumnIndex(OpenableColumns.DISPLAY_NAME);
int sizeIndex = returnCursor.getColumnIndex(OpenableColumns.SIZE);
returnCursor.moveToFirst();
String fileName = returnCursor.getString(nameIndex);
Log.d("name", returnCursor.getString(nameIndex));
Log.d("size", Long.toString(returnCursor.getLong(sizeIndex)));
try {
InputStream inputStream = context.getContentResolver().openInputStream(uri);
File root = new File(Environment.getExternalStorageDirectory(), "WittyParrot");
root.mkdirs();
File file = new File(root, fileName);
copyStreamToFile(file, inputStream);
return Uri.fromFile(file).getPath();
} catch (FileNotFoundException e) {
e.printStackTrace();
} finally {
returnCursor.close();
}
}
}
if ("content".equalsIgnoreCase(uri.getScheme())) {
String[] projection = {
MediaStore.Images.Media.DATA
};
Cursor cursor = null;
try {
cursor = context.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;
}
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 boolean isGoogleDriveFile(Uri uri) {
return "com.google.android.apps.docs.storage".equals(uri.getAuthority());
}
public static void copyStreamToFile(File file, InputStream input) {
try {
OutputStream output = new FileOutputStream(file);
try {
byte[] buffer = new byte[4 * 1024]; // or other buffer size
int read;
while ((read = input.read(buffer)) != -1) {
output.write(buffer, 0, read);
}
output.flush();
} catch (IOException e) {
e.printStackTrace();
} finally {
output.close();
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
input.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
The user will only be allowed to get files from internal/external storage
Not according to your code. The user can use anything that supports ACTION_GET_CONTENT. There is no requirement for ACTION_GET_CONTENT implementations to be limited to external storage, and you cannot access internal storage from other apps using the filesystem.
If you are only willing to work with external storage, use a file chooser library, not ACTION_GET_CONTENT or ACTION_OPEN_DOCUMENT.
I'd like a solution that would work with any type of file, if that's possible.
Use a file chooser library.
How do I convert it to a real filepath?
You don't.
Uri = content://com.whatsapp.provider.media/item/118727
I'm not able to get the actual path from this URI
Following the Documentation , i receive the image intent through :
void onCreate (Bundle savedInstanceState) {
...
// Get intent, action and MIME type
Intent intent = getIntent();
String action = intent.getAction();
String type = intent.getType();
if (Intent.ACTION_SEND.equals(action) && type != null) {
if (type.startsWith("image/")) {
handleSendImage(intent); // Handle single image being sent
}
}
}
ContentResolver wasn't working in this case as "_data" field was returning null. So i found another way to get a file from content URI.
In handleSendImage() you need to open inputStream and then copy it into a file.
void handleSendImage(Intent intent) throws IOException {
Uri imageUri = (Uri) intent.getParcelableExtra(Intent.EXTRA_STREAM);
if (imageUri != null) {
File file = new File(getCacheDir(), "image");
InputStream inputStream=getContentResolver().openInputStream(imageUri);
try {
OutputStream output = new FileOutputStream(file);
try {
byte[] buffer = new byte[4 * 1024]; // or other buffer size
int read;
while ((read = inputStream.read(buffer)) != -1) {
output.write(buffer, 0, read);
}
output.flush();
} finally {
output.close();
}
} finally {
inputStream.close();
byte[] bytes =getFileFromPath(file);
//Upload Bytes.
}
}
}
getFileFromPath() gets you the bytes which you can upload on your server.
public static byte[] getFileFromPath(File file) {
int size = (int) file.length();
byte[] bytes = new byte[size];
try {
BufferedInputStream buf = new BufferedInputStream(new FileInputStream(file));
buf.read(bytes, 0, bytes.length);
buf.close();
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return bytes;
}
You can get imageFilePath from getRealPathFromUri() below:
String filePath = getRealPathFromUri(this, fileUri);
// You can upload it as File
if (filePath != null && !filePath.isEmpty()) {
File file = new File(filePath);
if (file.exists()) {
// Using Retrofit you can do it like
// create Retrofit Client code......
// creates RequestBody instance from file
RequestBody requestFile = RequestBody.create(MediaType.parse("multipart/form-data"), file);
// MultipartBody.Part is used to send also the actual filename
MultipartBody.Part body = MultipartBody.Part.createFormData("file", file.getName(), requestFile);
// pass body as parameter while execute call
}
}
getRealPathFromUri()
public static String getRealPathFromUri(Context context, final Uri uri) {
// DocumentProvider
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT && DocumentsContract.isDocumentUri(context, uri)) {
// ExternalStorageProvider
if (isExternalStorageDocument(uri)) {
final String docId = DocumentsContract.getDocumentId(uri);
final String[] split = docId.split(":");
final String type = split[0];
if ("primary".equalsIgnoreCase(type)) {
return Environment.getExternalStorageDirectory() + "/" + split[1];
}
}
// DownloadsProvider
else if (isDownloadsDocument(uri)) {
final String id = DocumentsContract.getDocumentId(uri);
final Uri contentUri = ContentUris.withAppendedId(
Uri.parse("content://downloads/public_downloads"), Long.valueOf(id));
return getDataColumn(context, contentUri, null, null);
}
// MediaProvider
else if (isMediaDocument(uri)) {
final String docId = DocumentsContract.getDocumentId(uri);
final String[] split = docId.split(":");
final String type = split[0];
Uri contentUri = null;
if ("image".equals(type)) {
contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
} else if ("video".equals(type)) {
contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
} else if ("audio".equals(type)) {
contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
}
final String selection = "_id=?";
final String[] selectionArgs = new String[]{
split[1]
};
return getDataColumn(context, contentUri, selection, selectionArgs);
}
}
// MediaStore (and general)
else if ("content".equalsIgnoreCase(uri.getScheme())) {
// Return the remote address
if (isGooglePhotosUri(uri))
return uri.getLastPathSegment();
return getDataColumn(context, uri, null, null);
}
// File
else if ("file".equalsIgnoreCase(uri.getScheme())) {
return uri.getPath();
}
return null;
}
private static String getDataColumn(Context context, Uri uri, String selection,
String[] selectionArgs) {
Cursor cursor = null;
final String column = "_data";
final String[] projection = {
column
};
try {
cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs,
null);
if (cursor != null && cursor.moveToFirst()) {
final int index = cursor.getColumnIndexOrThrow(column);
return cursor.getString(index);
}
} finally {
if (cursor != null)
cursor.close();
}
return null;
}
private static boolean isExternalStorageDocument(Uri uri) {
return "com.android.externalstorage.documents".equals(uri.getAuthority());
}
private static boolean isDownloadsDocument(Uri uri) {
return "com.android.providers.downloads.documents".equals(uri.getAuthority());
}
private static boolean isMediaDocument(Uri uri) {
return "com.android.providers.media.documents".equals(uri.getAuthority());
}
private static boolean isGooglePhotosUri(Uri uri) {
return "com.google.android.apps.photos.content".equals(uri.getAuthority());
}
so here is my problem, i need to get a file in phone and then upload it to my parse-server. I've made a file chooser for document, download, external, media folder but android file chooser also propose GoogleDrive option. So i got te Uri but i can't find a way to access that "local copy?".
Do i need to use GoogleDrive SDK to access it? Or can't android just be smart enough and give me methods to handle that Uri ?
I did success getting file name.
content://com.google.android.apps.docs.storage/document/
Here is my file chooser and handler:
public static void pick(final Controller controller) {
final Intent chooseFileIntent = new Intent(Intent.ACTION_GET_CONTENT);
chooseFileIntent.setType("application/pdf");
chooseFileIntent.addCategory(Intent.CATEGORY_OPENABLE);
if (chooseFileIntent.resolveActivity(controller.getContext().getPackageManager()) != null) {
controller.startActivityForResult(chooseFileIntent, Configuration.Request.Code.Pdf.Pdf);
}
}
private static boolean isExternalStorageDocument(Uri uri) {
return "com.android.externalstorage.documents".equals(uri.getAuthority());
}
private static boolean isDownloadsDocument(Uri uri) {
return "com.android.providers.downloads.documents".equals(uri.getAuthority());
}
private static boolean isMediaDocument(Uri uri) {
return "com.android.providers.media.documents".equals(uri.getAuthority());
}
private static boolean isGooglePhotosUri(Uri uri) {
return "com.google.android.apps.photos.content".equals(uri.getAuthority());
}
private static boolean isGoogleDriveUri(Uri uri) {
return "com.google.android.apps.docs.storage".equals(uri.getAuthority());
}
private static String getDataColumn(Context context, Uri uri, String selection, String[] selectionArgs) {
Cursor cursor = null;
final String column = "_data";
final String[] projection = { column };
try {
cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs, null);
if (cursor != null && cursor.moveToFirst()) {
final int index = cursor.getColumnIndexOrThrow(column);
return cursor.getString(index);
}
} finally {
if (cursor != null)
cursor.close();
}
return null;
}
private static String getPath(Context context, Uri uri) {
if (DocumentsContract.isDocumentUri(context, uri)) {
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];
}
} else if (isGoogleDriveUri(uri)) {
// Cursor cursor = context.getContentResolver().query(uri, null, null, null, null);
// if (cursor != null) {
// int fileNameIndex = cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME);
// cursor.moveToFirst();
// Log.d("=== TAG ===", cursor.getString(fileNameIndex));
// Log.d("=== TAG ===", uri.getPath());
// cursor.close();
// }
} 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);
} 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);
}
}
else if ("content".equalsIgnoreCase(uri.getScheme())) {
if (isGooglePhotosUri(uri))
return uri.getLastPathSegment();
return getDataColumn(context, uri, null, null);
}
else if ("file".equalsIgnoreCase(uri.getScheme())) {
return uri.getPath();
}
return null;
}
public static void upload(final Context context, final String name, final ParseObject dataSource, final String field, final Uri uri, final Handler handler) {
if (context != null && name != null && dataSource != null && field != null && uri != null) {
String path = getPath(context, uri);
if (path != null) {
final File file = new File(path);
dataSource.put(field, new ParseFile(file));
dataSource.getParseFile(field).saveInBackground(new SaveCallback() {
#Override
public void done(ParseException e) {
if (e == null) {
if (handler != null) {
handler.success();
}
}
}
}, new ProgressCallback() {
#Override
public void done(Integer percentDone) {
if (handler != null) {
handler.progress(percentDone);
}
}
});
}
}
}
EDIT :
I've made some try but i got a problem when deleting the temporary file
Here is my code:
public static void copyFile(final Context context, final Uri uri, final ParseObject dataSource, final String field, final String name, final Data.Source target, final Handler handler) {
new AsyncTask<Void, Void, Boolean>() {
#Override
protected Boolean doInBackground(Void... params) {
try {
InputStream inputStream = context.getContentResolver().openInputStream(uri);
if (inputStream != null) {
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
byte[] bytes = new byte[1024];
int length;
while ((length = inputStream.read(bytes)) != -1) {
byteArrayOutputStream.write(bytes, 0, length);
}
dataSource.put(field, new ParseFile(name, byteArrayOutputStream.toByteArray()));
byteArrayOutputStream.close();
inputStream.close();
return true;
} else {
return false;
}
} catch (IOException e) {
e.printStackTrace();
return false;
}
}
#Override
protected void onPostExecute(final Boolean success) {
dataSource.getParseFile(field).saveInBackground(new SaveCallback() {
#Override
public void done(ParseException e) {
if (e == null) {
if (handler != null) {
handler.success();
}
}
}
}, new ProgressCallback() {
#Override
public void done(Integer percentDone) {
if (handler != null) {
handler.progress(percentDone);
}
}
});
}
}.execute();
}
Final Edit:
Here my code is correct, temporary file are created and put in cache by Parse himself, so its out of my range. Hope he can help.
So i got te Uri but i can't find a way to access that "local copy?".
There is no "local copy", at least one that you can access.
Or can't android just be smart enough and give me methods to handle that Uri ?
Use ContentResolver and openInputStream() to get an InputStream on the content identified by the Uri. Either use that directly with your "parse-server", or use it to create a temporary "local copy" to a file that you control. Upload that local copy, deleting it when you are done.
Here is my file chooser and handler:
pick() is fine. upload() might be fine; I have not used Parse. The rest of that code is junk, copied from prior junk. It makes many unfounded, unreliable assumptions, and it will not work for Uri values from arbitrary apps (e.g., served via FileProvider).
I want to sen file to server and I need to get real path from uri.
My code:
public String getPathFromURI(Context context, Uri contentUri) {
if ( contentUri.toString().indexOf("file:///") > -1 ){
return contentUri.getPath();
}
Cursor cursor = null;
try {
String[] proj = { MediaStore.Images.Media.DATA };
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);
}finally {
if (cursor != null) {
cursor.close();
}
}
}
And onActivityResult:
...
imageName = data.getData();
imagePath = getPathFromURI(getBaseContext(),imageName);
Picasso.with(getBaseContext()).load(imageName).into(imageView);
...
How it's possible that image shows in ImageView , but imagePath is ALWAYS null ? :) Thanks
EDIT:
How i send image to server
HttpClient httpClient = new DefaultHttpClient();
HttpContext localContext = new BasicHttpContext();
HttpPost httpPost = new HttpPost([URL TO A SERVER]);
MultipartEntity entity = new MultipartEntity(HttpMultipartMode.BROWSER_COMPATIBLE);
entity.addPart("uploaded_file_1", new FileBody(new File( imagePath )));
httpPost.setEntity(entity);
httpClient.execute(httpPost, localContext);
I went through some answers on stack, and found the solution...
public static String getPathFromURI(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];
}
}
// DownloadsProvider
else if (isDownloadsDocument(uri)) {
final String id = DocumentsContract.getDocumentId(uri);
final Uri contentUri = ContentUris.withAppendedId(Uri.parse("content://downloads/public_downloads"), Long.valueOf(id));
return getDataColumn(context, contentUri, null, null);
}
// MediaProvider
else if (isMediaDocument(uri)) {
final String docId = DocumentsContract.getDocumentId(uri);
final String[] split = docId.split(":");
final String type = split[0];
Uri contentUri = null;
if ("image".equals(type)) {
contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
} else if ("video".equals(type)) {
contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
} else if ("audio".equals(type)) {
contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
}
final String selection = "_id=?";
final String[] selectionArgs = new String[] {
split[1]
};
return getDataColumn(context, contentUri, selection, selectionArgs);
}
}
// MediaStore (and general)
else if ("content".equalsIgnoreCase(uri.getScheme())) {
return getDataColumn(context, uri, null, null);
}
// File
else if ("file".equalsIgnoreCase(uri.getScheme())) {
return uri.getPath();
}
return null;
}
public static String getDataColumn(Context context, Uri uri, String selection,
String[] selectionArgs) {
Cursor cursor = null;
final String column = "_data";
final String[] projection = {
column
};
try {
cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs,
null);
if (cursor != null && cursor.moveToFirst()) {
final int column_index = cursor.getColumnIndexOrThrow(column);
return cursor.getString(column_index);
}
} finally {
if (cursor != null)
cursor.close();
}
return null;
}
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());
}
This will find the real path in every case even for kitkat (that was the problem... kitkat)
From android 10 you must use app-specific storage for your files. In case you want file from external storage and do something to it like you want to upload it to the server, you need to get the file and make a copy of it to the app-specific storage.
Here is what you can use, assuming you already have the uri of the selected file.
val parcelFileDescriptor =
contentResolver.openFileDescriptor(selectedImageUri!!, "r", null) ?: return
val inputStream = FileInputStream(parcelFileDescriptor.fileDescriptor)
val file = File(cacheDir, contentResolver.getFileName(selectedImageUri!!))
val outputStream = FileOutputStream(file)
inputStream.copyTo(outputStream)
And the function to get the file name from the Uri is
fun ContentResolver.getFileName(fileUri: Uri): String {
var name = ""
val returnCursor = this.query(fileUri, null, null, null, null)
if (returnCursor != null) {
val nameIndex = returnCursor.getColumnIndex(OpenableColumns.DISPLAY_NAME)
returnCursor.moveToFirst()
name = returnCursor.getString(nameIndex)
returnCursor.close()
}
return name
}
Now you can use file.path and it will work.
If you don't want to do like this then for android 10 there is also a temporary solution that is
android:requestLegacyExternalStorage="true"
You can add this to your AndroidManifest.xml inside application tag.
Reference: Android Upload File to Server
Hope this will help, Thank You :)
This code work for me in android 11 and 12
private static String getRealPathFromURI(Uri uri, Context context) {
Uri returnUri = uri;
Cursor returnCursor = context.getContentResolver().query(returnUri, null, null, null, null);
int nameIndex = returnCursor.getColumnIndex(OpenableColumns.DISPLAY_NAME);
int sizeIndex = returnCursor.getColumnIndex(OpenableColumns.SIZE);
returnCursor.moveToFirst();
String name = (returnCursor.getString(nameIndex));
String size = (Long.toString(returnCursor.getLong(sizeIndex)));
File file = new File(context.getFilesDir(), name);
try {
InputStream inputStream = context.getContentResolver().openInputStream(uri);
FileOutputStream outputStream = new FileOutputStream(file);
int read = 0;
int maxBufferSize = 1 * 1024 * 1024;
int bytesAvailable = inputStream.available();
//int bufferSize = 1024;
int bufferSize = Math.min(bytesAvailable, maxBufferSize);
final byte[] buffers = new byte[bufferSize];
while ((read = inputStream.read(buffers)) != -1) {
outputStream.write(buffers, 0, read);
}
Log.e("File Size", "Size " + file.length());
inputStream.close();
outputStream.close();
Log.e("File Path", "Path " + file.getPath());
Log.e("File Size", "Size " + file.length());
} catch (Exception e) {
Log.e("Exception", e.getMessage());
}
return file.getPath();
}
I couldn't get the path for a Marshmallow phone sharing media from Google Photos to my app. I'll try to explain myself why this is probably happening.
I didn't find any official documentation to base my thought, but I'll share them with you to see if with some collaboration from different minds we reach to a solution.
My theory is that Google Photos does not have the media files physically in the phone, they are probably thumbnails or online. So when you share some pics, they are downloaded temporary and probably stored in the Internal Storage of the App so you can't access it (to the path).
The only workaround I found to get the path of the file is copying it to my app internal storage. I don't like it but everything I tried didn't work for me.
Thanks Michal Heneš and Sam .
After a lot of searching I got solution in java.
import android.annotation.SuppressLint;
import android.content.ContentResolver;
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.util.Log;
import android.widget.Switch;
import java.io.File;
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.ListIterator;
import java.util.Objects;
import kotlin.Metadata;
import kotlin.collections.CollectionsKt;
import kotlin.jvm.internal.Intrinsics;
import kotlin.text.Regex;
import kotlin.text.StringsKt;
public class UtilsFile {
private final static String PUBLIC_DOWNLOAD_PATH = "content://downloads/public_downloads";
private final static String EXTERNAL_STORAGE_DOCUMENTS_PATH = "com.android.externalstorage.documents";
private final static String DOWNLOAD_DOCUMENTS_PATH = "com.android.providers.downloads.documents";
private final static String MEDIA_DOCUMENTS_PATH = "com.android.providers.media.documents";
private final static String PHOTO_CONTENTS_PATH = "com.google.android.apps.photos.content";
private Boolean isExternalStorageDocument(Uri uri) {
return EXTERNAL_STORAGE_DOCUMENTS_PATH.equals(uri.getAuthority());
}
private Boolean isPublicDocument(Uri uri) {
return PUBLIC_DOWNLOAD_PATH.equals(uri.getAuthority());
}
private Boolean isDownloadsDocument(Uri uri) {
return DOWNLOAD_DOCUMENTS_PATH.equals(uri.getAuthority());
}
private Boolean isMediaDocument(Uri uri) {
return MEDIA_DOCUMENTS_PATH.equals(uri.getAuthority());
}
private Boolean isGooglePhotosUri(Uri uri) {
return MEDIA_DOCUMENTS_PATH.equals(uri.getAuthority());
}
private Boolean isPhotoContentUri(Uri uri) {
return PHOTO_CONTENTS_PATH.equals(uri.getAuthority());
}
private String getDataColumn(Context context, Uri uri, String selection, String[] selectionArgs) {
Cursor cursor = null;
//String column = "_data" REMOVED IN FAVOR OF NULL FOR ALL
//String projection = arrayOf(column) REMOVED IN FAVOR OF PROJECTION FOR ALL
try {
cursor = context.getContentResolver().query(uri, null, selection, selectionArgs, null);
if (cursor != null && cursor.moveToFirst()) {
int columnIndex = cursor.getColumnIndexOrThrow(DocumentsContract.Document.COLUMN_DISPLAY_NAME);
return cursor.getString(columnIndex);
}
} catch (Exception e) {
Log.e("PathUtils", "Error getting uri for cursor to read file: " + e.getMessage());
} finally {
assert cursor != null;
cursor.close();
}
return null;
}
public String getFullPathFromContentUri(final Context context, final Uri uri) {
final boolean isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;
String filePath="";
// 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];
}//non-primary e.g sd card
else {
if (Build.VERSION.SDK_INT > 20) {
//getExternalMediaDirs() added in API 21
File[] extenal = context.getExternalMediaDirs();
for (File f : extenal) {
filePath = f.getAbsolutePath();
if (filePath.contains(type)) {
int endIndex = filePath.indexOf("Android");
filePath = filePath.substring(0, endIndex) + split[1];
}
}
}else{
filePath = "/storage/" + type + "/" + split[1];
}
return filePath;
}
}
// DownloadsProvider
else if (isDownloadsDocument(uri)) {
String fileName = getDataColumn(context, uri,null, null);
String uriToReturn = null;
if (fileName != null) {
uriToReturn = Uri.withAppendedPath(
Uri.parse(
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).getAbsolutePath()), fileName
).toString();
}
return uriToReturn;
}
// 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]
};
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;
}
}
// 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();
}
else if (isPublicDocument(uri)){
String id = DocumentsContract.getDocumentId(uri);
final Uri contentUri = ContentUris.withAppendedId(
Uri.parse(PUBLIC_DOWNLOAD_PATH), Long.parseLong(id));
String[] projection = {MediaStore.Images.Media.DATA};
#SuppressLint("Recycle") Cursor cursor = context.getContentResolver().query(contentUri, projection, null, null, null);
if (cursor != null && cursor.moveToFirst()) {
int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
cursor.moveToFirst();
return cursor.getString(column_index);
}
}
return null;
}
}
Accessing public download files onActivityResult Android 28 Samsung Galaxy S9+ (Verizon)
you can use this funtion for get file from uri in new android and older
fun getFileFromUri(context: Context, uri: Uri?): File? {
uri ?: return null
uri.path ?: return null
var newUriString = uri.toString()
newUriString = newUriString.replace(
"content://com.android.providers.downloads.documents/",
"content://com.android.providers.media.documents/"
)
newUriString = newUriString.replace(
"/msf%3A", "/image%3A"
)
val newUri = Uri.parse(newUriString)
var realPath = String()
val databaseUri: Uri
val selection: String?
val selectionArgs: Array<String>?
if (newUri.path?.contains("/document/image:") == true) {
databaseUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI
selection = "_id=?"
selectionArgs = arrayOf(DocumentsContract.getDocumentId(newUri).split(":")[1])
} else {
databaseUri = newUri
selection = null
selectionArgs = null
}
try {
val column = "_data"
val projection = arrayOf(column)
val cursor = context.contentResolver.query(
databaseUri,
projection,
selection,
selectionArgs,
null
)
cursor?.let {
if (it.moveToFirst()) {
val columnIndex = cursor.getColumnIndexOrThrow(column)
realPath = cursor.getString(columnIndex)
}
cursor.close()
}
} catch (e: Exception) {
Log.i("GetFileUri Exception:", e.message ?: "")
}
val path = realPath.ifEmpty {
when {
newUri.path?.contains("/document/raw:") == true -> newUri.path?.replace(
"/document/raw:",
""
)
newUri.path?.contains("/document/primary:") == true -> newUri.path?.replace(
"/document/primary:",
"/storage/emulated/0/"
)
else -> return null
}
}
return if (path.isNullOrEmpty()) null else File(path)
}
I tried a solution (see below) that works fine, except in Android 4.4 the call to startActivityForResult() brings up an activity titled "Open from", which has "Recent", "Images", "Downloads" as well as several apps to pick from. When I choose "Images" and try to resolve the returned content URI (using the code below), the call to cursor.getString() returns null. If I choose the exact same file using the Gallery app, cursor.getString() returns a file path. I've only tested this in API levels 16 and 19. Everything works as expected in 16. As far as 19 goes, I have to choose the Gallery or other app or it doesn't work.
private String getRealPathFromURI(Context context, Uri contentUri) {
Cursor cursor = null;
try {
String[] proj = { MediaStore.Images.Media.DATA };
cursor = context.getContentResolver().query(contentUri, proj, null, null, null);
int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
cursor.moveToFirst();
String path = cursor.getString(column_index);
return path;
} finally {
if (cursor != null) {
cursor.close();
}
}
}
This will get the file path from the MediaProvider, DownloadsProvider, and ExternalStorageProvider, while falling back to the unofficial ContentProvider method you mention.
/**
* 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 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());
}
source aFileChooser
Convert content:// URI to actual path in Android 4.4
There is no reliable way to do this on any Android version. A content:// Uri does not have to represent a file on the filesystem, let alone one that you are able to access.
Android 4.4's changes to offer the storage framework simply increases the frequency with which you will encounter content:// Uri values.
If you get a content:// Uri, please consume it using a ContentResolver and methods like openInputStream() and openOutputStream().
I have been facing this problem too, but in my case, what I wanted to do was to specify a concrete Uri to the Gallery so I can use crop later. Looks like in the new Document Browser of KitKat we can't do that anymore unless you choose galery in the navigation drawer, and, like you said, open the image or file directly from there.
In the Uri case, you can still retrieve the path when opening fromt he Document Browser.
Intent dataIntent= new Intent(Intent.ACTION_GET_CONTENT);
dataIntent.setType("image/*"); //Or whatever type you need
And then in onActivityResult:
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == ACTIVITY_SELECT_IMAGE && resultCode == RESULT_OK) {
myUri = data.getData();
String path = myUri.getPath();
openPath(myUri);
}
}
If you need then to open a file with that path, you just have yo use a Content Resolver:
public void openPath(Uri uri){
InputStream is = null;
try {
is = getContentResolver().openInputStream(uri);
//Convert your stream to data here
is.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
It is introduced in a Google API. You can try this:
private Bitmap getBitmapFromUri(Uri uri) throws IOException {
ParcelFileDescriptor parcelFileDescriptor =
getContentResolver().openFileDescriptor(uri, "r");
FileDescriptor fileDescriptor = parcelFileDescriptor.getFileDescriptor();
Bitmap image = BitmapFactory.decodeFileDescriptor(fileDescriptor);
parcelFileDescriptor.close();
return image;
}
If you really need a file path. First, get the data using ContentResolver. Then, you can save the data to a temp file and use that path.
(I had to use a library with File object in a function parameter.)
Thanks to #FireBear, I modified answer now one will get path of media file
String filePath=saveBitmap(activity,getBitmapFromUri(imageUri),"tmpFile").getPath();
private Bitmap getBitmapFromUri(Context context, Uri uri) throws IOException {
ParcelFileDescriptor parcelFileDescriptor =
context.getContentResolver().openFileDescriptor(uri, "r");
FileDescriptor fileDescriptor = parcelFileDescriptor.getFileDescriptor();
Bitmap image = BitmapFactory.decodeFileDescriptor(fileDescriptor);
parcelFileDescriptor.close();
return image;
}
private File saveBitmap(Context context, Bitmap bitmap, String name) {
File filesDir = context.getFilesDir();
File imageFile = new File(filesDir, name + ".jpg");
OutputStream os;
try {
os = new FileOutputStream(imageFile);
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, os);
os.flush();
os.close();
} catch (Exception e) {
//Log.e(getClass().getSimpleName(), "Error writing bitmap", e);
}
return imageFile;
}
I know it does not answer the question itself, but as #CommonsWare sad, SAF was not meant to use this way.
Maybe an option for this is creating a copy of the file on the app's external files dir, use it and then delete it.
public File createFileCopy(Context context, DocumentFile file) {
if (file == null || !file.exists() || file.getName() == null) {
throw new IllegalArgumentException("The file must no be null, and must exist, and must have a name.");
}
File fileCopy = new File(context.getExternalFilesDir(null).getAbsolutePath(), file.getName());
try {
android.os.FileUtils.copy(openFileInputStream(file), new FileOutputStream(fileCopy));
return fileCopy;
} catch (Exception e) {
// do whateveer you want with this exceeption
e.printStackTrace();
}
return null;
}
I tried in a different way. each answer on stackoverflow was having some kind of issue, either it leads to some kind of crash or dosen't works out. the first answer above won't work for finding URI from whatsApp media.
below solution is all rounder solution worked for me. I have copied complete PathUtils class here. use getpath() function for the path.
public class PathUtils {
private static final int BUFFER_SIZE = 1024 * 2;
public static String getPath(Context context, Uri contentUri) {
String fileName = getFileName(contentUri);
if (!TextUtils.isEmpty(fileName)) {
File copyFile = new File(context.getCacheDir() + fileName+contentUri.getScheme());
copy(context, contentUri, copyFile);
return copyFile.getAbsolutePath();
}
return null;
}
public static String getFileName(Uri uri) {
if (uri == null) return null;
String fileName = null;
String path = uri.getPath();
int cut = path.lastIndexOf('/');
if (cut != -1) {
fileName = path.substring(cut + 1);
}
return fileName;
}
public static void copy(Context context, Uri srcUri, File dstFile) {
try {
InputStream inputStream = context.getContentResolver().openInputStream(srcUri);
if (inputStream == null) return;
OutputStream outputStream = new FileOutputStream(dstFile);
copyMain(inputStream, outputStream);
inputStream.close();
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
public static int copyMain(InputStream input, OutputStream output) throws Exception, IOException {
byte[] buffer = new byte[BUFFER_SIZE];
BufferedInputStream in = new BufferedInputStream(input, BUFFER_SIZE);
BufferedOutputStream out = new BufferedOutputStream(output, BUFFER_SIZE);
int count = 0, n = 0;
try {
while ((n = in.read(buffer, 0, BUFFER_SIZE)) != -1) {
out.write(buffer, 0, n);
count += n;
}
out.flush();
} finally {
try {
out.close();
} catch (IOException e) {
Log.e(e.getMessage(), e.toString());
}
try {
in.close();
} catch (IOException e) {
Log.e(e.getMessage(), e.toString());
}
}
return count;
}
}
Convert content:// URI to actual path in Android.
I have managed this fileUtils Class From a SO answer, and get path from all kinds of Uri:
package com.alquran.tafhimul_quran.Common;
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.util.Log;
import androidx.annotation.RequiresApi;
import java.io.File;
public class UtilsFile {
private final static String PUBLIC_DOWNLOAD_PATH = "content://downloads/public_downloads";
private final static String EXTERNAL_STORAGE_DOCUMENTS_PATH = "com.android.externalstorage.documents";
private final static String DOWNLOAD_DOCUMENTS_PATH = "com.android.providers.downloads.documents";
private final static String MEDIA_DOCUMENTS_PATH = "com.android.providers.media.documents";
private final static String PHOTO_CONTENTS_PATH = "com.google.android.apps.photos.content";
private Boolean isExternalStorageDocument(Uri uri) {
return EXTERNAL_STORAGE_DOCUMENTS_PATH.equals(uri.getAuthority());
}
private Boolean isPublicDocument(Uri uri) {
return PUBLIC_DOWNLOAD_PATH.equals(uri.getAuthority());
}
private Boolean isDownloadsDocument(Uri uri) {
return DOWNLOAD_DOCUMENTS_PATH.equals(uri.getAuthority());
}
private Boolean isMediaDocument(Uri uri) {
return MEDIA_DOCUMENTS_PATH.equals(uri.getAuthority());
}
private Boolean isGooglePhotosUri(Uri uri) {
return MEDIA_DOCUMENTS_PATH.equals(uri.getAuthority());
}
private Boolean isPhotoContentUri(Uri uri) {
return PHOTO_CONTENTS_PATH.equals(uri.getAuthority());
}
private String getDataColumn(Context context, Uri uri, String selection, String[] selectionArgs) {
Cursor cursor = null;
//String column = "_data" REMOVED IN FAVOR OF NULL FOR ALL
//String projection = arrayOf(column) REMOVED IN FAVOR OF PROJECTION FOR ALL
try {
cursor = context.getContentResolver().query(uri, null, selection, selectionArgs, null);
if (cursor != null && cursor.moveToFirst()) {
int columnIndex = cursor.getColumnIndexOrThrow(DocumentsContract.Document.COLUMN_DISPLAY_NAME);
return cursor.getString(columnIndex);
}
} catch (Exception e) {
Log.e("PathUtils", "Error getting uri for cursor to read file: " + e.getMessage());
} finally {
assert cursor != null;
cursor.close();
}
return null;
}
#RequiresApi(api = Build.VERSION_CODES.KITKAT)
public String getFullPathFromContentUri(final Context context, final Uri uri) {
final boolean isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;
String filePath="";
// 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];
}//non-primary e.g sd card
else {
if (Build.VERSION.SDK_INT > 20) {
//getExternalMediaDirs() added in API 21
File[] extenal = context.getExternalMediaDirs();
for (File f : extenal) {
filePath = f.getAbsolutePath();
if (filePath.contains(type)) {
int endIndex = filePath.indexOf("Android");
filePath = filePath.substring(0, endIndex) + split[1];
}
}
}else{
filePath = "/storage/" + type + "/" + split[1];
}
return filePath;
}
}
// DownloadsProvider
else if (isDownloadsDocument(uri)) {
String fileName = getDataColumn(context, uri,null, null);
String uriToReturn = null;
if (fileName != null) {
uriToReturn = Uri.withAppendedPath(
Uri.parse(
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).getAbsolutePath()), fileName
).toString();
}
return uriToReturn;
}
// 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]
};
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;
}
}
// 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();
}
else if (isPublicDocument(uri)){
String id = DocumentsContract.getDocumentId(uri);
final Uri contentUri = ContentUris.withAppendedId(
Uri.parse(PUBLIC_DOWNLOAD_PATH), Long.parseLong(id));
String[] projection = {MediaStore.Images.Media.DATA};
#SuppressLint("Recycle") Cursor cursor = context.getContentResolver().query(contentUri, projection, null, null, null);
if (cursor != null && cursor.moveToFirst()) {
int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
cursor.moveToFirst();
return cursor.getString(column_index);
}
}
return null;
}
}
Usage of OnActivityResult:
if (requestCode == PICK_AUDIO_REQUEST && resultCode == RESULT_OK && data != null && data.getData() != null) {
Uri uri = data.getData();
UtilsFile utilsFile = new UtilsFile();
String filePath = utilsFile.getFullPathFromContentUri(mContext, uri);
System.out.println("Audio File Path : "+ filePath);
// audioString = audioFileToString(filePath);
}
Get a file path from a Uri:- I had created a Util class that will get the path for Storage Access Framework Documents, as well as the _data field for the MediaStore and other file-based ContentProviders.
ConvertUriToFilePath :-
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.support.annotation.RequiresApi;
public class ConvertUriToFilePath {
/**
* 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.
*/
#RequiresApi(api = Build.VERSION_CODES.KITKAT)
public static String getPathFromURI(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())) {
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);
// 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());
}
}
Example Code :
// Just call this function of ConvertUriToFilePath class and it will return full path of file URI.
String actualFilepath= ConvertUriToFilePath.getPathFromURI(activity,tempUri);