How to return workable filepath? - java

I have an activity that when users press "share" on a file it would open my app and start uploading the file. Now this works perfectly with images because the URI returned is for MediaStore. But I want to be able to return the URI from any source such as from ES File Explorer
Here is the current code:
public String getPath(Uri uri) {
String[] projection = { MediaStore.Images.Media.DATA };
Cursor cursor = managedQuery(uri, projection, null, null, null);
int column_index = cursor
.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
cursor.moveToFirst();
return cursor.getString(column_index);
}
How can I make this so instead of MediaStore it will be used for any type of file?

I'd recommend skipping the path step (if possible) and going straight to getting an InputStream which can simplify things a bit:
public InputStream getInputStream(Uri uri) {
InputStream stream = null;
String scheme = uri.getScheme();
try {
if (ContentResolver.SCHEME_CONTENT.equals(scheme) || ContentResolver.SCHEME_FILE.equals(scheme) || ContentResolver.SCHEME_ANDROID_RESOURCE.equals(scheme)) {
stream = getContentResolver().openInputStream(uri);
} else if ("https".equals(scheme) || "http".equals(scheme)) {
// ContentResolver can't handle web uris. Handle or skip them as you see fit.
}
} catch (FileNotFoundException e) {
// Handle the exception however you see fit.
}
return stream;
}
I'd favor using the ContentResolver and letting it sort out the specifics... For example, what happens if you get a content uri that isn't related to the MediaStore? By letting the ContentResolver handle that, you don't have to care.

You can't do that. You can use it for the media store, beacuse the path of those images are stored in the built in SQLite database, but the files on your sd card has no entries in the database.
You can check if the URI's scheme is content or file, and use different methods to access the file the following way:
public String getPath(Uri uri) {
if(uri.getScheme().equals("content")){
String[] projection = { MediaStore.Images.Media.DATA };
Cursor cursor = managedQuery(uri, projection, null, null, null);
int column_index = cursor.getColumnIndexOrThrow(
MediaStore.Images.Media.DATA);
cursor.moveToFirst();
return cursor.getString(column_index);
} else if(uri.getScheme().equals("file")){
File myFile = new File(uri);
return myFile.getAbsolutePath();
}
}

Related

Having issue with file path

