I tried saving video to gallery like i found on example:
private fun saveVideoToInternalStorage3(filePath: String) {
val newfile: File
try {
val currentFile = File(filePath)
val fileName = currentFile.name
val cw = ContextWrapper(applicationContext)
val directory = cw.getDir("videoDir", Context.MODE_PRIVATE)
newfile = File(directory.absolutePath, fileName)
if(currentFile.exists()) {
val `in`: InputStream = FileInputStream(currentFile)
val out: OutputStream = FileOutputStream(newfile)
// Copy the bits from instream to outstream
val buf = ByteArray(1024)
var len: Int
while(`in`.read(buf).also {len = it} > 0) {
out.write(buf, 0, len)
}
scanner(filePath)
`in`.close()
out.close()
Log.d("", "Video file saved successfully.")
Toast.makeText(this, "Push Video Saved TO Gallery", Toast.LENGTH_SHORT).show()
} else {
Log.d("", "Video saving failed. Source file missing.")
}
} catch(e: java.lang.Exception) {
Log.d("", "EXS " + e.message)
e.printStackTrace()
}
And it works fine it shows message "Video file saved successfully." But there is no video in my gallery.
After searching for problem i found post that says you need a scanner and i tried:
private fun scanner(path: String) {
MediaScannerConnection.scanFile(this, arrayOf(path), null, object: OnScanCompletedListener {
override fun onScanCompleted(path: String, uri: Uri?) {
Log.i("", "Finished scanning $path")
}
})
But still no luck. Does any1 know what is going on? Saving images in gallery works fine btw.
Related
In an Android app the user can record his voice. The sound recording is saved in a file defined by:
audioTempFile = File(getFilesDir(), "Audio_Temp_File")
Then I want to give the user the choice of the final folder and file name for the file to be saved.
So the audioTempFile above can be used for a possible next recording without destroying the current one.
For example let us assume I want the file to be saved in this file called finalFile :
val rootDir = getFilesDir()
val storeDir = File(rootDir, "MyStorageDirectory")
val finalFile = File(storeDir, "MyFinalFileName")
How can I move or possibly copy audioTempFile to finalFile?
I did not find any clear answer by searching the net.
I don't know about saving to a specific location, but this is the way I'm saving the recordings in my app.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q){
try{
val values = ContentValues()
values.put(MediaStore.MediaColumns.DISPLAY_NAME, allFiles[position].name)
values.put(MediaStore.MediaColumns.MIME_TYPE, "audio/mp3")
values.put(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_MUSIC)
val savedAudio = context.contentResolver.insert(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, values)
val outputStream = savedAudio?.let {
context.contentResolver.openOutputStream(it)
}
val fis = FileInputStream(allFiles[position])
var length : Int
val buffer = ByteArray(8192)
while (fis.read(buffer).also { length = it } > 0) {
outputStream?.write(buffer, 0,length)
}
Toast.makeText(context, "Audio Saved to Music Folder", Toast.LENGTH_SHORT).show()
}catch (e : IOException){
Toast.makeText(
context,
"There was an error saving the file",
Toast.LENGTH_SHORT
).show()
e.printStackTrace()
}
}else{
try {
val audioDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MUSIC)
val audio = File(audioDir, allFiles[position].name)
val fis = FileInputStream(allFiles[position])
val fos = FileOutputStream(audio)
var length : Int
val buffer = ByteArray(8192)
while (fis.read(buffer).also { length = it } > 0){
fos.write(buffer,0,length)
}
Toast.makeText(context, "Audio Saved to Music Folder", Toast.LENGTH_SHORT).show()
}catch (e : IOException){
Toast.makeText(
context,
"There was an error saving the file",
Toast.LENGTH_SHORT
).show()
e.printStackTrace()
}
}
You would need MANAGE_EXTERNAL_STORAGE permission if u want to save files other than public directories. It's recommended to use MediaStore API to save your files.
Do correct me if I'm wrong as I'm still learning.
Hope this helps u :)
I have a page in my application where the user select an image from the gallery and save it as part of needed details. The image will be sent to a server through API request using Ktor. I have tried to convert the image bitmap to file but I get "operation not permitted" exception, and tired to look for a solution but nothing worked. One of the solutions recommended to add use permission for storage in the Manifest:
It didn't work as well.
The code is too long but here the block where I need to convert and save the file:
fun bitmapToFile(bitmap: Bitmap, fileNameToSave: String): File? { // File name like "image.png"
//create a file to write bitmap data
var file: File? = null
return try {
file = File(Environment.DIRECTORY_PICTURES + File.separator + fileNameToSave)
file.createNewFile()
//Convert bitmap to byte array
val bos = ByteArrayOutputStream()
bitmap.compress(Bitmap.CompressFormat.PNG, 0, bos) // YOU can also save it in JPEG
val bitmapData = bos.toByteArray()
//write the bytes in file
val fos = FileOutputStream(file)
fos.write(bitmapData)
fos.flush()
fos.close()
file
} catch (e: Exception) {
Toast.makeText( context, e.message, Toast.LENGTH_LONG ).show()
e.printStackTrace()
file // it will return null
}
}
fun handleChangeImage() {
try{
imageUri?.let {
if (Build.VERSION.SDK_INT < 28) {
bitmap = MediaStore.Images.Media.getBitmap(context.contentResolver, it)
} else {
val source = ImageDecoder.createSource(context.contentResolver, it)
bitmap = ImageDecoder.decodeBitmap(source)
}
}
//fixme: file conversion throw operation denied error
val fileName = imageUri?.lastPathSegment.toString().replace(":", ".")
val fileInput = if (bitmap != null)
bitmapToFile(bitmap!!, fileName)
else null
if(fileInput == null)
throw Exception("Error")
assetImageInput.value = fileInput
} catch (e: FileNotFoundException) {
Toast.makeText( context, e.message, Toast.LENGTH_LONG ).show()
} catch (e: Exception) {
Toast.makeText( context, e.message, Toast.LENGTH_LONG ).show()
}
}
After converting the image it should be saved as "assetImageInput.value" and be sent through the API as a parameter.
I implemented share image to other apps using intent, I followed the recommended approach by saving the image first then getting its LocalBitmapUri. but when i run the app and share image i get the Toast message [The file format is not supported]. and i cant seem to figure out what I did wrong.. thanks.
fun shareItem(url: String?,context: Context,scope: CoroutineScope) {
scope.launch {
withContext(Dispatchers.IO){
val i = Intent(Intent.ACTION_SEND)
i.type = "image/*"
i.putExtra(Intent.EXTRA_STREAM,
getBitmap("d",context,"https://cdn2.thecatapi.com/images/3o8.jpg")?.let {
getLocalBitmapUri(
it,
context
)
})
startActivity(context,Intent.createChooser( i, "Share Image"),null)
}
}
}
fun getLocalBitmapUri(bmp: Bitmap,context: Context): Uri? {
val builder = VmPolicy.Builder()
StrictMode.setVmPolicy(builder.build())
var bmpUri: Uri? = null
try {
val file = File(
context.getExternalFilesDir(Environment.DIRECTORY_PICTURES),
"share_image_jj" + System.currentTimeMillis() + ".png"
)
val out = FileOutputStream(file)
bmp.compress(Bitmap.CompressFormat.PNG, 90, out)
out.close()
bmpUri = Uri.fromFile(file)
} catch (e: IOException) {
e.printStackTrace()
}
return bmpUri
}
private suspend fun getBitmap(tag: String, context: Context, imageUrl: String): Bitmap? {
var bitmap: Bitmap? = null
val imageRequest = ImageRequest.Builder(context)
.data(imageUrl)
.target(
...//,
onSuccess = { result ->
Log.e(tag, "Coil loader success.")
bitmap = result.toBitmap()
}
)
.build()
context.imageLoader.execute(imageRequest)
return bitmap
}
I'm using below code for downloading the image and it download successfully but not showing in galary please help!!!
I have tried couple of examples none of them are working..
I have also tried the MediaScanner to scan the file and update the gallery
If anyone have links related this question please share
class DownloadFileFromURL : AsyncTask<Void, Void, Void>() {
override fun doInBackground(vararg params: Void): Void? {
var count: Int
try {
val url = URL(getUrl())
val conection: URLConnection = url.openConnection()
conection.connect()
// input stream to read file - with 8k buffer
val input: InputStream = BufferedInputStream(url.openStream(), 8192)
val output: OutputStream?
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
val resolver: ContentResolver = activity?.contentResolver!!
val contentValues = ContentValues()
val name = System.currentTimeMillis()
contentValues.put(MediaStore.MediaColumns.DISPLAY_NAME, "$name.jpg")
contentValues.put(MediaStore.MediaColumns.MIME_TYPE, "image/jpg")
contentValues.put(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_PICTURES)
val imageUri: Uri? = resolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues)
output = imageUri?.let { resolver.openOutputStream(it) }!!
} else {
val imgFile = createImageFile()
if (!imgFile.exists()) {
imgFile.createNewFile()
}
output = FileOutputStream(imgFile)
}
// Output stream to write file
val data = ByteArray(1024)
var total: Long = 0
while (input.read(data).also { count = it } != -1) {
total += count.toLong()
// writing data to file
output.write(data, 0, count)
}
// flushing output
output.flush()
// closing streams
output.close()
input.close()
} catch (e: Exception) {
Log.e("Error: ", e.message)
}
return null
}
override fun onPostExecute(result: Void?) {
downloadComplete()
}
#Throws(IOException::class)
private fun createImageFile(): File {
// Create an image file name
val timeStamp: String = SimpleDateFormat("yyyyMMdd_HHmmss", Locale.US).format(Date())
val storageDir: File = activity?.getExternalFilesDir(Environment.DIRECTORY_PICTURES)!!
return File(
storageDir, /* directory */
"JPEG_${timeStamp}"+ /* prefix */
".jpg" /* suffix */
).apply {
// Save a file: path for use with ACTION_VIEW intents
mCurrentPhotoPath = absolutePath
}
}
}
I'm using Storage Access Network to pick file and save in internal storage so that app can use if in future.
I'm getting URI without any issues. It's something like content://com.android.providers.media.documents/document/image%3A141274
Problem comes when I'm trying to save image into internal directory. Code passes without crashes, image with same size is saved into internal directory (I can see it in device Explorer: https://take.ms/3TwBS).
But image itself is broken and can't be opened.
Here's code I'm using (after getting URI)
val destinationFile = File("${context.filesDir.absolutePath}/$fileName")
try {
val writer = FileWriter(destinationFile)
writer.append(readTextFromUri(it))
writer.flush()
writer.close()
} catch (e: Exception) {
e.printStackTrace()
}
#Throws(IOException::class)
private fun readTextFromUri(uri: Uri): String {
val inputStream = activity!!.contentResolver.openInputStream(uri)
val reader = BufferedReader(InputStreamReader(inputStream))
val stringBuilder = StringBuilder()
var line: String? = null
while ({ line = reader.readLine(); line }() != null) {
stringBuilder.append(line)
}
inputStream?.close()
reader.close()
return stringBuilder.toString()
}
As #CommonsWare described I should have used proper dealing with files, not texts.
Proper way to do:
private fun inputStreamToFile(uri: Uri){
val inputStream = contentResolver.openInputStream(uri)
val output = FileOutputStream(File("${filesDir.absoluteFile}/magic.png"))
inputStream?.copyTo(output, 4 * 1024)
}
Or longer way (without extension functions)
fun inputStreamToFile(uri: Uri){
val inputStream = contentResolver.openInputStream(uri)
inputStream.use {
val directory = getDir("test", Context.MODE_PRIVATE)
val file = File(directory, "correct.txt")
val output = FileOutputStream(file)
output.use {
val buffer = ByteArray(4 * 1024) // or other buffer size
var read: Int = inputStream?.read(buffer) ?: -1
while (read != -1) {
output.write(buffer, 0, read)
read = inputStream?.read(buffer) ?: -1
}
output.flush()
}
}
}