0

my App collecting some data from the user including an optional picture. To getting a High-Res picture i'm using following code:

https://medium.com/codex/how-to-use-the-android-activity-result-api-for-selecting-and-taking-images-5dbcc3e6324b

Getting the picture works as expected. If the user click on a save button, all data shall be written to an CSV-File on the SD-Card, and if latestTmpUri not null the user made a picture as well, and should be saved to the SD-Card, also.

I tried some snippets to move a file on Android, but everytime i'll get an error "File not exists". Maybe it has to do with path in provider_paths.xml, but i'm not sure.

By the way, i'm newbee on programming in Kotlin for Android.

EDIT:

If you take a look in the code from the URL above, there is an deleteOnExit()

private fun getTmpFileUri(): Uri {
    val tmpFile = File.createTempFile("tmp_image_file", ".png", cacheDir).apply {
        createNewFile()
        deleteOnExit()
    }

    return FileProvider.getUriForFile(applicationContext, "${BuildConfig.APPLICATION_ID}.provider", tmpFile)
}

And if you look in provider_paths.xml

<cache-path name="cached_files" path="." />
<files-path name="images" path="." />

This is the path of the picture

content://com.company.contacts.provider/cached_files/tmp_image_file580022157706292749.png

To give an other path in <cache-path name="cached_files" path="." /> is not the solution i guess, because the SD-CARD's got a unique identifier, like E534-12F6

  • Why would you wanna move your picture file? – blackapps Oct 14 '21 at 08:57
  • And for moving your file you dont need FileProvider which you seem to use now. – blackapps Oct 14 '21 at 08:58
  • @blackapps I want to move it, because it's temporarily. The picture should be accessible on the SD-Card. – Thomas Schulze Oct 14 '21 at 09:01
  • Files dont disappear from their own. Even if you use a function with that name. And temporary files can be created on a removable micro sd card too. And further it is unclear what you mean with SD-Card. You shoud come better to the -programming-point as all you say is not exact. – blackapps Oct 14 '21 at 09:05
  • @blackapps I have edit my post. – Thomas Schulze Oct 14 '21 at 09:21
  • `This is the path of the picture` No that is not a path but a content scheme uri. Where did you get that uri from? From FileProvider? Again you are not exact and i have to ask for clarifying. Also tell us path of your file. – blackapps Oct 14 '21 at 10:01
  • `like E534-12F6` That is indeed a removable micro sd card. And a path there cannot be used with FileProvider. Hence you could not use that path to take a picture. Moreover you could not even create a file there as micro sd cards are read only since Android 4 KitKat. – blackapps Oct 14 '21 at 10:03
  • @blackapps What are you talking about? I have Android 9 and i am storing my CSV in this path `/storage/E534-12F6/Android/data/...` and if i put the SD-Card in my PC i see exact this file/folder structure (except `/storage/E534-12F6/`) and my CSV files as i can see in Android Studio. In one comment you say i can create a temp file on SD-Card and in another you say its read-only? I guess i'm exact with my explainings. – Thomas Schulze Oct 14 '21 at 10:55
  • `/storage/E534-12F6/Android/data//files` is an app specific storage location on a removable micro sd card where your app can write to without needing any permissions. It's the firsttime you mention this path and you cannot have used it for a file with FileProvider to take a picture. Outside that app specific directory the card is read only. But.. what does it have to do with copying your picture file? – blackapps Oct 14 '21 at 11:06
  • There are two folders under `/...//files`. `Documents` where my CSV goes, and `Pictures` where i actually store my picture getting from the ImageView. But getting the picture from the ImageView it has a poor quality, thats why i want to store the original picture from the temp path there. I hope i was clear enough now. – Thomas Schulze Oct 14 '21 at 11:17
  • We stil dont know full path of your -temp-picture file. And we also do not know full path to where you wanna copy that file to. So you could say that clearness is lacking. – blackapps Oct 14 '21 at 11:28

2 Answers2

0

After a bit of research and thinking about FileInputStream and FileOutputStream and reading this post

https://stackoverflow.com/a/11327789/10155771

i got my solution. Depending on the Code in my first post to take a High-Res picture i modified it in this way:

private lateinit var tmpFile: File    
private fun getTmpFileUri(): Uri {
        tmpFile = File.createTempFile("tmp_image_file", ".png", cacheDir).apply {
            createNewFile()
            deleteOnExit()
        }

        return FileProvider.getUriForFile(applicationContext, "${BuildConfig.APPLICATION_ID}.provider", tmpFile)
    }

to make the variable tmpFile global.

In my function to save the CSV and the optional picture i did this:

var imageName = ""
                if(latestTmpUri != null) { // There was taken a picture if not null
                    val folder = getExternalFilesDirs(Environment.DIRECTORY_PICTURES)
                    val root = java.lang.String.valueOf(folder[1]).toString() // folder[1] is my SD-Card while folder[0] is internal storage
                    val filets: String = java.lang.String.valueOf(
                        TimeUnit.MILLISECONDS.toSeconds(
                            System.currentTimeMillis()
                        )
                    ) // Unix Timestamp
                    imageName = companyContact +"_$filets.png"
                    var instream: InputStream? = null
                    var outstream: OutputStream? = null
                    try {
                        val dir: File = File(root, imageName.replace(" ", "_"))
                        instream = FileInputStream(tmpFile.path)
                        outstream = FileOutputStream(dir.path)
                        val buffer = ByteArray(1024)
                        var read: Int
                        while (instream!!.read(buffer).also { read = it } != -1) {
                            outstream!!.write(buffer, 0, read)
                        }
                        instream.close()
                        instream = null

                        outstream!!.flush()
                        outstream.close()
                        outstream = null
                    } catch (fnfe1: FileNotFoundException) {
                        fnfe1.message?.let { it1 -> Log.e("FileNotFoundException", it1) }
                    } catch (e: java.lang.Exception) {
                        Log.e("Exception", e.message!!)
                    }
                }

Now i have my picture as png on my SD-Card.

0

Here is a simple solution for Kotlin 1.7.X

// move Uri file from cache to app's external files 
// - from: data/data/com.example.myapp/cache/videos/file.mp4
// - to: sdcard/Android/data/com.example.myapp/files/Movies
// Note: not selectable by the user.
fun moveUriFileToAppMovies(fromUri: Uri, context: Context) {
    val inputStream = context.contentResolver.openInputStream(fromUri)!!
    val file = File(context.getExternalFilesDir(Environment.DIRECTORY_MOVIES),
        fromUri.lastPathSegment ?:  "video.mp4")
    val outputStream = FileOutputStream(file)

    inputStream.copyTo(outputStream)
    inputStream.close()
    outputStream.close()
}
RealityExpander
  • 133
  • 1
  • 8