I am successfully able to select file programmatically. But, when I am getting uri from that file
content://com.android.providers.downloads.documents/document/3356
content://com.android.providers.downloads.documents/document/3331
Unfortunately, wherever the file is my uri is always locating at downloads.documents
I think it doesn't fact. Cause, everyone get the uri by data.getData(). So, I think the uri is correct.
Last year, I was working with Audio, Video, File and Image uploading to server. I was trying that source code to get path.
String mediaPath, mediaPath1;
String[] mediaColumns = {MediaStore.Video.Media._ID};
// Get the file from data
String path = data.getStringExtra(mediaPath);
File file = new File(path);
Uri selectedFile = Uri.fromFile(new File(file.getAbsolutePath()));
String[] filePathColumn = {MediaStore.Files.FileColumns.MEDIA_TYPE};
Cursor cursor = getContentResolver().query(selectedFile, filePathColumn, null, null, null);
assert cursor != null;
cursor.moveToFirst();
int columnIndex = cursor.getColumnIndex(filePathColumn[0]);
mediaPath = cursor.getString(columnIndex);
txt.setText(path);
// Set the Image in ImageView for Previewing the Media
cursor.close();
Unfortunately,That is returning null pointerexception. After researching little bit, I found another source code(PathUtils)
public class PathUtils {
public static String getPath(final Context context, final Uri uri) {
// DocumentProvider
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT && DocumentsContract.isDocumentUri(context, uri)) {
if (isExternalStorageDocument(uri)) {// ExternalStorageProvider
final String docId = DocumentsContract.getDocumentId(uri);
final String[] split = docId.split(":");
final String type = split[0];
String storageDefinition;
if("primary".equalsIgnoreCase(type)){
return Environment.getExternalStorageDirectory() + "/" + split[1];
} else {
if(Environment.isExternalStorageRemovable()){
storageDefinition = "EXTERNAL_STORAGE";
} else{
storageDefinition = "SECONDARY_STORAGE";
}
return System.getenv(storageDefinition) + "/" + split[1];
}
} else if (isDownloadsDocument(uri)) {// DownloadsProvider
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)) {// MediaProvider
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())) {// MediaStore (and general)
// Return the remote address
if (isGooglePhotosUri(uri))
return uri.getLastPathSegment();
return getDataColumn(context, uri, null, null);
} else if ("file".equalsIgnoreCase(uri.getScheme())) {// File
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());
}
public static boolean isGooglePhotosUri(Uri uri) {
return "com.google.android.apps.photos.content".equals(uri.getAuthority());
}
}
I am not getting any error. But, Path is always locating at Downloads file. I don't know why. After looking at uri I noticed my uri is always returning downloads.documents. I am not sure is it the issue.
There is lot of question similar to this question in stackoverflow. To tell everyone none worked for me. So, I will request to not flag it.
PATH: /storage/emulated/0/Download/The Road to Reality ( PDFDrive ).pdf
PATH: /storage/emulated/0/Download/The order of time ( PDFDrive ).pdf
PATH: /storage/emulated/0/Download/pdf_495.pdf
First pdf file is in documents file. Second pdf file is in Download third pdf file is in /storage/emulated/0/
I am parsing pdf texts. Here is my code
try {
String parsedText="";
StringBuilder builder = new StringBuilder();
//Here you can see I need path to load the pdf file
PdfReader reader = new PdfReader(PathUtils.getPathFromUri(getApplicationContext(),PathHolder));
int n = reader.getNumberOfPages();
for (int i = 10; i <n ; i++) {
parsedText = parsedText+ PdfTextExtractor.getTextFromPage(reader, i).trim()+"\n";
Log.d("for_loop", String.valueOf(i));
Log.d("PARSED_TEXT",parsedText+" ");
}
builder.append(parsedText);
reader.close();
runOnUiThread(() -> {
txt.setText(builder.toString());
});
// System.out.println("TEXT FROM PDF : "+builder.toString());
} catch (Exception e) {
System.out.println(e);
}
As you can see I need path to load the pdf file. But, I have already told you I am having issue with path. So, if I wanna do something with uri than how can i do that cause, path required.
I tried another way to get the path also.
Uri PathHolder = data.getData();
Cursor cursor = null;
try {
cursor = this.getContentResolver().query(PathHolder, new String[]{MediaStore.Files.FileColumns.DATA}, null, null, null);
if (cursor != null && cursor.moveToFirst()) {
String fileName = cursor.getString(0);
String path = Environment.getExternalStorageDirectory().toString()+"/" + fileName;
Log.d("PATH",path);
if (!TextUtils.isEmpty(path)) {
}else{
Toast.makeText(this, "null return", Toast.LENGTH_SHORT).show();
}
}
}catch (Exception e){
e.printStackTrace();
Log.d("EXCEPTION_ERROR",e.toString());
} finally {
if (cursor != null)
cursor.close();
}
Unfortunately, It's not working also.
Like we do for audio, images or, videos.
Uri selectedImage = data.getData();
String[] filePathColumn = {MediaStore.Audio.Media.DATA};
Cursor cursor = getContentResolver().query(selectedImage, filePathColumn, null, null, null);
assert cursor != null;
cursor.moveToFirst();
int columnIndex = cursor.getColumnIndex(filePathColumn[0]);
mediaPath = cursor.getString(columnIndex);
str1.setText(mediaPath);
// Set the Image in ImageView for Previewing the Media
imgView.setImageBitmap(BitmapFactory.decodeFile(mediaPath));
cursor.close();
Edited :
Uri uri = data.getData();
try{
InputStream in = getContentResolver().openInputStream(uri);
BufferedReader r = new BufferedReader(new InputStreamReader(in));
StringBuilder total = new StringBuilder();
for (String line; (line = r.readLine()) != null; ) {
total.append(line).append('\n');
}
String content = total.toString();
Log.d("CONTENT",content);
}catch (Exception e){
e.printStackTrace();
}
The problem I am facing here is.
As you can see the catch is returning no such file or directory found. I am not sure what I am doing wrong here. Cause, I took the source code from somewhere else and it is first time I am working with InputStream. And, I think the problem is on I am unable to get the file by uri.
Catch exception is returning
no such file or directory
Edited :
Uri uri = data.getData();
File file=new File(uri.toString());
InputStream inputStream = getContentResolver().openInputStream(uri);
OutputStream out = new FileOutputStream(file);
byte[] buf = new byte[1024];
int len;
while((len=inputStream.read(buf))>0){
out.write(buf,0,len);
}
out.close();
inputStream.close();
Starting from Android 10 using Scoped Storage is required. You cannot get absolute path of the file and work with file APIs with external Storage. MediaStore.Audio.Media.DATA that is used to take absolute path is depracated. But with uri returned you can copy that file using inputStream to your app-specific directory and do what you want with that file. For more information please refer to this article.
For reading pdf as I said you can copy that file to your app-specific directory or use that uri like this sample.
Copying file from uri in kotlin:
val uri: Uri = data?.data ?: return
val ins = context?.contentResolver?.openInputStream(uri)
val file = File(context?.filesDir, "image.jpg")
val fileOutputStream = FileOutputStream(file)
ins?.copyTo(fileOutputStream)
ins?.close()
fileOutputStream.close()
val absolutePath = file.absolutePath
Log.d("AAA", absolutePath)
If you use java there is no copyTo function so use this function then you can use the file in Files directory in app-specific storage
private void copyInputStreamToFile( InputStream in, File file ) {
try {
OutputStream out = new FileOutputStream(file);
byte[] buf = new byte[1024];
int len;
while((len=in.read(buf))>0){
out.write(buf,0,len);
}
out.close();
in.close();
} catch (Exception e) {
e.printStackTrace();
}}
Copied file in app-specific directory
This is log:
D/AAA: /data/user/0/com.example.pickerapp/files/image.jpg

