Save camera image to SD card, retrieve and upload to Firestore Storage

Viewed 317

I am having difficulties saving an image inside my SD card. For some reason it saves to the internal Storage folder. I am also not able to retrieve the filepath where the image is stored. Or I am not correctly retrieving the file. Due to this, I cannot upload the image to Firestore Storage.

I have included all of my code for this, if anyone could help it would be appreciated. Currently using a Samsung Galaxy S10. This is to support offline capability for my Firestore App.

My saved image is only stored in

Internal Storage / Android / data / com.mly.Live /files / Pictures /

I would prefer to save this in the SD Card Folder...

Android Manifest

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

    <provider
        android:name="androidx.core.content.FileProvider"
        android:authorities="com.mly.Live.fileprovider"
        android:exported="false"
        android:grantUriPermissions="true">
        <meta-data
            android:name="android.support.FILE_PROVIDER_PATHS"
            android:resource="@xml/file_paths" />
    </provider>

file_paths.xml

<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-files-path
    name="my_images"
    path="Android/data/com.mly.Live/files/Pictures/"/>
<external-files-path
    name="my_debug_images"
    path="/storage/emulated/0/Android/data/com.mly.Live/files/Pictures/"/>
<external-files-path
    name="my_root_images"
    path="/"/>
</paths>

Activity (Kotlin)

private fun dispatchTakePictureIntent() {
    Intent(MediaStore.ACTION_IMAGE_CAPTURE).also {
        takePictureIntent -> takePictureIntent.resolveActivity(packageManager)?.also {

            val photoFile: File? = try {
                createImageFile()
            } catch (ex: IOException) {
                null
            }
            photoFile?.also {
                photoURI = FileProvider.getUriForFile(
                        this,
                        "com.mly.Live.fileprovider",
                        it
                )
                takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI)
                startActivityForResult(takePictureIntent, REQUEST_IMAGE_CAPTURE)
            }
        }
    }
}

@Throws(IOException::class)
private fun createImageFile(): File {
    val timeStamp: String = SimpleDateFormat("yyyyMMdd_HHmmss").format(Date())
   
    val storageDir: File = getExternalFilesDir(Environment.DIRECTORY_PICTURES)!!

    return File.createTempFile(
            "${timeStamp}_", /* prefix */
            ".jpg", /* suffix */
            storageDir /* directory */
    ).apply {
        currentPhotoPath = absolutePath
    }
}


override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
    super.onActivityResult(requestCode, resultCode, data)

    if (requestCode == REQUEST_IMAGE_CAPTURE && resultCode == RESULT_OK) {
        // Shows a small thumbnail image
        binding?.issueImage?.setImageURI(photoURI)
    }
}

When I save the Firestore document... I set 'imageRemoteSent' to false (meaning the image hasn't been saved to Firestore Storage) and the filepath of imageLocal...

photoURI.toString() gives me...

content://com.mly.Live.fileprovider/my_root_images/Pictures/54b4beb1-e30e-4f64-8bd9-9ed37695b474_7839622760179284029.jpg

currentPhotoPath gives me... (I have matched the imageName to illustrate the difference).

/storage/emulated/0/Android/data/com.mly.Live/files/Pictures/54b4beb1-e30e-4f64-8bd9-9ed37695b474_7839622760179284029.jpg

I can only see these photos in 'InternalStorage / Android / data / com.mly.Live /files / Pictures /'

AddIssueActivity (Kotlin)

private fun saveIssue1() {

    val db = FirebaseFirestore.getInstance()

    val data = hashMapOf(
            "type" to binding?.issueTypeSpinner?.selectedItem.toString(),
            "imageRemoteSent" to false,
            "imageLocal" to photoURI.toString(),
            "imageRemote" to "",
    )

    db.collection("Issues")
            .add(data)
            .addOnSuccessListener { documentReference ->

            }
            .addOnFailureListener { e ->

            }

}

HomeActivity (Java) Realtime Firestore Listener... listens for Issues were 'imageRemoteSent == false' and attempts to upload them to the Firestore Storage. This is called when the User Signs into the app in onCreate. I cannot correctly upload this to firestore. On successfully uploading to Firestore Storage, I change 'imageRemoteSent == true' and save the downloadURL in 'imageRemote'.

void checkForRemoteImages() {

    FirebaseHelper.getInstance().getIssueLocalImageCollection((issues -> {

        this.issue = issues;

        if (issue.size() > 0) {

            for (Issue object: issue) {

                String imageName = UUID.randomUUID().toString();

                FirebaseStorage storage = FirebaseStorage.getInstance();
                StorageReference storageRef = storage.getReference();

                StorageReference imageReference = storageRef.child("partInfoImagesFolder").child(imageName);

                Uri uriP = Uri.parse(object.getImageLocal());

                Uri uploadUri = Uri.fromFile(new File(uriP.toString()));

                imageReference.putFile(uploadUri)
                        .addOnCompleteListener(new OnCompleteListener<UploadTask.TaskSnapshot>() {
                            @Override
                            public void onComplete(@NonNull Task<UploadTask.TaskSnapshot> task) {

                                imageReference.getDownloadUrl().addOnSuccessListener(new OnSuccessListener<Uri>() {
                                    @Override
                                    public void onSuccess(Uri uri) {

                                        Uri url = uri;

                                        Toast.makeText(HomeActivity.this, "Upload Successful!", Toast.LENGTH_SHORT).show();

                                        DocumentReference washingtonRef = FirebaseFirestore.getInstance().collection("Issues").document(object.getDocumentId());

                                        washingtonRef
                                                .update("imageRemoteSent", true,
                                                        "imageRemote", url)
                                                .addOnSuccessListener(new OnSuccessListener<Void>() {
                                                    @Override
                                                    public void onSuccess(Void aVoid) {
                                                        Log.d("TAG WORK!!", "DocumentSnapshot successfully updated!");
                                                    }
                                                })
                                                .addOnFailureListener(new OnFailureListener() {
                                                    @Override
                                                    public void onFailure(@NonNull Exception e) {
                                                        Log.w("TAG FAIL", "Error updating document", e);
                                                    }
                                                });
                                    }
                                });
                            }

                        })
                        .addOnFailureListener(new OnFailureListener() {
                            @Override
                            public void onFailure(@NonNull Exception e) {
                                Log.w("TAG FAIL", "Error updating document", e);
                            }
                        });

                }

            } else {
                Toast.makeText(HomeActivity.this, "There are no Images to upload to firestore!", Toast.LENGTH_SHORT).show();
            }
    }));
}

FirebaseHelper Activity (Java)

public void getIssueLocalImageCollection(FireStoreDataRetrieved<List<Issue>> action){
    FirebaseFirestore.getInstance().collection(ISSUES_REF).whereEqualTo("imageRemoteSent",false)
            //.whereEqualTo("issueActive", true)
            .orderBy("issueDate", Query.Direction.DESCENDING)
            .addSnapshotListener((snapshot, err)->{
                List<DocumentSnapshot> list =  snapshot.getDocuments();

                List<Issue> infos = new ArrayList<>();
                if(snapshot.size() > 0){
                    infos = snapshot.toObjects(Issue.class);
                }

                for (int index = 0 ;index < snapshot.size();index++)
                {
                    infos.get(index).setDocumentId(list.get(index).getId());
                }

                action.onFetch(infos);
            });
}

If anyone could help out it would be much appreciated. Been looking at this all week now.

1 Answers

It will be better to create a Dialog to let the user select where they want the photo to be store at. Remember there are a ton of android devices and they might vary. If you still want to do it I found the same question here.

Android Studio: save image in SD Card

Related