I have this code to upload a file to my app, and when the file is opened with a file manager, or dropbox, or anything else, the returned path is correct and I can access it, I am only having problems with Google Drive, it returns some path starting with "exposed_content" and I can't "decode" it any way, I have searched and didn't found a way, anyone have any idea?
if (resultCode == Activity.RESULT_OK) {
if ((data != null) && (data.getData() != null)) {
final Uri filePath;
if (data.getDataString().startsWith("content")) {
filePath = getRealPathFromURI(getApplicationContext(), data.getData());
} else {
filePath = data.getData();
}
// TODO bug with google drive
if (filePath.getLastPathSegment() != null) {
tvSelectedFile.setText("File selected: " + filePath.getLastPathSegment());
} else {
tvSelectedFile.setText("File can not be accessed, please try another way");
}
}
}
Use the attached code... from onActivity result you will get content uri ...pass this uri to the given method...
public static String getGDriveDataColumn(Context context, Uri uri, String selection,
String[] selectionArgs) {
Cursor cursor = null;
final String column = "_display_name";
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;
}
Related
When I'm going select a file from all downloads folder and then getting file path from uri using content provider getting following permission denied issue below
Permission Denial: reading com.android.providers.downloads.DownloadProvider uri content://downloads/all_downloads/1092 from pid=31615, uid=10228 requires android.permission.ACCESS_ALL_DOWNLOADS, or grantUriPermission()
using following code
String[] contentUriPrefixesToTry = new String[]{
"content://downloads/public_downloads",
"content://downloads/my_downloads",
"content://downloads/all_downloads"
};
final String id = DocumentsContract.getDocumentId(uri);
String path = null;
for (String uriPath : contentUriPrefixesToTry) {
final Uri contentUri = ContentUris.withAppendedId(
Uri.parse(uriPath), Long.valueOf(id));
String lastPathSagment = uri.getLastPathSegment();
InputStream inputStream = context.getContentResolver().openInputStream(uri);
File file = new File(context.getCacheDir().getAbsolutePath() + "/" + lastPathSagment);
writeFile(inputStream, file);
path = file.getAbsolutePath();
if (path != null) {
return path;
}
}
I had the above issue, but found a solution. I was using ACTION_GET_CONTENT to pick a file from external storage, but it does not work in Android 7 and above. Someone guided me to use ACTION_OPEN_DOCUMENT to pick a file, and now it's working fine for me.
Intent PDF Picker:
if (Build.VERSION.SDK_INT <19) {
Intent pdfIntent = new Intent(Intent.ACTION_GET_CONTENT);
pdfIntent.setType("application/pdf");
startActivityForResult(pdfIntent, PICK_PDF);
} else {
Intent pdfIntent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
pdfIntent.setType("application/pdf");
pdfIntent.addCategory(Intent.CATEGORY_OPENABLE);
startActivityForResult(pdfIntent, PICK_PDF);
}
Code to get File Path:
if (isDownloadsDocument(uri)) {
String fileName = getFilePath(context, uri);
if (fileName != null) {
return String.format("%s/Download/%s", Environment.getExternalStorageDirectory().toString(), fileName);
}
String id = DocumentsContract.getDocumentId(uri);
if (id.startsWith("raw:")) {
id = id.replaceFirst("raw:", "");
File file = new File(id);
if (file.exists())
return id;
}
}
final Uri contentUri = ContentUris.withAppendedId(Uri.parse("content://downloads/public_downloads"), Long.valueOf(id));
return getDataColumn(context, contentUri, null, null);
}
Methods used in above code:
public static String getFilePath(Context context, Uri uri) {
Cursor cursor = null;
final String[] projection = { MediaStore.MediaColumns.DISPLAY_NAME };
try {
cursor = context.getContentResolver().query(uri, projection, null, null, null);
if (cursor != null && cursor.moveToFirst()) {
final int index = cursor.getColumnIndexOrThrow(MediaStore.MediaColumns.DISPLAY_NAME);
return cursor.getString(index);
}
} catch(Exception e) {
e.printStackTrace();
} finally {
if (cursor != null) {
cursor.close();
}
}
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 column_index = cursor.getColumnIndexOrThrow(column);
return cursor.getString(column_index);
}
} finally {
if (cursor != null) {
cursor.close();
}
}
return null;
}
private static boolean isDownloadsDocument(Uri uri) {
return "com.android.providers.downloads.documents".equals(uri.getAuthority());
}
Your code is 'trying' to access that directory to see if it exists, and even open an inputstream to get the supposed File. If the directory doesn't exist Android will be displeased with you and tell you that you're not allowed to access that dir.
No need to request permission as the dir does not exist.
Trying to extract file path from send action:
<data android:mimeType="*/*" />
Here is activity:
Uri contentUri = intent.getParcelableExtra(Intent.EXTRA_STREAM);
if (contentUri != null) {
String pathUri = contentUri.toString();
if (pathUri.contains("file://")) {
path = contentUri.getPath();
}
}
if(path==null) {
if (type.startsWith("image/")) {
path = Constant.getRealPathFromURI(this, (Uri) intent.getParcelableExtra(Intent.EXTRA_STREAM));
} else if (type.startsWith("video/")) {
path = Constant.getRealPathFromURI(this, (Uri) intent.getParcelableExtra(Intent.EXTRA_STREAM));
}
}
if (path == null && intent.getData() != null) {
path = intent.getData().getPath();
}
if (path == null) {
Toast.makeText(getApplicationContext(), "None uri !", Toast.LENGTH_LONG).show();
}
Always getting null path except 'image/' and 'video/".
on: Essential PH-1 device
Working all fine on: Lenovo Vibe K5 Note
Is not bullet proof code for all devices? anything wrong with code?
Is there any universal way to extract send action file path without being worried about it's mimetype?
Edit:
public static String getRealPathFromURI(Context context, Uri contentUri) {
String[] proj = {MediaStore.Images.Media.DATA};
Cursor cursor = context.getContentResolver().query(contentUri, proj, null, null, null);
int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
cursor.moveToFirst();
return cursor.getString(column_index);
}
I am trying to access file from device. All works goods but when i browse and select file from google drive it gives null path. I have seen many question but didn't got the answer. One solution which i got below only gives me the file name.
public static String getGDriveDataColumn(Context context, Uri uri, String selection,
String[] selectionArgs) {
Cursor cursor = null;
final String column = "_display_name";
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;
}
Is it possible to get that file? Because that file is on the drive and not on the device. Please help me how can i get that file.
I have developing app which get the path from SDcard for all types (Images, Audio, Video)...
It works fine for opening the Default Android Browsers(Gallery). But when i open the SDcard in other app's it throws NullPointer. For example i have open the SDcard through my app using Explorer app shows null pointer exception...
I will save the image path to SQlite and get the content from the SQLite on another activity. But this Explorer app shows all types, not only for specified type. (Example i select image button, but it shows all types).
radio_group.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(RadioGroup rd_group, int checked_id) {
checking = null;
switch(checked_id) {
case R.id.radio_image:
checking = "image";
break;
case R.id.radio_audio:
checking = "audio";
break;
case R.id.radio_video:
checking = "video";
break;
}
}
});
// I have a radio button for type of content will shown only
select_content.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View view) {
if(checking.equals("")) {
Toast.makeText(getApplicationContext(), "Please select the content type", Toast.LENGTH_SHORT).show();
return;
}
// when i select image, show image content only in SDcard.
// When i select audio, show only audio contents.
// when i select video, show only video contents.
if(checking.equals("image")) {
Intent intent_image = new Intent();
intent_image.setType("image/*");
intent_image.setAction(Intent.ACTION_GET_CONTENT);
startActivityForResult(Intent.createChooser(intent_image, "Select Image"), SELECT_IMAGE_DIALOG);
}
if(checking.equals("audio")) {
Intent intent_audio = new Intent();
intent_audio.setType("audio/*");
intent_audio.setAction(Intent.ACTION_GET_CONTENT);
startActivityForResult(Intent.createChooser(intent_audio, "Select Audio"), SELECT_AUDIO_DIALOG);
}
if(checking.equals("video")) {
Intent intent_video = new Intent();
intent_video.setType("video/*");
intent_video.setAction(Intent.ACTION_GET_CONTENT);
startActivityForResult(Intent.createChooser(intent_video, "Select Video"), SELECT_VIDEO_DIALOG);
}
}
});
public void onActivityResult(int requestCode, int resultCode, Intent result) {
// imagePath = null;
if (requestCode == SELECT_IMAGE_DIALOG) {
if (resultCode == Activity.RESULT_OK) {
Uri data = result.getData();
Log.d("DATA", data.toString());
selected_Path = getPath(data);
final_path.getBytes();
selected_path_text.setText(final_path);
Log.d("Image Path", final_path);
}
}
if (requestCode == SELECT_AUDIO_DIALOG) {
if (resultCode == RESULT_OK) {
Uri data = result.getData();
Log.d("DATA", data.toString());
selected_Path = getPath(data);
final_path.getBytes();
selected_path_text.setText(final_path);
Log.d("Audio Path", final_path);
}
}
if (requestCode == SELECT_VIDEO_DIALOG) {
if (resultCode == RESULT_OK) {
Uri data = result.getData();
Log.d("DATA", data.toString());
selected_Path = getPath(data);
final_path.getBytes();
selected_path_text.setText(final_path);
Log.d("Video Path", final_path);
}
}
}
private String getPath(Uri data) {
String[] projection = { MediaStore.Images.Media.DATA };
Cursor cursor = managedQuery(data, projection, null, null, null);
column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
cursor.moveToFirst();
final_path = cursor.getString(column_index);
Log.d("Image Path", final_path);
return cursor.getString(column_index);
}
Try this:
Intent i = new Intent(Intent.android.provider.MediaStore.{File type for getting path }.Media.EXTERNAL_CONTENT_URI);
startActivityForResult(i, RESULT_CODE);
if (requestCode == RESULT_CODE && resultCode == RESULT_OK && null != data) {
Uri selectedImage = data.getData();
String[] filePathColumn = {MediaStore.{FILETYPE }.Media.DATA};
Cursor cursor = getContentResolver().query(selectedImage, filePathColumn, null, null, null);
cursor.moveToFirst();
int columnIndex = cursor.getColumnIndex(filePathColumn[0]);
path = cursor.getString(columnIndex);
cursor.close();
}
We can do by usin ContentProviders also:
private Cursor mCursor;
if (audio) {
mUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
mCursor = mContentResolver.query(mUri, null, null, null, null);
if (mCursor != null && mCursor.moveToFirst()) {
do {
mFileName = mCursor
.getString(mCursor
.getColumnIndex(MediaStore.Audio.Media.DISPLAY_NAME));
mFilePath = mCursor
.getString(mCursor
.getColumnIndex(MediaStore.Audio.Media.DATA));
} while (mCursor.moveToNext());
}
}
if (video) {
mUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
mCursor = mContentResolver.query(mUri, null, null, null, null);
if (mCursor != null && mCursor.moveToFirst()) {
do {
mFileName = mCursor
.getString(mCursor
.getColumnIndex(MediaStore.Video.Media.DISPLAY_NAME));
mFilePath = mCursor
.getString(mCursor
.getColumnIndex(MediaStore.Video.Media.DATA));
} while (mCursor.moveToNext());
}
}
if (image) {
mUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
mCursor = mContentResolver.query(mUri, null, null, null, null);
if (mCursor != null && mCursor.moveToFirst()) {
do {
mFileName = mCursor
.getString(mCursor
.getColumnIndex(MediaStore.Images.Media.DISPLAY_NAME));
mFilePath = mCursor
.getString(mCursor
.getColumnIndex(MediaStore.Images.Media.DATA));
} while (mCursor.moveToNext());
}
}
mCursor.close();
Android 5.1.1 lollipop return null file path if image chosen from gallery. The below code works fine in all the devices below 5.1.1, but doesn't work in lollipop 5.1.1
Uri contentUri = data.getData();
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();
}
}
cursor.getString(column_index) this returns null.
For now I have ended up with this for getting an image from gallery. I've tested it on 4.4, 5.0.1 and 5.1.1 but it should work on previous versions too (with new and old Google photo app), should be less hacky and doesn't require a check on Android version.
public static Uri handleImageUri(Uri uri) {
if (uri.getPath().contains("content")) {
Pattern pattern = Pattern.compile("(content://media/.*\\d)");
Matcher matcher = pattern.matcher(uri.getPath());
if (matcher.find())
return Uri.parse(matcher.group(1));
else
throw new IllegalArgumentException("Cannot handle this URI");
}
return uri;
}
And with this I used the same code I have ever used before for getting the image path:
public static String getRealPathFromURI(Context context, Uri uri) {
Cursor cursor = null;
try {
Uri newUri = handleImageUri(uri);
String[] proj = { MediaStore.Images.Media.DATA };
cursor = context.getContentResolver().query(newUri, proj, null, null, null);
int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
cursor.moveToFirst();
return cursor.getString(column_index);
} catch (Exception e){
return null;
} finally {
if (cursor != null) {
cursor.close();
}
}
}
For a temporary hack-around for android lollipop 5.1.1. It Works fine now. But m not satisfied with this unofficial hack.
Uri selectedImage = data.getData();
if (Build.VERSION.SDK_INT == 22) {
if (selectedImage != null && selectedImage.toString().length() > 0) {
try {
final String extractUriFrom = selectedImage.toString();
String firstExtraction = extractUriFrom.contains("com.google.android.apps.photos.contentprovider") ? extractUriFrom.split("/1/")[1] : extractUriFrom;
firstExtraction = firstExtraction.contains("/ACTUAL") ? firstExtraction.replace("/ACTUAL", "").toString() : firstExtraction;
String secondExtraction = URLDecoder.decode(firstExtraction, "UTF-8");
selectedImage = Uri.parse(secondExtraction);
} catch (UnsupportedEncodingException e) {
} catch (Exception e) {
}
}
}