Get cover of the songs in mediastore

I'm trying to get a Cover (album art) of the song using the following code:
public static String getCoverArtPath(Context context, long androidAlbumId) {
String path = null;
Cursor c = context.getContentResolver().query(
MediaStore.Audio.Albums.EXTERNAL_CONTENT_URI,
new String[]{MediaStore.Audio.Albums.ALBUM_ART},
MediaStore.Audio.Albums._ID + "=?",
new String[]{Long.toString(androidAlbumId)},
null);
if (c != null) {
if (c.moveToFirst()) {
path = c.getString(0);
}
c.close();
}
return path;
}
This method returns a string of an image path but this path points to a non-formatted file.
How to set this image on the ImageView?
If you know of any other way than this method please tell me.
You can create a drawable from the path and set it
Drawable drawable = Drawable.createFromPath(path_of_the_cover_art);
yourImageView.setImageDrawable(drawable);
Or create a file:
File image = new File(path_of_the_cover_art);
if(image.exists()){
Bitmap bitmap = BitmapFactory.decodeFile(image.getAbsolutePath());
yourImageView.setImageBitmap(bitmap);
}
just make sure you have the WRITE_STORAGE_PERMISSION for that!

Get Contact Name through contact number not work in Android 9.0 Pie

I want to get the name for incoming call number from contact list through the following method. it work on all android version but it give null in android 9.0 pie.
private String getContactName(String number, Context context) {
String contactName = "";
String[] projection = new String[] {
ContactsContract.PhoneLookup.DISPLAY_NAME,
ContactsContract.PhoneLookup.NUMBER,
ContactsContract.PhoneLookup.HAS_PHONE_NUMBER };
Uri contactUri = Uri.withAppendedPath(
ContactsContract.PhoneLookup.CONTENT_FILTER_URI,
Uri.encode(number));
Cursor cursor = context.getContentResolver().query(contactUri,
projection, null, null, null);
if(cursor != null) {
if (cursor.moveToFirst()) {
contactName = cursor.getString(cursor
.getColumnIndex(ContactsContract.PhoneLookup.DISPLAY_NAME));
}
cursor.close();
}
return contactName.equals("") ? number : contactName;
}
i also try a new method but it also not working and give me null value. i get this code from google developer documentation. whats wrong with my code or please help me on which method i can get contact name for a number.
public String onCreateIncomingConnection (String s) {
// Get the telephone number from the incoming request URI.
String phoneNumber = s;
String displayName = "Unknown caller";
boolean isCallerInWorkProfile = false;
// Look up contact details for the caller in the personal and work profiles.
Uri lookupUri = Uri.withAppendedPath(
ContactsContract.PhoneLookup.ENTERPRISE_CONTENT_FILTER_URI,
Uri.encode(phoneNumber));
Cursor cursor = getContentResolver().query(
lookupUri,
new String[]{
ContactsContract.PhoneLookup._ID,
ContactsContract.PhoneLookup.DISPLAY_NAME,
ContactsContract.PhoneLookup.CUSTOM_RINGTONE
},
null,
null,
null);
// Use the first contact found and check if they're from the work profile.
if (cursor != null) {
try {
if (cursor.moveToFirst() == true) {
displayName = cursor.getString(1);
isCallerInWorkProfile =
ContactsContract.Contacts.isEnterpriseContactId(cursor.getLong(0));
}
} finally {
cursor.close();
}
}
// Return a configured connection object for the incoming call.
// MyConnection connection = new MyConnection();
// connection.setCallerDisplayName(displayName, TelecomManager.PRESENTATION_ALLOWED);
//
// Our app's activity uses this value to decide whether to show a work badge.
// connection.setIsCallerInWorkProfile(isCallerInWorkProfile);
// Configure the connection further ...
return displayName;
}

