We have some old issues with similar words, but most of them are about converting one or the other.
What I'm looking here is the "Right" behaviour of URI usage with the new changes. Let me give some context:
Before when we get an image URI this would return file://... format.
But since the new OS permissions changes, where we should not use WRITE_EXTERNAL_STORAGE anymore we should use getUriForFile(..) that return content://... path.(Scope Storage usage Android 11 Storage FAQ)
This can be spot on some Android guides, like: taken photos guide
The "problem" is that many users got used to use the URI of a crop image (for example) to create a file of it and save it.
Now, with this changes come the question:
How should we use the URI?
Make some code to check Android version and if more than 29 we should create a new file path for the URI?
Let the URI be the path to the image (content of file) and if someone wanna save it would need to create it own file path
Something else that I don't get yet about how to use URI right.
Obs: Asking this, because of a Android Image Crop open source project handover, where we need to upgrade the permissions for Android 10/11 but now we have this content/file issue. More here
Edit:
As pointed on the comments
Code returning file:// (not valid anymore since the changes)
Uri outputFileUri = null;
outputFileUri = Uri.fromFile(
new File(context.getExternalCacheDir().getPath(),
"pickImageResult.jpeg")
);
Code returning content://
outputFileUri = FileProvider.getUriForFile(
context,
context.getPackageName() + CommonValues.authority,
File.createTempFile("pickImageResult", ".jpeg", getImage)
);
The "problem" is that many users got used to use the URI of a crop image (for example) to create a file of it and save it.
In the end, this is your library, and you need to document what any Uri that you return is suitable for. After all, a Uri could point to:
A file on the filesystem (file)
A Web resource (https, or possibly http)
An Android resource (android.resource)
An asset in the app (file://android_asset)
Some arbitrary set of bytes (content)
Your library is for image cropping. While I have not examined the implementation, I assume that it all works inside the app itself. If so, there is nothing wrong with returning a file Uri, if you want to do so. Your code is writing a file somewhere (e.g., getCacheDir() on Context). The app using your library must have access to that file, or else you would have crashed trying to write it. A Uri created via Uri.fromFile(), for that file, is perfectly fine... in that app.
Where Uri.fromFile() becomes a problem is in passing the Uri to another app. However, your library is for cropping images, not sharing content with other apps. Your job, IMHO, is to give a cropped image back to the app. What the app does with it is up to that app, subject to whatever limitations there are in the Uri that you hand over.
The two options that you seem to be considering have different issues:
Uri Source
Advantages
Disadvantages
Uri.fromFile()
Cheap, easy
Can only be used within the app itself; cannot be passed to other apps
FileProvider
Uri can be passed to other apps
Requires a library and manifest configuration; cannot readily get to the underlying file
Since IMHO an image cropper is not an image sharing solution, Uri.fromFile() seems reasonable. If the app using your library wants to turn around and share the cropped image, they would set up FileProvider themselves and use FileProvider.getUriForFile(). The only catch is that either you need to document where the file will be written or give them an option to tell you what directory to use — that information will be needed to set up the FileProvider metadata.
Someday, if you elect to change the API, you might consider returning an ordinary File instead of a Uri. That way, there is no confusion about what it represents.
But, in the end, this is all your decision. If you want to use FileProvider, or you want to upload images to your own Web server and use https, that is all up to you. However, you should document what you are doing and what the Uri represents.
Related
I am working on an offline app where I want to open and make changes to an offline document.
I am able to open the file from the android uri path i.e. /data/user/0/com.nativetemplate/files/files/default/documents/3377699720528075#1634821435640
but my requirement is to get the content:// uri path so I can save the changes made on the file.
eg: content://com.google.android.apps.docs.storage/document/acc%3D1%3Bdoc%3Dencoded%3D3ANW16SOSAt4EvkKHsYo_159-fKCSyFbzE4zHcCNeew3N7oDXd0jgvbNFDM%3D
how do I get the content uri?
My requirement can also work if the file is converted into base64. But as I have android uri path I think I would need an API to read the file from the uri.
please provide me with any suggestions you may have.
Thanks
I am trying to following post.
Here is the code
But it is not working for me.
It crashes when I get the image from camera.
The error is from cursor.getString(index) in getDataColum function.
Can you help me?
Thank you.
I think you should be use FileProvider. Basically, from android docs:
FileProvider is a special subclass of ContentProvider that facilitates secure sharing of files associated with an app by creating a content:// Uri for a file instead of a file:/// Uri.
It is a new way to share content. In case of get URI, it works similar. You can use the following example: https://developer.android.com/training/camera/photobasics
I am currently allowing my user to pick an image from the gallery and I load it in an ImageView. Then I store in my sharedPreferences the URI of the image in order to be able to load it again later.
It won't work, and I've noticed that somehow the URI of the picture changed.
I was wondering how to simply store the Image I got from the gallery to be able to reload it later.
Then I store in my sharedPreferences the URI of the image in order to be able to load it again later.
That is not going to work. Not only might the Uri differ, but if the Uri has a content scheme, you lose the rights to work with the content identified by the Uri after your process ends. Plus, the user might get rid of the image.
I was wondering how to simply store the Image I got from the gallery to be able to reload it later.
Use Java I/O to make a copy of the image to a file that you control (e.g., on internal storage), then use that copy. Adjust your UI to reflect this (e.g., use verbs like "import" instead of "link").
Depending on how you got that Uri, you might be able to call takePersistableUriPermission() to try to get long-term rights to the content, in which case the Uri also should be stable (assuming that the user does not move or delete the content in question).
Better to store image path in shared preferences, then reload it again
I'm trying to get the local path of a image in order to upload it to a server. When using pre ICS it would get a standard path within the android device via getRealPathFromURI(theURI)
However with ICS URI will contain a uriString as something like : content://com.google.android.gallery3d.provider/picasa/item/12312312312312.
and running getRealPathFromURI(theURI) returns null
Do I now need to extract the above uriString and manually download the image via the API (if i detect that its a Picasa gallery image) rather than one locally stored? or am I completely missing something?
thanks for any advice
EDIT:
seems i was searching on the wrong question...
found the problem in the below link... which is pretty much what I expected I'd need to do. Pretty annoying google/android didn't handle this more elegantly.
To properly handle fetching an image from the Gallery you need to handle three scenarios:
The user selected a local image file
The user selected a Picasa image and the device is running Android version prior to 3.0
The user selected a Picasa image and
the device is running Android version 3.0 and higher
http://dimitar.me/how-to-get-picasa-images-using-the-image-picker-on-android-devices-running-any-os-version/
That's what I found out on device running Android 4.0+.
The ICS URI you gave as an example is an URI with content:// scheme, so there should be a ContentProvider responsible for that.
Hence, what is the use of that tricks getRealPathFromURI() uses? Just let ContentResolver do this work for you:
InputStream inStream = getContentResolver().openInputStream(theUri);
Bitmap bitmap = BitmapFactory.decodeStream(is);
I have between one and three photos I'd like my app to display. I won't know until runtime exactly how many photos are downloaded from the Internet.
I can't figure out how to create an Intent to display the photos. Right now I'm caching them on the sdcard under a folder I create by doing something like (sans error checking):
final File externalDirectory = Environment.getExternalStorageDirectory();
final String folder = externalDirectory.getAbsolutePath() + "/Android/data/" + packageName + "/files/";
This was explained in the Android Developer Reference.
I can get one photo to display by doing the following:
final Uri uri = Uri.fromFile(file);
final Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(uri, "image/*");
Util.startActivity(this, intent);
Where file is the file of a saved photo.
If it helps, I could save the images to any location available to my app, however I would prefer to not have the photos show up listed with the user's other personal photos as that may be annoying.
The Image Viewer has a menu option "Slideshow", so it must know about multiple photos.
I could create my own Image Viewer, but that seems like extra work and beyond what I would I reasonably expect. Even if I did this, I would like the user to be able to install a 3rd party Image Viewer and get a better experience with pan, zoom, share, ...
I tried using the directory of the cached photo files to create the Uri, but the Image Viewer shows a black page. If I pass in the file, it shows just that one file and no others.
I know this must be possible because I can see use the Gallery app and show the photos if I manually select the folder. Everytime I research this issue, the comments say it's not possible to show multiple images.
I suspect there's some magic incantation, but what?
I think your goal is out of your control. If the viewer app is designed to handle mutiple images or a directory, you may ask it to show as you want, but you are defined to the viewer's pattern.
I have installed a third-party image viewer called QuickPic. I just tested your code snippet and the system popped up a chooser dialog to let me select the app to show the images in the folder. If I select native gallery, what I see is just an empty folder, while the Quickpic works as I want.
PS: I tell my app the Uri of the folder this way:
intent.setDataAndType(Uri.fromFile(new File("//mnt/sdcard/test/")), MimeTypeMap.getSingleton().getMimeTypeFromExtension("png"));