0

We have an Android app where field workers take photographs which are stored on their phone and also uploaded via a web api. If the uploads fail they do have retry mechanisms but sometimes they need to resort to pulling the images off their phone. In order to bring the app up to Android 10 version without deprecation I was forced to write the images to an app internal directory. The problem is that when they upgrade their app they lose their photos from the app. (I do also copy the images to a backup directory but this is all looking a bit klutzy)

I would like to write the images to : /storage/emulated/0/DCIM/GoTrialImages

Instead they are going to : /storage/emulated/0/Android/data/au.come.aceware.ktr.ktr/files/DCIM/GoTrialImages/photoIntent (where photoIntent is the activity that this is occurring in)

Here is the code I have copied and tweaked from an online article:

String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
        String fileName = "JPEG_" + timeStamp + ".jpg";
        File mediaStorageDir = new File(getExternalFilesDir(Environment.DIRECTORY_DCIM + File.separator +"GoTrialPhotos"), TAG);
        // Create the storage directory if it does not exist
        if (!mediaStorageDir.exists() && !mediaStorageDir.mkdirs()){
            Log.d(TAG, "failed to create directory");
        }

        // Return the file target for the photo based on filename
        File file = new File(mediaStorageDir.getPath() + File.separator + fileName);
        Uri bmpUri = FileProvider.getUriForFile(this, BuildConfig.APPLICATION_ID + ".provider", file);

Here is my file provider entry in the manifest:

        android:name="androidx.core.content.FileProvider"
        android:authorities="${applicationId}.provider"
        android:exported="false"
        android:grantUriPermissions="true">
        <meta-data
            android:name="android.support.FILE_PROVIDER_PATHS"
            android:resource="@xml/provider_paths" />
    </provider>```

and here is @xml/provider_paths:


    ```<?xml version="1.0" encoding="utf-8"?>
    <paths xmlns:android="http://schemas.android.com/apk/res/android">
        <external-path name="external_files" path="."/>
    </paths>```


1) Is it possible to do what I am seeking to do ?
2) How do I do it without using deprecated code

Many thanks in advance
Tony

Following the suggestion to use media store I kept most of the code for creating the app internal file name 
(mainly because I wanted the randomised display name):

    private File createImageFileV2() throws IOException
    {
        // Create an image file name
        String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
        String imageFileName = "JPEG_" + timeStamp + "_";
        imageFileNameToUseAtWebServerEnd = strTrial + "_" + timeStamp + "_" + strUserId + ".jpg";
        File[] storageDir = getExternalMediaDirs();
        File image = File.createTempFile(
                imageFileName,  /* prefix */
                ".jpg",         /* suffix */
                storageDir[0]     /* directory */
        );

        return image;
    }

I then passed the file object in to the following code:

public Uri testgetPhotoFileUri2(File f)
    {
        Uri uri = null;
        String strDisplayName = f.getName();
        final ContentValues values = new ContentValues();
        values.put(MediaStore.MediaColumns.DISPLAY_NAME, strDisplayName);
        values.put(MediaStore.MediaColumns.MIME_TYPE, "image/jpeg");
        values.put(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_DCIM );

        final ContentResolver resolver = thisContext.getContentResolver();

        try
        {
            final Uri contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
            uri = resolver.insert(contentUri, values);

            if (uri == null)
                throw new IOException("Failed to create new MediaStore record.");
            return uri;
        }
        catch (IOException e)
        {

            if (uri != null) {
                // Don't leave an orphan entry in the MediaStore
                resolver.delete(uri, null, null);
            }

        }

        return uri;
    }

I then used the resulting uri as my camera uri:

takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, cameraUri);

However, when the OnActivityResult calls HandleBigCameraPhoto and attempts to extract the bitmap using the CameraUri:

    private void handleBigCameraPhoto() {
        Bitmap bitmap = null;
        if (cameraUri != null)
        {

            if (Build.VERSION.SDK_INT >= 29) {
                ImageDecoder.Source source = ImageDecoder.createSource(getApplicationContext().getContentResolver(), cameraUri);
                try {
                    bitmap = ImageDecoder.decodeBitmap(source);
                } catch (IOException e) {
                    e.printStackTrace();
                }

It error traps to "no such file or directory"

Does this mean that I need to most of my work (image resizing, rotation, etc) using my app private file only and then as a last step insert the bitmap in to media store (and then delete the app private file so the user does not see the file name twice under gallery, recents)?
Tony
  • 33
  • 4
  • Why you dont want to use deprecated code? – Khaby Lame Oct 22 '21 at 10:48
  • Does this answer your question? [Android prevent saving photo on DCIM / public folder](https://stackoverflow.com/questions/22387877/android-prevent-saving-photo-on-dcim-public-folder) – Khaby Lame Oct 22 '21 at 10:49
  • "I would like to write the images to : /storage/emulated/0/DCIM/GoTrialImages" -- use `MediaStore` on Android 10 and higher. See [this blog post](https://commonsware.com/blog/2019/12/21/scoped-storage-stories-storing-mediastore.html) for more. – CommonsWare Oct 22 '21 at 11:06
  • Many thanks for everyone's suggestions - I can see I have some more learning to do. – Tony Oct 24 '21 at 00:53

1 Answers1

0

You will not make use of a deprecated function:

File file = new File(getExternalFilesDir(null)
.getParentFile()
.getParentFile()
.getParentFile()
.getParentFile(), "DCIM");

;-).

blackapps
  • 8,011
  • 2
  • 11
  • 25