Extracting Filenames from SAF content URIs

Hello my fellow stackoverflows,
I am writing an application where I implemented an Activity that handles share-intents.
So far it works fine but during testing I have got a problem with Quickoffice (Android 4.4, KitKat),
because it returns an URI from which I can´t get the filename from. I also tried sharing with other apps like Dropbox and it works there.
The exact URI I get from the Qickoffice app:
content://com.quickoffice.android.quickcommon.FileContentProvider/5cmeDeeatcdv8IFyu-bEr2w1jSHrvPmCzXGb_VvZulMBErE5Tmfd_5P5kckE68LaEYDVSp3q5r19%0A4sOkpYCEM_VqK6Y%3D%0A
This was the code I used first:
public String getRealPathFromURI(Uri contentUri) {
Cursor cursor = null;
try {
String[] proj = {MediaStore.Images.Media.DATA}; // = "_data"
ContentResolver cr = getContentResolver();
cursor = cr.query(contentUri, proj, null, null, null); // <--EXCEPTION
int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
cursor.moveToFirst();
return cursor.getString(column_index);
} catch (Exception exception) {
Log.d("clixend", "Exception: " + exception);
Toast.makeText(this, "Exception: " + exception, Toast.LENGTH_LONG).show();
} finally {
if (cursor != null) {
cursor.close();
}
}
return null;
}
Where I received following error:
09-23 16:54:17.664 32331-32341/? E/DatabaseUtils﹕ Writing exception to parcel
java.lang.UnsupportedOperationException: Unsupported column: _data
at com.google.android.apps.docs.quickoffice.FileContentProvider.query(FileContentProvider.java:78)
at android.content.ContentProvider.query(ContentProvider.java:857)
at android.content.ContentProvider$Transport.query(ContentProvider.java:200)
at android.content.ContentProviderNative.onTransact(ContentProviderNative.java:112)
at android.os.Binder.execTransact(Binder.java:404)
at dalvik.system.NativeStart.run(Native Method)
After some research I figured out that Android 4.4 Kitkat introduces SAF (Storage Access Framework) which manages data different, so I tried the following Code from https://developer.android.com/guide/topics/providers/document-provider.html to get the name:
public String getNameKitkat(Uri contentUri) {
Cursor cursor = getContentResolver()
.query(contentUri, null, null, null, null, null); // <--EXCEPTION
try {
if (cursor != null && cursor.moveToFirst()) {
String displayName = cursor.getString(
cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME));
return displayName;
}
} finally {
cursor.close();
}
return null;
}
But I also receive an error code:
09-23 16:49:43.317 32331-32421/? E/DatabaseUtils﹕ Writing exception to parcel
java.lang.IllegalArgumentException: columnNames.length = 4, columnValues.size() = 2
at android.database.MatrixCursor.addRow(MatrixCursor.java:157)
at android.database.MatrixCursor.addRow(MatrixCursor.java:128)
at com.google.android.apps.docs.quickoffice.FileContentProvider.query(FileContentProvider.java:95)
at android.content.ContentProvider.query(ContentProvider.java:857)
at android.content.ContentProvider$Transport.query(ContentProvider.java:200)
at android.content.ContentProviderNative.onTransact(ContentProviderNative.java:112)
at android.os.Binder.execTransact(Binder.java:404)
at dalvik.system.NativeStart.run(Native Method)
If somebody knows how to get the name out of the URI I get from Quickoffice I would be very thankful.
After I searched some more I found the answer to my question how to get the filename from the URI I get from Quickoffice.
public String getNameFromURI(Uri contenturi){
String[] proj = {
OpenableColumns.DISPLAY_NAME,
OpenableColumns.SIZE
};
String name = null;
int size= 0;
Cursor metadataCursor = getContentResolver().query(contenturi, proj, null, null, null);
if (metadataCursor != null) {
try {
if (metadataCursor.moveToFirst()) {
name = metadataCursor.getString(0);
size = metadataCursor.getInt(1);
}
} finally {
metadataCursor.close();
}
}
return name;
}
The problem was I didn´t use the proper Typ, I wanted to receive.
After using:
String[] proj = {
OpenableColumns.DISPLAY_NAME,
OpenableColumns.SIZE
};
it worked perfectly fine.
Sorry for your waste of time.

