I'm using ACTION_GET_CONTENT so that the user can select text files that the rest of my code can read and deal with.
Intent intent = new Intent();
intent.setAction(Intent.ACTION_GET_CONTENT);
intent.setType("text/*");
startActivityForResult(Intent.createChooser(intent, "select data"), SELECT_DATA);
Above is my code so that the user can browse which works fine.
Uri DataUri = data.getData();
File FileUri = new File(DataUri.getPath());
If I convert DataUri or FileUri to a string after using getPath or getAbsolutePath, I get a completely wrong path.
The path should be /storage/emulated/0/Documents/myFile but it gives me /document/primary:Documents/myFile. I have no idea what this "primary:Documents" thing is.
The data from the intent itself already has the wrong path, any suggestions?
I'm using ACTION_GET_CONTENT so that the user can select text files
No, you are using ACTION_GET_CONTENT so that the user can select some content that has a MIME type of text/*. Where that content comes from is largely up to the user. It may or may not be a file on the filesystem, and if it is, is may or may not be a file that you could access yourself directly (e.g., internal storage of the Dropbox app, files on removable storage on Android 4.4+ devices).
The path should be /storage/emulated/0/Documents/myFile
No, it should not.
but it gives me /document/primary:Documents/myFile
What you get will vary by whatever activity handles the ACTION_GET_CONTENT request. What that activity is will depend on what the user has installed that supports ACTION_GET_CONTENT and what the user chooses out of that list of installed stuff.
Usually, you will get a content Uri (i.e., getScheme() on Uri will return content), as the Uri will point to data being served by a ContentProvider.
The data from the intent itself already has the wrong path
It has the correct path. It is simply not a path on the filesystem.
any suggestions?
Use a ContentResolver and openInputStream() to get an InputStream for the content represented by the content Uri.
Related
I'm trying to upload a file by copying it from mobile app to server app running on windows.
I used a file chooser to let the user select the file:
public void openFile(View view) {
Intent intent = new Intent();
intent.setType("*/*");
intent.setAction(Intent.ACTION_GET_CONTENT);
startActivityForResult(Intent.createChooser(intent, "Select file"), LEARN_TREE);
}
Then i got the uri from the intent of onActivityResult.
First question here is why it displays a file named "servo.dat" as numbers (in this case it shows "5889")?
After that I put the uri as an extra into another intent and use that intent to start another activity.
In the second activity I retrieve the uri.
Now I'd like to use FileInputStream to read bytes from my file in order to write them to the ObjectOutputStream created from Socket.getOutputStream().
Here is where it doesn't work. Basically the path provided here
FileInputStream fis = new FileInputStream(uri.getPath());
is incorrect. If I check on my device the file location is Download/servo.dat, the Uri in the app shows Download/5889 and the absolute path that I tried retrieving using a UriUtils library found online shows storage/emulated/0/Download/servo.dat but this one doesn't actually exist on my phone.
I think it's not so hard but I'm getting confused since I'm new to both Android app development and Android itself, please help!
I'm open to any good solution, I saw online there is the ContentResolver class that should be helpful but I didn't manage to understand how to use it :|
First question here is why it displays a file named "servo.dat" as numbers (in this case it shows "5889")?
Because it is not a file. It is a piece of content, and you are attempting to treat the path portion of a Uri as a filesystem path, which is is not.
If you want a display name for the content:
Call DocumentFile.fromSingleUri(), passing in your Uri, to create a DocumentFile
Call getDisplayName on the DocumentFile
Basically the path provided here is incorrect
That is because you are trying to treat the path portion of a Uri as a filesystem path, which it is not.
To get an InputStream, call openInputStream() on a ContentResolver, passing in your Uri. See the documentation. So, for example, from a method in an Activity, you would use InputStream inputStream = getContentResolver().openInputStream(uri);.
I'm getting confused since I'm new to both Android app development and Android itself
You may wish to consider reading a book on Android app development or taking a course in Android app development.
I'm trying to load documents from files in my app using Microsoft Word and PDF viewers and I'm using a FileProvider to handle Android 7.0+ not allowing file URIs to be passed freely. I get the URI like so and and set the Intent flags to allow reading and writing before opening it, like so:
// From the byte array create a file containing that data, and get extension and MIME type.
File fileToOpen = byteArrayToFile(documentData, shortFileName);
String fileExtension = UtilityMethods.getFileExtension(fileToOpen.getName());
String mime = MimeTypeMap.getSingleton().getMimeTypeFromExtension(fileExtension);
// Get the Uri for the file from the file provider, open using intent.
Uri documentUri = FileProvider.getUriForFile(getContext(), "com.mycompany.provider", fileToOpen);
Intent intent = new Intent();
intent.setDataAndType(documentUri, mime);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
intent.setAction(Intent.ACTION_VIEW);
startActivity(intent);
However when the file loads in MS Word the file is read only, and cannot be edited, which is not the desired behaviour. Where am I going wrong?
In Android, one can use the ACTION_OPEN_DOCUMENT Intent to open the native file picker and select for example an .mp4 file. This is achived by setting the mime type to video/mp4 using the following code:
public static void pickFile(Context mContext, int REQUEST_CODE) {
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
intent.addCategory(Intent.CATEGORY_OPENABLE);
intent.setType("video/mp4");
((Activity) mContext).startActivityForResult(intent, REQUEST_CODE);
}
In my project, I want to pick a custom extension file whose mime type is not known in android's MimeTypeMap like for example .qgs or .dcm files.
To solve this I see two possibilities that we, so far, failed to implement:
filter by extension in the ACTION_OPEN_DOCUMENT Intent
register a new mime type to android so that it can be used with the ACTION_OPEN_DOCUMENT Intent
is either of those options doable and how?
or are there other approaches I missed without coding my own file picker?
You can try creating a custom file picker and pass the mount storage points and recursively iterate on all the file types:
public void scanFiles(File file) {
File[] fileArray = file.listFiles();
for (File f : fileArray){
if (f.isDirectory())
scanFiles(f);
if (f.isFile() && (f.getpath().endswith("..qgs") || //any extensions)) {
//Add to your list
}
}
}
And call scan files for all the mount points in android using a process builder and mount command and you can add checks for all the mount points you wish to support.
one can use the ACTION_OPEN_DOCUMENT Intent to open the native file picker
That is not a "file picker". There is no requirement that every DocumentsProvider on the device be serving documents that happen to be files.
I want to pick a custom extension file whose mime type is not known in android's MimeTypeMap like for example .qgs or .dcm files
There is no requirement that every DocumentsProvider on the device be using documents that have filenames for their files. The names that you see are "display names", and while for some providers they will be filenames, for other providers they can be anything that the provider wants.
is either of those options doable
No.
or are there other approaches I missed without coding my own file picker?
If you only want files, there are plenty of existing file picker implementations available in libraries. ACTION_OPEN_DOCUMENT is there for when you want to work with all possible document sources (removable storage, cloud providers, etc.), not just files.
I'm having trouble getting file paths from uri returned by other activities.
I found many solutions on how to convert Uri to absolute file path like this one but its always dependent on type of content such as audio in the given link.
My app provides an activity to send files of any type.. that said I set the intent filter to
mimetype */*
but when I go in file browser and select a image file from from the camera photo folder I get path like /external/images/media/288 but If I pick a music file I get Uri like external/audio/media/1336
but on the other hand if I choose a non media file type (ex.pdf or zip) then I get the absoute path already in the Uri
So as you can see Its not known what path will Uri have it depends on what file i pick for sending with my app.
one possible solution is to make cursor queries for all types of media e.g audio video and image and if they return null then check for Uri.getPath() but I think thats a very bad practice or inefficient way !
Is there any way to get absolute Path from any Uri (given the file exists) without checking for each type of uri?
I'm having trouble getting file paths from uri returned by other activities.
There does not have to be a "file path" associated with a Uri. A Uri points to a source of data, which may or may not be a file, let alone a file which you can access directly.
You can obtain an InputStream on the data associated with a Uri via a call to openInputStream() on a ContentResolver.
Is there any way to get absolute Path from any Uri
Not in any sort of a reliable fashion. Please use the Uri in the way it was intended.
I have a camera intent set up to try to create a file in the root of my device.
File storagePath = new File(Environment.getExternalStorageDirectory()+ "/Football_Fans");
storagePath.mkdirs();
File file = new File(storagePath, "FAN_IMAGE_TEMP");
Intent cameraIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, storagePath);
startActivityForResult(cameraIntent,CAMERA_REQUEST_IMAGE);
When I run my application, I don't have any activityOnResult set, but I use fileExplorer to try to see if my file was created. My folder gets created fine, but the photo does not show up. Any idea why?
The documentation states that if an EXTRA_OUTPUT is set, it will write to that location. So I'm confused why it's not working.
The caller may pass an extra EXTRA_OUTPUT to control where this image
will be written. If the EXTRA_OUTPUT is not present, then a small
sized image is returned as a Bitmap object in the extra field. This is
useful for applications that only need a small image. If the
EXTRA_OUTPUT is present, then the full-sized image will be written to
the Uri value of EXTRA_OUTPUT.
use Uri. try this
cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(storagePath));
"..will be written to the Uri value of EXTRA_OUTPUT."
You are passing in a File object (storagePath). It expects a Uri so use this:
cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(storagePath));