How to delete photo just taken in android program - android

I have written a program that uses the Intent for the image capture to get a photo using the application in the phone.
Using MediaStore.EXTRA_OUTPUT, I get a URI to the image, which converted to a path results in something like "/external/images/media/NN" where NN is the number of the photo.
Now, in my program, after I read and manipulated the image, I want to delete that image.
How should I do that?
(File image = new File(path); image.delete(); // returns false, so doesn't work)

Thanks for the answer.
I resolved reading this answer, Problems saving a photo to a file
For me it works on Hero, even if in the comment in that code snipped says that Hero behave differently.
Now I get the image in "/sdcard/image.tmp", and I can delete it.
I think this is the best solution, cause I think it's a trouble trying to get the camera app to write in my app directory.
Thanks again.

Is it possible that you've failed to request the WRITE_EXTERNAL_STORAGE permission in your app? This would cause deletions to fail. (The camera would be able to write regardless, since it is a separate app with its own permissions.)
It's also possible (but not likely) that the media folder is only writable by the camera app, in which case you'd want to specify a different desired destination in the EXTRA_OUTPUT extra of the intent which invokes the camera so that the file will be written into your app's directory. In fact, you probably want to do that anyway to avoid cluttering up the global space with private resources, even if you are going to delete them immediately.

Related

Android - overwrite photo in photo library

In my application I want to give users ability to open, edit and save image from Android photo library.
Opening is easy, as well as saving as a new file. The problem is with overwriting images (opened from the photo library).
When saving changes I simply overwrite files, knowing the path of the original file.
If user saves a brand new file (not opened from library, but created in the app), the file is saved in
Android.OS.Environment.DirectoryPictures folder.
(e.g. /storage/emulated/0/Pictures/img_2019921_212552.jpg)
I generate random file name, append to the directory path, save, and the file is there.
Knowing this path I can later update file contents by simply overwriting the file.
If however, I open a file from the photo library (including also these files that I had just created with the app), the path that is visible
to me is a kind of weird (e.g. /document/image:87799). I am able to get file contents using this pseudo-code:
Android.Net.Uri uri = intent.Data;
Stream stream = ContentResolver.OpenInputStream(uri);
Upon saving however, the only thing with regard to the photo location that I have is this strange path (e.g. /document/image:87799)
which of course cannot be used to open write stream to the file.
What I need is:
a way to resolve this strange path into a kind of physical one, which will work with streams (to overwrite file).
Or maybe I'm doing it the wrong way...? Updating image from photo library seems to be a standard task, which may have a dedicated
APIs / good practices ?
After my verification, as suggested by CommonsWare:
The following code can be used to save changed image to photo library.
var uri = Android.Net.Uri.Parse(currentPhotoURL);
using (var stream = contentResolver.OpenOutputStream(uri))
{
await stream.WriteAsync(data, 0, data.Length);
}
What is important, no file system APIs are used here.
Now, as overwriting existing file is solved (knowing the URI of the original image), how can I write a brand new image (byte[] array e.g. with encoded jpeg), without using fileSystem APIs ? (this is what I currently do for 'save as new file' operation). Eventually I will need to have URI to the image (starting with content://) - so as to be able to overwrite that copy, if used decides to overwrite it after a while.

Uri points to deleted file but still displays in app, how?

From inside my app, I take a picture using my camera. This picture is then loaded into an ImageView using its Uri which would look something like this: content://media/external/images/media/12345. I can get the path of this Uri by querying the MediaStore, it looks something like this: /storage/emulated/0/DCIM/Camera/IMG_12345.jpg.
I now manually delete the image from that path above. But when I reopen the app, the image is still there and accessible under the same Uri. If I query the MediaStore again it gives me a CursorIndexOutOfBoundsException. So the file does not exist to the MediaStore
So what's happening here? If I've deleted the file manually, then it should not be available to the app. Where is this file right now? Is there a better way of deleting images such that they are removed from everywhere?
The MediaStore is an index of available files. Like any index, it needs to be updated when there are changes to the filesystem. And, like a search engine, there are two main ways in which that happens:
Somebody tells the MediaStore to scan something and add it to the index
The MediaStore crawls the fileystem
In your case, deleting the file using a file manager may not have updated MediaStore, in part because there is no documentation on how to update the MediaStore when you delete something. The docs are focused on indexing new files, not de-listing deleted ones.
The reason why the Uri appeared to continue to work is because of your image-loading library (Glide, in your case). Glide has an in-memory cache, and it will use images from cache when possible.
You should read about caching: https://en.wikipedia.org/wiki/Web_cache
When downloading a resource (such as an image) for the first time, the browser (or most apps using a built-in http communication component) save that resource in the so-called cache. When it comes to reading the resource again next time, they find it has been cached locally, so they don't need to load it again over the net.
You don't have full control over the behaviour, but you can serve your resource via HTTP using the Cache-control and Proxy headers: https://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html
If you want to remove that resource from the cache, well, you have to clean your browser cache. Usually, this can be done in the system settings or in the settings of your browser.

Android sharing between apps using ContentUri

I wanted to know the best approach to passing information from an app to another app on the same devices in android.
For example:
I open google apps and I share a document with my App A.
Google App generated an intent and sends a content URI. From my
understanding, the content uri contains information about the file
(filename, file size, mimetype) and the ability to extract the
content which is located in the cache of the google app on the
device.
When App A opens, it reads the content URI. Ideally, it
should be able to extract the information from the content uri and
then render the image. What this means is that App A will display the image shared. In this example, google app shares a docement, and App A wants to open and display the document within it's own app.
The confusing part
From searching the web, it seems that some people actually try to
extract the file path from the content URI. This requires that you
have permission to access another app's cache or storage space
within the device. Let's say this is possible. It also makes some
assumptions that it's possible to extract the file path.
After reading some articles:
https://commonsware.com/blog/2016/03/14/psa-file-scheme-ban-n-developer-preview.html
https://commonsware.com/blog/2014/07/04/uri-not-necessarily-file.html
https://commonsware.com/blog/2016/03/15/how-consume-content-uri.html
it seems that, ideally you should never assume that you can extract the file path and that google has made some updates that makes this not possible.
Work around:
Eventhough i'm not able to extract the file path from the
contentUri, I'm able to read the bytes of what the contentUri is
pointing to. So I could save it to a file that is relevant to the
local cache of App A and pass that path along to get render or pass
the bytes back. This refers to App A displaying the content. That is passing the path or bytes and let's make the assumption that it knows how to display it given that information.
Question:
The work around does not seem ideal because technically you are
save the file again on the device. There are two locations with the
same content ( google app storage and App A's storage). You also
have to manage when to delete the App A's file that you created.
This doesn't really seem ideal and was wondering what the best
approach would be? Or is this the expected flow?
Also I don't know
if it's ideal to pass the bytes back up vs. just a file path.
Update
To be more specific, the app i'm creating is a hybrid where i'm using cordova plugin to interact with a web app. The web app has methods to process or display the shared document based on file path. So ideally I want to keep it consistent with just reading the file path so that the other platforms that the web app supports does not break.
Any advice appreciated,
D
Eventhough i'm not able to extract the file path from the contentUri, I'm able to read the bytes of what the contentUri is pointing to.
Correct. This is not significantly different than how you use an HTTPS URL, where you also do not have direct filesystem access to the content (in that case, resident on a different server).
So I could save it to a file that is relevant to the local cache of App A and pass that path along to get render or pass the bytes back.
Or, just consume the bytes. Again, drawing an analogy to an HTTPS URL, there is no requirement to save those bytes to disk to use them.
The work around does not seem ideal because technically you are save the file again on the device. There are two locations with the same content ( google app storage and App A's storage). You also have to manage when to delete the App A's file that you created.
Then do not save the file again on the device, and simply use the stream of bytes. Again, this is not significantly different than using an HTTPS URL.
This doesn't really seem ideal and was wondering what the best approach would be?
Do not write the bytes to disk. Just use them.
So ideally I want to keep it consistent with just reading the file path so that the other platforms that the web app supports does not break.
Your choices are:
Improve the Web app code, such that a local file path is one possible source of the data, or
Suffer the problems with making copies of that data
After all, bear in mind that the Uri you are given via ACTION_SEND does not have to be a content Uri. It could very easily be an http or https Uri.

DocumentFile - direct access to underlying file

Is it somehow possible to get a File object from an DocumentFile? With some small trick I can get the real path of the file, but the File class is not allowed to read/write there...
I need to access media files from USB OTG or secondary storage and I need following functions:
get exif data from images => I really need that for
getting the location of the image
getting the real creation date of the image
actually, for displaying purpose, I need all exif data
ability to rotate images (this would be possible by creating a temp image, delete the old one and rename the temp image)
Any idea on how to achieve that?
Is it somehow possible to get a File object from an DocumentFile?
No.
With some small trick I can get the real path of the file
Not reliably. After all, the Storage Access Framework does not require there to be an actual file. Various DocumentProvider implementations work off of cloud services, where the data is not stored locally on the device until needed. Beyond that, whatever approach that you are using is dependent upon internal implementation that may vary by device, let alone Android OS version. And, to top it off, you still cannot necessarily access the data even if you derive a path, as you may not have filesystem access to that location (e.g., files held on internal storage by the DocumentProvider).
get exif data from images
Use the stream, along with EXIF code that can work with streams, such as this one or this one, found by searching the Internet for android exif stream.
ability to rotate images (this would be possible by creating a temp image, delete the old one and rename the temp image)
You don't have a choice to make a local copy, rotate the image, and then write the image back to the original DocumentFile using an OutputStream. Whether that "local copy" is only in RAM, or needs to be an actual file on disk, depends a bit on how you were planning on rotating it.

Camera pics not appearing in Gallery app

When I take pictures using android.hardware.camera and I save them to the following location /sdcard/dcim/camera/ they don't appear when I launch the gallery. Is there a process for getting them to show up in the gallery that I missed?
I can see my images using a file explorer and know they have been saved.
You need to run MediaScanner on the type of media that you have saved to make your changes(SDcard writes) transparent throughout the system.
MediaScanner is bundled with devTools package so you can either run it manually or you can also do it via Java code(right after the write to SDcard op). Google "MediaScanner" you will find plenty of examples.
Hope that helps.

Categories

Resources