Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to save an image in a subdirectory on android Q whilst remaining backwards compatible

Tags:

I'm creating a simple image editor app and therefore need to load and save image files. I'd like the saved files to appear in the gallery in a separate album. From Android API 28 to 29, there have been drastic changes to what extent an app is able to access storage. I'm able to do what I want in Android Q (API 29) but that way is not backwards compatible.

When I want to achieve the same result in lower API versions, I have so far only found way's, which require the use of deprecated code (as of API 29).

These include:

  • the use of the MediaStore.Images.Media.DATA column
  • getting the file path to the external storage via Environment.getExternalStoragePublicDirectory(...)
  • inserting the image directly via MediaStore.Images.Media.insertImage(...)

My question is: is it possible to implement it in such a way, so it's backwards compatible, but doesn't require deprecated code? If not, is it okay to use deprecated code in this situation or will these methods soon be deleted from the sdk? In any case it feels very bad to use deprecated methods so I'd rather not :)

This is the way I found which works with API 29:

ContentValues values = new ContentValues();
String filename = System.currentTimeMillis() + ".jpg";

values.put(MediaStore.Images.Media.TITLE, filename);
values.put(MediaStore.Images.Media.DISPLAY_NAME, filename);
values.put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg");
values.put(MediaStore.Images.Media.DATE_ADDED, System.currentTimeMillis() / 1000);
values.put(MediaStore.Images.Media.DATE_TAKEN, System.currentTimeMillis());
values.put(MediaStore.Images.Media.RELATIVE_PATH, "PATH/TO/ALBUM");

getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,values);

I then use the URI returned by the insert method to save the bitmap. The Problem is that the field RELATIVE_PATH was introduced in API 29 so when I run the code on a lower version, the image is put into the "Pictures" folder and not the "PATH/TO/ALBUM" folder.

like image 626
multimodcrafter Avatar asked Jul 14 '19 20:07

multimodcrafter


1 Answers

is it okay to use deprecated code in this situation or will these methods soon be deleted from the sdk?

The DATA option will not work on Android Q, as that data is not included in query() results, even if you ask for it you cannot use the paths returned by it, even if they get returned.

The Environment.getExternalStoragePublicDirectory(...) option will not work by default on Android Q, though you can add a manifest entry to re-enable it. However, that manifest entry may be removed in Android R, so unless you are short on time, I would not go this route.

AFAIK, MediaStore.Images.Media.insertImage(...) still works, even though it is deprecated.

is it possible to implement it in such a way, so it's backwards compatible, but doesn't require deprecated code?

My guess is that you will need to use two different storage strategies, one for API Level 29+ and one for older devices. I took that approach in this sample app, though there I am working with video content, not images, so insertImage() was not an option.

like image 182
CommonsWare Avatar answered Sep 21 '22 15:09

CommonsWare