android - ContentProvider: problem setting filename for files delivered by using ContentProvider.openFile

I'm facing the following problem while implementing a ContentProvider to deliver images stored in the private data area of an application in an android-project:
The files returned by the implementation below have the complete absolute path to the stored images as filename which look like
_data_data_com.mypackage.imageprovider_app_images_123456789.jpg
where app_images is the name of the directory the images are stored in by the application and 123456789.jpg is the actual filename.
My question now is: How can I make the ContentProvider set only the actual filename (or alternatively a filename I specify) for the delivered images?
It should be possible, since e.g. the built-in providers in android manage to deliver only the actual filename for an image.
The database table has columns for _id, filename and _data, where _data holds the absolute path to the image in the filesystem.
Any hints are very highly appreciated :)
Thanks in advance, snowcrash123
Here are the relevant parts of my current ContentProvider:
#Override
public Cursor query(Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder)
{
final SQLiteQueryBuilder queryBuilder = new SQLiteQueryBuilder();
queryBuilder.setTables(PhotosTable.TABLE_NAME);
switch (URI_MATCHER.match(uri))
{
case PHOTO_DIR:
if (sortOrder == null)
{
sortOrder = PhotosDirectory.DEFAULT_SORT_ORDER;
}
break;
case PHOTO_ID:
queryBuilder.appendWhere(IPhotoColumns.FILENAME + "="
+ uri.getPathSegments().get(1) + " AND ");
break;
default:
throw new IllegalArgumentException("Unknown URI " + uri);
}
if (!mDb.isOpen())
{
assignWritableDb();
}
return queryBuilder.query(mDb, PhotosDirectory.ALL_COLUMNS,
selection, selectionArgs, null, null, sortOrder);
}
#Override
public ParcelFileDescriptor openFile(Uri uri, String mode)
{
if (URI_MATCHER.match(uri) != PHOTO_ID)
{
throw new IllegalArgumentException(
"operation only permitted for single file");
}
try
{
return openFileHelper(uri, mode);
}
catch (FileNotFoundException e)
{
return null;
}
}

Categories

Resources