@@ -4,9 +4,8 @@ import android.content.Context
44import android.graphics.Bitmap
55import android.graphics.BitmapFactory
66import android.media.ThumbnailUtils
7- import android.os.Build
8- import android.util.Size
97import com.tomclaw.cache.DiskLruCache
8+ import okhttp3.internal.closeQuietly
109import org.cryptomator.cryptolib.api.Cryptor
1110import org.cryptomator.cryptolib.common.DecryptingReadableByteChannel
1211import org.cryptomator.cryptolib.common.EncryptingWritableByteChannel
@@ -50,6 +49,9 @@ import java.util.Queue
5049import java.util.UUID
5150import java.util.function.Supplier
5251import timber.log.Timber
52+ import java.io.PipedInputStream
53+ import java.io.PipedOutputStream
54+ import kotlin.concurrent.thread
5355
5456
5557abstract class CryptoImplDecorator (
@@ -361,12 +363,30 @@ abstract class CryptoImplDecorator(
361363 val diskCache = cryptoFile.cloudFile.cloud?.type()?.let { getLruCacheFor(it) }
362364 val cacheKey = generateCacheKey(ciphertextFile)
363365 val genThumbnail = isGenerateThumbnailsEnabled(diskCache, cryptoFile.name)
364- val decryptedTempFile : File
366+ var thumbnailBitmap : Bitmap ? = null
367+
368+ val thumbnailWriter = PipedOutputStream ()
369+ val thumbnailReader = PipedInputStream (thumbnailWriter)
370+
365371 try {
372+ // cloudContentRepository.read(file, encryptedTmpFile, encryptedData, ...)
373+ // file appena letto dalla rete, portato in cache ancora cifrato!
366374 val encryptedTmpFile = readToTmpFile(cryptoFile, ciphertextFile, progressAware)
367- decryptedTempFile = File .createTempFile(encryptedTmpFile.nameWithoutExtension, " .tmp" , internalCache)
368375
369- val decryptedTempFileOutputStream = decryptedTempFile.outputStream()
376+ // TODO: reusable thread?
377+ // A thread pool is a managed collection of threads that runs tasks in parallel from a queue.
378+ // https://developer.android.com/develop/background-work/background-tasks/asynchronous/java-threads
379+ val t = thread(start = false , name = " S.AN-DRO" ) { // Simply A New Data Readable Output
380+ try {
381+ val bitmap = BitmapFactory .decodeStream(thumbnailReader) // wait for the full image
382+ thumbnailBitmap = ThumbnailUtils .extractThumbnail(bitmap, 100 , 100 )
383+ thumbnailReader.closeQuietly()
384+ } catch (e : Exception ) {
385+ Timber .e(" Bitmap generation crashed" )
386+ }
387+ }
388+
389+ t.start()
370390 progressAware.onProgress(Progress .started(DownloadState .decryption(cryptoFile)))
371391 try {
372392 Channels .newChannel(FileInputStream (encryptedTmpFile)).use { readableByteChannel ->
@@ -378,34 +398,36 @@ abstract class CryptoImplDecorator(
378398 while (decryptingReadableByteChannel.read(buff).also { read = it } > 0 ) {
379399 buff.flip()
380400 data.write(buff.array(), 0 , buff.remaining())
381- decryptedTempFileOutputStream .write(buff.array(), 0 , buff.remaining())
401+ thumbnailWriter .write(buff.array(), 0 , buff.remaining())
382402
383403 decrypted + = read.toLong()
404+
384405 progressAware
385- .onProgress(
386- Progress .progress(DownloadState .decryption(cryptoFile)) //
387- .between(0 ) //
388- .and (cleartextSize) //
389- .withValue(decrypted)
390- )
406+ .onProgress(
407+ Progress .progress(DownloadState .decryption(cryptoFile)) //
408+ .between(0 ) //
409+ .and (cleartextSize) //
410+ .withValue(decrypted)
411+ )
391412 }
392413 }
414+ thumbnailWriter.flush()
393415 }
394416 } finally {
395- decryptedTempFileOutputStream.flush()
396- decryptedTempFileOutputStream.close()
397417 encryptedTmpFile.delete()
418+ thumbnailWriter.closeQuietly()
398419 progressAware.onProgress(Progress .completed(DownloadState .decryption(cryptoFile)))
399420 }
421+ t.join() // wait the thread
422+ thumbnailReader.closeQuietly()
400423 } catch (e: IOException ) {
401424 throw FatalBackendException (e)
402425 }
403426
404427 // store it in cloud-related LRU cache
405- if (genThumbnail) {
406- generateAndStoreThumbnail(diskCache, cacheKey, decryptedTempFile )
428+ if (genThumbnail && thumbnailBitmap != null ) {
429+ generateAndStoreThumbnail(diskCache, cacheKey, thumbnailBitmap !! )
407430 }
408- decryptedTempFile.delete()
409431 }
410432
411433 protected fun generateCacheKey (cloudFile : CloudFile ) : String {
@@ -428,17 +450,17 @@ abstract class CryptoImplDecorator(
428450 isImageMediaType(fileName)
429451 }
430452
431- private fun generateAndStoreThumbnail (cache : DiskLruCache ? , cacheKey : String , thumbnailTmp : File ) {
432- // generate the Bitmap (in memory)
433- val bitmap : Bitmap = if (Build .VERSION .SDK_INT >= Build .VERSION_CODES .Q ) {
434- ThumbnailUtils .createImageThumbnail(thumbnailTmp, Size (100 , 100 ), null )
435- } else {
436- ThumbnailUtils .extractThumbnail(BitmapFactory .decodeFile(thumbnailTmp.path), 100 , 100 )
437- }
453+ private fun generateAndStoreThumbnail (cache : DiskLruCache ? , cacheKey : String , thumbnailBitmap : Bitmap ) {
454+ // // generate the Bitmap (in memory)
455+ // val bitmap : Bitmap = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
456+ // ThumbnailUtils.createImageThumbnail(thumbnailTmp, Size(100, 100), null)
457+ // } else {
458+ // ThumbnailUtils.extractThumbnail(BitmapFactory.decodeFile(thumbnailTmp.path), 100, 100)
459+ // }
438460
439461 // write the thumbnail in a file (on disk)
440462 val thumbnailFile : File = File .createTempFile(UUID .randomUUID().toString(), " .thumbnail" , internalCache)
441- bitmap .compress(Bitmap .CompressFormat .JPEG , 100 , thumbnailFile.outputStream())
463+ thumbnailBitmap .compress(Bitmap .CompressFormat .JPEG , 100 , thumbnailFile.outputStream())
442464
443465 try {
444466 cache?.let {
0 commit comments